Be more consistant with paths in #includes. Eventually, eliminate a bunch of -I...
[mesa.git] / src / mesa / shader / slang / slang_typeinfo.c
index 8bedb40435ab0e54d41439a2dc272f9afab02ee5..8a1c3abf4807df21510511cf62f0af37fa05e808 100644 (file)
  * \author Michal Krol
  */
 
-#include "imports.h"
+#include "main/imports.h"
+#include "shader/prog_instruction.h"
 #include "slang_typeinfo.h"
 #include "slang_compile.h"
-#include "slang_error.h"
-#include "prog_instruction.h"
-
-
+#include "slang_log.h"
+#include "slang_mem.h"
 
 
 /**
@@ -151,10 +150,26 @@ _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
+_slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left,
+                         const slang_swizzle * right)
+{
+   GLuint i;
+
+   dst->num_components = right->num_components;
+   for (i = 0; i < right->num_components; i++)
+      dst->swizzle[i] = left->swizzle[right->swizzle[i]];
+}
+
+
 GLvoid
 slang_type_specifier_ctr(slang_type_specifier * self)
 {
-   self->type = slang_spec_void;
+   self->type = SLANG_SPEC_VOID;
    self->_struct = NULL;
    self->_array = NULL;
 }
@@ -164,11 +179,11 @@ slang_type_specifier_dtr(slang_type_specifier * self)
 {
    if (self->_struct != NULL) {
       slang_struct_destruct(self->_struct);
-      slang_alloc_free(self->_struct);
+      _slang_free(self->_struct);
    }
    if (self->_array != NULL) {
       slang_type_specifier_dtr(self->_array);
-      slang_alloc_free(self->_array);
+      _slang_free(self->_array);
    }
 }
 
@@ -180,14 +195,14 @@ slang_type_specifier_copy(slang_type_specifier * x,
 
    slang_type_specifier_ctr(&z);
    z.type = y->type;
-   if (z.type == slang_spec_struct) {
-      z._struct = (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
+   if (z.type == SLANG_SPEC_STRUCT) {
+      z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct));
       if (z._struct == NULL) {
          slang_type_specifier_dtr(&z);
          return GL_FALSE;
       }
       if (!slang_struct_construct(z._struct)) {
-         slang_alloc_free(z._struct);
+         _slang_free(z._struct);
          slang_type_specifier_dtr(&z);
          return GL_FALSE;
       }
@@ -196,10 +211,9 @@ slang_type_specifier_copy(slang_type_specifier * x,
          return GL_FALSE;
       }
    }
-   else if (z.type == slang_spec_array) {
-      z._array =
-         (slang_type_specifier *)
-         slang_alloc_malloc(sizeof(slang_type_specifier));
+   else if (z.type == SLANG_SPEC_ARRAY) {
+      z._array = (slang_type_specifier *)
+         _slang_alloc(sizeof(slang_type_specifier));
       if (z._array == NULL) {
          slang_type_specifier_dtr(&z);
          return GL_FALSE;
@@ -215,17 +229,44 @@ slang_type_specifier_copy(slang_type_specifier * x,
    return GL_TRUE;
 }
 
+
+/**
+ * Test if two types are equal.
+ */
 GLboolean
 slang_type_specifier_equal(const slang_type_specifier * x,
                            const slang_type_specifier * y)
 {
    if (x->type != y->type)
-      return 0;
-   if (x->type == slang_spec_struct)
+      return GL_FALSE;
+   if (x->type == SLANG_SPEC_STRUCT)
       return slang_struct_equal(x->_struct, y->_struct);
-   if (x->type == slang_spec_array)
+   if (x->type == SLANG_SPEC_ARRAY)
       return slang_type_specifier_equal(x->_array, y->_array);
-   return 1;
+   return GL_TRUE;
+}
+
+
+/**
+ * As above, but allow float/int casting.
+ */
+static GLboolean
+slang_type_specifier_compatible(const slang_type_specifier * x,
+                                const slang_type_specifier * y)
+{
+   /* special case: float == int */
+   if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) {
+      return GL_TRUE;
+   }
+   /* XXX may need to add bool/int compatibility, etc */
+
+   if (x->type != y->type)
+      return GL_FALSE;
+   if (x->type == SLANG_SPEC_STRUCT)
+      return slang_struct_equal(x->_struct, y->_struct);
+   if (x->type == SLANG_SPEC_ARRAY)
+      return slang_type_specifier_compatible(x->_array, y->_array);
+   return GL_TRUE;
 }
 
 
@@ -244,9 +285,36 @@ slang_typeinfo_destruct(slang_typeinfo * ti)
 }
 
 
+
 /**
  * Determine the return type of a function.
- * \param name  name of the function
+ * \param a_name  the function name
+ * \param param  function parameters (overloading)
+ * \param num_params  number of parameters to function
+ * \param space  namespace to search
+ * \param spec  returns the type
+ * \param funFound  returns pointer to the function, or NULL if not found.
+ * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
+ */
+static GLboolean
+_slang_typeof_function(slang_atom a_name,
+                       slang_operation * params, GLuint num_params,
+                       const slang_name_space * space,
+                       slang_type_specifier * spec,
+                       slang_function **funFound,
+                       slang_atom_pool *atoms, slang_info_log *log)
+{
+   *funFound = _slang_locate_function(space->funcs, a_name, params,
+                                      num_params, space, atoms, log);
+   if (!*funFound)
+      return GL_TRUE;  /* yes, not false */
+   return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier);
+}
+
+
+/**
+ * Determine the type of a math function.
+ * \param name  name of the operator, one of +,-,*,/ or unary -
  * \param params  array of function parameters
  * \param num_params  number of parameters
  * \param space  namespace to use
@@ -255,28 +323,44 @@ slang_typeinfo_destruct(slang_typeinfo * ti)
  * \return GL_TRUE for success, GL_FALSE if failure
  */
 static GLboolean
-typeof_existing_function(const char *name, const slang_operation * params,
-                         GLuint num_params,
-                         const slang_name_space * space,
-                         slang_type_specifier * spec,
-                         slang_atom_pool * atoms)
+typeof_math_call(const char *name, slang_operation *call,
+                 const slang_name_space * space,
+                 slang_type_specifier * spec,
+                 slang_atom_pool * atoms,
+                 slang_info_log *log)
 {
-   slang_atom atom;
-   GLboolean exists;
+   if (call->fun) {
+      /* we've previously resolved this function call */
+      slang_type_specifier_copy(spec, &call->fun->header.type.specifier);
+      return GL_TRUE;
+   }
+   else {
+      slang_atom atom;
+      slang_function *fun;
+
+      /* number of params: */
+      assert(call->num_children == 1 || call->num_children == 2);
+
+      atom = slang_atom_pool_atom(atoms, name);
+      if (!_slang_typeof_function(atom, call->children, call->num_children,
+                                  space, spec, &fun, atoms, log))
+         return GL_FALSE;
 
-   atom = slang_atom_pool_atom(atoms, name);
-   if (!_slang_typeof_function(atom, params, num_params, space, spec,
-                               &exists, atoms))
+      if (fun) {
+         /* Save pointer to save time in future */
+         call->fun = fun;
+         return GL_TRUE;
+      }
       return GL_FALSE;
-   return exists;
+   }
 }
 
 GLboolean
 _slang_typeof_operation(const slang_assemble_ctx * A,
-                        const slang_operation * op,
+                        slang_operation * op,
                         slang_typeinfo * ti)
 {
-   return _slang_typeof_operation_(op, &A->space, ti, A->atoms);
+   return _slang_typeof_operation_(op, &A->space, ti, A->atoms, A->log);
 }
 
 
@@ -289,217 +373,278 @@ _slang_typeof_operation(const slang_assemble_ctx * A,
  * \return GL_TRUE for success, GL_FALSE if failure
  */
 GLboolean
-_slang_typeof_operation_(const slang_operation * op,
+_slang_typeof_operation_(slang_operation * op,
                          const slang_name_space * space,
                          slang_typeinfo * ti,
-                         slang_atom_pool * atoms)
+                         slang_atom_pool * atoms,
+                         slang_info_log *log)
 {
    ti->can_be_referenced = GL_FALSE;
    ti->is_swizzled = GL_FALSE;
 
    switch (op->type) {
-   case slang_oper_block_no_new_scope:
-   case slang_oper_block_new_scope:
-   case slang_oper_variable_decl:
-   case slang_oper_asm:
-   case slang_oper_break:
-   case slang_oper_continue:
-   case slang_oper_discard:
-   case slang_oper_return:
-   case slang_oper_if:
-   case slang_oper_while:
-   case slang_oper_do:
-   case slang_oper_for:
-   case slang_oper_void:
-      ti->spec.type = slang_spec_void;
+   case SLANG_OPER_BLOCK_NO_NEW_SCOPE:
+   case SLANG_OPER_BLOCK_NEW_SCOPE:
+   case SLANG_OPER_VARIABLE_DECL:
+   case SLANG_OPER_ASM:
+   case SLANG_OPER_BREAK:
+   case SLANG_OPER_CONTINUE:
+   case SLANG_OPER_DISCARD:
+   case SLANG_OPER_RETURN:
+   case SLANG_OPER_IF:
+   case SLANG_OPER_WHILE:
+   case SLANG_OPER_DO:
+   case SLANG_OPER_FOR:
+   case SLANG_OPER_VOID:
+      ti->spec.type = SLANG_SPEC_VOID;
       break;
-   case slang_oper_expression:
-   case slang_oper_assign:
-   case slang_oper_addassign:
-   case slang_oper_subassign:
-   case slang_oper_mulassign:
-   case slang_oper_divassign:
-   case slang_oper_preincrement:
-   case slang_oper_predecrement:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms))
+   case SLANG_OPER_EXPRESSION:
+   case SLANG_OPER_ASSIGN:
+   case SLANG_OPER_ADDASSIGN:
+   case SLANG_OPER_SUBASSIGN:
+   case SLANG_OPER_MULASSIGN:
+   case SLANG_OPER_DIVASSIGN:
+   case SLANG_OPER_PREINCREMENT:
+   case SLANG_OPER_PREDECREMENT:
+      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
          return GL_FALSE;
       break;
-   case slang_oper_literal_bool:
-   case slang_oper_logicalor:
-   case slang_oper_logicalxor:
-   case slang_oper_logicaland:
-   case slang_oper_equal:
-   case slang_oper_notequal:
-   case slang_oper_less:
-   case slang_oper_greater:
-   case slang_oper_lessequal:
-   case slang_oper_greaterequal:
-   case slang_oper_not:
-      ti->spec.type = slang_spec_bool;
+   case SLANG_OPER_LITERAL_BOOL:
+      if (op->literal_size == 1)
+         ti->spec.type = SLANG_SPEC_BOOL;
+      else if (op->literal_size == 2)
+         ti->spec.type = SLANG_SPEC_BVEC2;
+      else if (op->literal_size == 3)
+         ti->spec.type = SLANG_SPEC_BVEC3;
+      else if (op->literal_size == 4)
+         ti->spec.type = SLANG_SPEC_BVEC4;
+      else {
+         _mesa_problem(NULL,
+               "Unexpected bool literal_size %d in _slang_typeof_operation()",
+               op->literal_size);
+         ti->spec.type = SLANG_SPEC_BOOL;
+      }
       break;
-   case slang_oper_literal_int:
-      ti->spec.type = slang_spec_int;
+   case SLANG_OPER_LOGICALOR:
+   case SLANG_OPER_LOGICALXOR:
+   case SLANG_OPER_LOGICALAND:
+   case SLANG_OPER_EQUAL:
+   case SLANG_OPER_NOTEQUAL:
+   case SLANG_OPER_LESS:
+   case SLANG_OPER_GREATER:
+   case SLANG_OPER_LESSEQUAL:
+   case SLANG_OPER_GREATEREQUAL:
+   case SLANG_OPER_NOT:
+      ti->spec.type = SLANG_SPEC_BOOL;
       break;
-   case slang_oper_literal_float:
-      ti->spec.type = slang_spec_float;
+   case SLANG_OPER_LITERAL_INT:
+      if (op->literal_size == 1)
+         ti->spec.type = SLANG_SPEC_INT;
+      else if (op->literal_size == 2)
+         ti->spec.type = SLANG_SPEC_IVEC2;
+      else if (op->literal_size == 3)
+         ti->spec.type = SLANG_SPEC_IVEC3;
+      else if (op->literal_size == 4)
+         ti->spec.type = SLANG_SPEC_IVEC4;
+      else {
+         _mesa_problem(NULL,
+               "Unexpected int literal_size %d in _slang_typeof_operation()",
+               op->literal_size);
+         ti->spec.type = SLANG_SPEC_INT;
+      }
+      break;
+   case SLANG_OPER_LITERAL_FLOAT:
+      if (op->literal_size == 1)
+         ti->spec.type = SLANG_SPEC_FLOAT;
+      else if (op->literal_size == 2)
+         ti->spec.type = SLANG_SPEC_VEC2;
+      else if (op->literal_size == 3)
+         ti->spec.type = SLANG_SPEC_VEC3;
+      else if (op->literal_size == 4)
+         ti->spec.type = SLANG_SPEC_VEC4;
+      else {
+         _mesa_problem(NULL,
+               "Unexpected float literal_size %d in _slang_typeof_operation()",
+               op->literal_size);
+         ti->spec.type = SLANG_SPEC_FLOAT;
+      }
       break;
-   case slang_oper_identifier:
+   case SLANG_OPER_IDENTIFIER:
       {
          slang_variable *var;
          var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
-         if (var == NULL)
-            RETURN_ERROR2("undefined variable", (char *) op->a_id, 0);
-         if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier))
-            RETURN_OUT_OF_MEMORY();
+         if (!var) {
+            slang_info_log_error(log, "undefined variable '%s'",
+                                 (char *) op->a_id);
+            return GL_FALSE;
+         }
+         if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) {
+            slang_info_log_memory(log);
+            return GL_FALSE;
+         }
          ti->can_be_referenced = GL_TRUE;
          ti->array_len = var->array_len;
       }
       break;
-   case slang_oper_sequence:
+   case SLANG_OPER_SEQUENCE:
       /* TODO: check [0] and [1] if they match */
-      if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms))
-         RETURN_NIL();
+      if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
+         return GL_FALSE;
+      }
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
       break;
-      /*case slang_oper_modassign: */
-      /*case slang_oper_lshassign: */
-      /*case slang_oper_rshassign: */
-      /*case slang_oper_orassign: */
-      /*case slang_oper_xorassign: */
-      /*case slang_oper_andassign: */
-   case slang_oper_select:
+      /*case SLANG_OPER_MODASSIGN: */
+      /*case SLANG_OPER_LSHASSIGN: */
+      /*case SLANG_OPER_RSHASSIGN: */
+      /*case SLANG_OPER_ORASSIGN: */
+      /*case SLANG_OPER_XORASSIGN: */
+      /*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))
-         RETURN_NIL();
+      if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
+         return GL_FALSE;
+      }
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
       break;
-      /*case slang_oper_bitor: */
-      /*case slang_oper_bitxor: */
-      /*case slang_oper_bitand: */
-      /*case slang_oper_lshift: */
-      /*case slang_oper_rshift: */
-   case slang_oper_add:
-      if (!typeof_existing_function("+", op->children, 2, space,
-                                    &ti->spec, atoms))
-         RETURN_NIL();
+      /*case SLANG_OPER_BITOR: */
+      /*case SLANG_OPER_BITXOR: */
+      /*case SLANG_OPER_BITAND: */
+      /*case SLANG_OPER_LSHIFT: */
+      /*case SLANG_OPER_RSHIFT: */
+   case SLANG_OPER_ADD:
+      assert(op->num_children == 2);
+      if (!typeof_math_call("+", op, space, &ti->spec, atoms, log))
+         return GL_FALSE;
       break;
-   case slang_oper_subtract:
-      if (!typeof_existing_function("-", op->children, 2, space,
-                                    &ti->spec, atoms))
-         RETURN_NIL();
+   case SLANG_OPER_SUBTRACT:
+      assert(op->num_children == 2);
+      if (!typeof_math_call("-", op, space, &ti->spec, atoms, log))
+         return GL_FALSE;
       break;
-   case slang_oper_multiply:
-      if (!typeof_existing_function("*", op->children, 2, space,
-                                    &ti->spec, atoms))
-         RETURN_NIL();
+   case SLANG_OPER_MULTIPLY:
+      assert(op->num_children == 2);
+      if (!typeof_math_call("*", op, space, &ti->spec, atoms, log))
+         return GL_FALSE;
       break;
-   case slang_oper_divide:
-      if (!typeof_existing_function("/", op->children, 2, space,
-                                    &ti->spec, atoms))
-         RETURN_NIL();
+   case SLANG_OPER_DIVIDE:
+      assert(op->num_children == 2);
+      if (!typeof_math_call("/", op, space, &ti->spec, atoms, log))
+         return GL_FALSE;
       break;
-      /*case slang_oper_modulus: */
-   case slang_oper_plus:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms))
-         RETURN_NIL();
+   /*case SLANG_OPER_MODULUS: */
+   case SLANG_OPER_PLUS:
+      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
+         return GL_FALSE;
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
       break;
-   case slang_oper_minus:
-      if (!typeof_existing_function("-", op->children, 1, space,
-                                    &ti->spec, atoms))
-         RETURN_NIL();
+   case SLANG_OPER_MINUS:
+      assert(op->num_children == 1);
+      if (!typeof_math_call("-", op, space, &ti->spec, atoms, log))
+         return GL_FALSE;
       break;
-      /*case slang_oper_complement: */
-   case slang_oper_subscript:
+      /*case SLANG_OPER_COMPLEMENT: */
+   case SLANG_OPER_SUBSCRIPT:
       {
          slang_typeinfo _ti;
 
          if (!slang_typeinfo_construct(&_ti))
-            RETURN_NIL();
-         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
+            return GL_FALSE;
+         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
             slang_typeinfo_destruct(&_ti);
-            RETURN_NIL();
+            return GL_FALSE;
          }
          ti->can_be_referenced = _ti.can_be_referenced;
-         if (_ti.spec.type == slang_spec_array) {
+         if (_ti.spec.type == SLANG_SPEC_ARRAY) {
             if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_NIL();
+               return GL_FALSE;
             }
          }
          else {
             if (!_slang_type_is_vector(_ti.spec.type)
                 && !_slang_type_is_matrix(_ti.spec.type)) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_ERROR("cannot index a non-array type", 0);
+               slang_info_log_error(log, "cannot index a non-array type");
+               return GL_FALSE;
             }
             ti->spec.type = _slang_type_base(_ti.spec.type);
          }
          slang_typeinfo_destruct(&_ti);
       }
       break;
-   case slang_oper_call:
-      {
-         GLboolean exists;
-
+   case SLANG_OPER_CALL:
+      if (op->fun) {
+         /* we've resolved this call before */
+         slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier);
+      }
+      else {
+         slang_function *fun;
          if (!_slang_typeof_function(op->a_id, op->children, op->num_children,
-                                     space, &ti->spec, &exists, atoms))
-            RETURN_NIL();
-         if (!exists) {
+                                     space, &ti->spec, &fun, atoms, log))
+            return GL_FALSE;
+         if (fun) {
+            /* save result for future use */
+            op->fun = fun;
+         }
+         else {
             slang_struct *s =
                slang_struct_scope_find(space->structs, op->a_id, GL_TRUE);
-            if (s != NULL) {
-               ti->spec.type = slang_spec_struct;
+            if (s) {
+               /* struct initializer */
+               ti->spec.type = SLANG_SPEC_STRUCT;
                ti->spec._struct =
-                  (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
+                  (slang_struct *) _slang_alloc(sizeof(slang_struct));
                if (ti->spec._struct == NULL)
-                  RETURN_NIL();
+                  return GL_FALSE;
                if (!slang_struct_construct(ti->spec._struct)) {
-                  slang_alloc_free(ti->spec._struct);
+                  _slang_free(ti->spec._struct);
                   ti->spec._struct = NULL;
-                  RETURN_NIL();
+                  return GL_FALSE;
                }
                if (!slang_struct_copy(ti->spec._struct, s))
-                  RETURN_NIL();
+                  return GL_FALSE;
             }
             else {
+               /* float, int, vec4, mat3, etc. constructor? */
                const char *name;
                slang_type_specifier_type type;
 
                name = slang_atom_pool_id(atoms, op->a_id);
                type = slang_type_specifier_type_from_string(name);
-               if (type == slang_spec_void)
-                  RETURN_ERROR2("function not found", name, 0);
+               if (type == SLANG_SPEC_VOID) {
+                  slang_info_log_error(log, "undefined function '%s'", name);
+                  return GL_FALSE;
+               }
                ti->spec.type = type;
             }
          }
       }
       break;
-   case slang_oper_field:
+   case SLANG_OPER_FIELD:
       {
          slang_typeinfo _ti;
 
          if (!slang_typeinfo_construct(&_ti))
-            RETURN_NIL();
-         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
+            return GL_FALSE;
+         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
             slang_typeinfo_destruct(&_ti);
-            RETURN_NIL();
+            return GL_FALSE;
          }
-         if (_ti.spec.type == slang_spec_struct) {
+         if (_ti.spec.type == SLANG_SPEC_STRUCT) {
             slang_variable *field;
 
             field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id,
                                            GL_FALSE);
             if (field == NULL) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_NIL();
+               return GL_FALSE;
             }
             if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_NIL();
+               return GL_FALSE;
             }
             ti->can_be_referenced = _ti.can_be_referenced;
          }
@@ -509,17 +654,17 @@ _slang_typeof_operation_(const slang_operation * op,
             slang_type_specifier_type base;
 
             /* determine the swizzle of the field expression */
-#if 000
             if (!_slang_type_is_vector(_ti.spec.type)) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_ERROR("Can't swizzle scalar expression", 0);
+               slang_info_log_error(log, "Can't swizzle scalar expression");
+               return GL_FALSE;
             }
-#endif
             rows = _slang_type_dim(_ti.spec.type);
             swizzle = slang_atom_pool_id(atoms, op->a_id);
             if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) {
                slang_typeinfo_destruct(&_ti);
-               RETURN_ERROR("Bad swizzle", 0);
+               slang_info_log_error(log, "bad swizzle '%s'", swizzle);
+               return GL_FALSE;
             }
             ti->is_swizzled = GL_TRUE;
             ti->can_be_referenced = _ti.can_be_referenced
@@ -538,14 +683,14 @@ _slang_typeof_operation_(const slang_operation * op,
                break;
             case 2:
                switch (base) {
-               case slang_spec_float:
-                  ti->spec.type = slang_spec_vec2;
+               case SLANG_SPEC_FLOAT:
+                  ti->spec.type = SLANG_SPEC_VEC2;
                   break;
-               case slang_spec_int:
-                  ti->spec.type = slang_spec_ivec2;
+               case SLANG_SPEC_INT:
+                  ti->spec.type = SLANG_SPEC_IVEC2;
                   break;
-               case slang_spec_bool:
-                  ti->spec.type = slang_spec_bvec2;
+               case SLANG_SPEC_BOOL:
+                  ti->spec.type = SLANG_SPEC_BVEC2;
                   break;
                default:
                   break;
@@ -553,14 +698,14 @@ _slang_typeof_operation_(const slang_operation * op,
                break;
             case 3:
                switch (base) {
-               case slang_spec_float:
-                  ti->spec.type = slang_spec_vec3;
+               case SLANG_SPEC_FLOAT:
+                  ti->spec.type = SLANG_SPEC_VEC3;
                   break;
-               case slang_spec_int:
-                  ti->spec.type = slang_spec_ivec3;
+               case SLANG_SPEC_INT:
+                  ti->spec.type = SLANG_SPEC_IVEC3;
                   break;
-               case slang_spec_bool:
-                  ti->spec.type = slang_spec_bvec3;
+               case SLANG_SPEC_BOOL:
+                  ti->spec.type = SLANG_SPEC_BVEC3;
                   break;
                default:
                   break;
@@ -568,14 +713,14 @@ _slang_typeof_operation_(const slang_operation * op,
                break;
             case 4:
                switch (base) {
-               case slang_spec_float:
-                  ti->spec.type = slang_spec_vec4;
+               case SLANG_SPEC_FLOAT:
+                  ti->spec.type = SLANG_SPEC_VEC4;
                   break;
-               case slang_spec_int:
-                  ti->spec.type = slang_spec_ivec4;
+               case SLANG_SPEC_INT:
+                  ti->spec.type = SLANG_SPEC_IVEC4;
                   break;
-               case slang_spec_bool:
-                  ti->spec.type = slang_spec_bvec4;
+               case SLANG_SPEC_BOOL:
+                  ti->spec.type = SLANG_SPEC_BVEC4;
                   break;
                default:
                   break;
@@ -588,27 +733,29 @@ _slang_typeof_operation_(const slang_operation * op,
          slang_typeinfo_destruct(&_ti);
       }
       break;
-   case slang_oper_postincrement:
-   case slang_oper_postdecrement:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms))
-         RETURN_NIL();
+   case SLANG_OPER_POSTINCREMENT:
+   case SLANG_OPER_POSTDECREMENT:
+      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
+         return GL_FALSE;
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
       break;
    default:
-      RETURN_NIL();
+      return GL_FALSE;
    }
 
    return GL_TRUE;
 }
 
 
-
+/**
+ * Lookup a function according to name and parameter count/types.
+ */
 slang_function *
 _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
-                       const slang_operation * args, GLuint num_args,
-                       const slang_name_space * space,
-                       slang_atom_pool * atoms)
+                       slang_operation * args, GLuint num_args,
+                       const slang_name_space * space, slang_atom_pool * atoms,
+                       slang_info_log *log)
 {
    GLuint i;
 
@@ -628,21 +775,23 @@ _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
 
          if (!slang_typeinfo_construct(&ti))
             return NULL;
-         if (!_slang_typeof_operation_(&args[j], space, &ti, atoms)) {
+         if (!_slang_typeof_operation_(&args[j], space, &ti, atoms, log)) {
             slang_typeinfo_destruct(&ti);
             return NULL;
          }
-         if (!slang_type_specifier_equal(&ti.spec,
-             &f->parameters->variables[j/* + haveRetValue*/]->type.specifier)) {
+         if (!slang_type_specifier_compatible(&ti.spec,
+             &f->parameters->variables[j]->type.specifier)) {
             slang_typeinfo_destruct(&ti);
             break;
          }
          slang_typeinfo_destruct(&ti);
 
-         /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
+         /* "out" and "inout" formal parameter requires the actual
+          * parameter to be l-value.
+          */
          if (!ti.can_be_referenced &&
-             (f->parameters->variables[j/* + haveRetValue*/]->type.qualifier == slang_qual_out ||
-              f->parameters->variables[j/* + haveRetValue*/]->type.qualifier == slang_qual_inout))
+             (f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT ||
+              f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT))
             break;
       }
       if (j == num_args)
@@ -650,38 +799,11 @@ _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
    }
    if (funcs->outer_scope != NULL)
       return _slang_locate_function(funcs->outer_scope, a_name, args,
-                                    num_args, space, atoms);
+                                    num_args, space, atoms, log);
    return NULL;
 }
 
 
-
-/**
- * Determine the return type of a function.
- * \param a_name  the function name
- * \param param  function parameters (overloading)
- * \param num_params  number of parameters to function
- * \param space  namespace to search
- * \param exists  returns GL_TRUE or GL_FALSE to indicate existance of function
- * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
- */
-GLboolean
-_slang_typeof_function(slang_atom a_name, const slang_operation * params,
-                       GLuint num_params,
-                       const slang_name_space * space,
-                       slang_type_specifier * spec, GLboolean * exists,
-                       slang_atom_pool * atoms)
-{
-   slang_function *fun = _slang_locate_function(space->funcs, a_name, params,
-                                                num_params, space, atoms);
-   *exists = fun != NULL;
-   if (!fun)
-      return GL_TRUE;  /* yes, not false */
-   return slang_type_specifier_copy(spec, &fun->header.type.specifier);
-}
-
-
-
 /**
  * Determine if a type is a matrix.
  * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
@@ -690,9 +812,15 @@ GLboolean
 _slang_type_is_matrix(slang_type_specifier_type ty)
 {
    switch (ty) {
-   case slang_spec_mat2:
-   case slang_spec_mat3:
-   case slang_spec_mat4:
+   case SLANG_SPEC_MAT2:
+   case SLANG_SPEC_MAT3:
+   case SLANG_SPEC_MAT4:
+   case SLANG_SPEC_MAT23:
+   case SLANG_SPEC_MAT32:
+   case SLANG_SPEC_MAT24:
+   case SLANG_SPEC_MAT42:
+   case SLANG_SPEC_MAT34:
+   case SLANG_SPEC_MAT43:
       return GL_TRUE;
    default:
       return GL_FALSE;
@@ -708,15 +836,15 @@ GLboolean
 _slang_type_is_vector(slang_type_specifier_type ty)
 {
    switch (ty) {
-   case slang_spec_vec2:
-   case slang_spec_vec3:
-   case slang_spec_vec4:
-   case slang_spec_ivec2:
-   case slang_spec_ivec3:
-   case slang_spec_ivec4:
-   case slang_spec_bvec2:
-   case slang_spec_bvec3:
-   case slang_spec_bvec4:
+   case SLANG_SPEC_VEC2:
+   case SLANG_SPEC_VEC3:
+   case SLANG_SPEC_VEC4:
+   case SLANG_SPEC_IVEC2:
+   case SLANG_SPEC_IVEC3:
+   case SLANG_SPEC_IVEC4:
+   case SLANG_SPEC_BVEC2:
+   case SLANG_SPEC_BVEC3:
+   case SLANG_SPEC_BVEC4:
       return GL_TRUE;
    default:
       return GL_FALSE;
@@ -725,66 +853,170 @@ _slang_type_is_vector(slang_type_specifier_type ty)
 
 
 /**
- * Given a vector type, return the type of the vector's elements
+ * Given a vector type, return the type of the vector's elements.
+ * For a matrix, return the type of the columns.
  */
 slang_type_specifier_type
 _slang_type_base(slang_type_specifier_type ty)
 {
    switch (ty) {
-   case slang_spec_float:
-   case slang_spec_vec2:
-   case slang_spec_vec3:
-   case slang_spec_vec4:
-      return slang_spec_float;
-   case slang_spec_int:
-   case slang_spec_ivec2:
-   case slang_spec_ivec3:
-   case slang_spec_ivec4:
-      return slang_spec_int;
-   case slang_spec_bool:
-   case slang_spec_bvec2:
-   case slang_spec_bvec3:
-   case slang_spec_bvec4:
-      return slang_spec_bool;
-   case slang_spec_mat2:
-      return slang_spec_vec2;
-   case slang_spec_mat3:
-      return slang_spec_vec3;
-   case slang_spec_mat4:
-      return slang_spec_vec4;
+   case SLANG_SPEC_FLOAT:
+   case SLANG_SPEC_VEC2:
+   case SLANG_SPEC_VEC3:
+   case SLANG_SPEC_VEC4:
+      return SLANG_SPEC_FLOAT;
+   case SLANG_SPEC_INT:
+   case SLANG_SPEC_IVEC2:
+   case SLANG_SPEC_IVEC3:
+   case SLANG_SPEC_IVEC4:
+      return SLANG_SPEC_INT;
+   case SLANG_SPEC_BOOL:
+   case SLANG_SPEC_BVEC2:
+   case SLANG_SPEC_BVEC3:
+   case SLANG_SPEC_BVEC4:
+      return SLANG_SPEC_BOOL;
+   case SLANG_SPEC_MAT2:
+      return SLANG_SPEC_VEC2;
+   case SLANG_SPEC_MAT3:
+      return SLANG_SPEC_VEC3;
+   case SLANG_SPEC_MAT4:
+      return SLANG_SPEC_VEC4;
+   case SLANG_SPEC_MAT23:
+      return SLANG_SPEC_VEC3;
+   case SLANG_SPEC_MAT32:
+      return SLANG_SPEC_VEC2;
+   case SLANG_SPEC_MAT24:
+      return SLANG_SPEC_VEC4;
+   case SLANG_SPEC_MAT42:
+      return SLANG_SPEC_VEC2;
+   case SLANG_SPEC_MAT34:
+      return SLANG_SPEC_VEC4;
+   case SLANG_SPEC_MAT43:
+      return SLANG_SPEC_VEC3;
    default:
-      return slang_spec_void;
+      return SLANG_SPEC_VOID;
    }
 }
 
 
 /**
- * Return the dimensionality of a vector or matrix type.
+ * Return the dimensionality of a vector, or for a matrix, return number
+ * of columns.
  */
 GLuint
 _slang_type_dim(slang_type_specifier_type ty)
 {
    switch (ty) {
-   case slang_spec_float:
-   case slang_spec_int:
-   case slang_spec_bool:
+   case SLANG_SPEC_FLOAT:
+   case SLANG_SPEC_INT:
+   case SLANG_SPEC_BOOL:
       return 1;
-   case slang_spec_vec2:
-   case slang_spec_ivec2:
-   case slang_spec_bvec2:
-   case slang_spec_mat2:
+   case SLANG_SPEC_VEC2:
+   case SLANG_SPEC_IVEC2:
+   case SLANG_SPEC_BVEC2:
+   case SLANG_SPEC_MAT2:
       return 2;
-   case slang_spec_vec3:
-   case slang_spec_ivec3:
-   case slang_spec_bvec3:
-   case slang_spec_mat3:
+   case SLANG_SPEC_VEC3:
+   case SLANG_SPEC_IVEC3:
+   case SLANG_SPEC_BVEC3:
+   case SLANG_SPEC_MAT3:
       return 3;
-   case slang_spec_vec4:
-   case slang_spec_ivec4:
-   case slang_spec_bvec4:
-   case slang_spec_mat4:
+   case SLANG_SPEC_VEC4:
+   case SLANG_SPEC_IVEC4:
+   case SLANG_SPEC_BVEC4:
+   case SLANG_SPEC_MAT4:
       return 4;
+
+   case SLANG_SPEC_MAT23:
+      return 2;
+   case SLANG_SPEC_MAT32:
+      return 3;
+   case SLANG_SPEC_MAT24:
+      return 2;
+   case SLANG_SPEC_MAT42:
+      return 4;
+   case SLANG_SPEC_MAT34:
+      return 3;
+   case SLANG_SPEC_MAT43:
+      return 4;
+
    default:
       return 0;
    }
 }
+
+
+/**
+ * Return the GL_* type that corresponds to a SLANG_SPEC_* type.
+ */
+GLenum
+_slang_gltype_from_specifier(const slang_type_specifier *type)
+{
+   switch (type->type) {
+   case SLANG_SPEC_BOOL:
+      return GL_BOOL;
+   case SLANG_SPEC_BVEC2:
+      return GL_BOOL_VEC2;
+   case SLANG_SPEC_BVEC3:
+      return GL_BOOL_VEC3;
+   case SLANG_SPEC_BVEC4:
+      return GL_BOOL_VEC4;
+   case SLANG_SPEC_INT:
+      return GL_INT;
+   case SLANG_SPEC_IVEC2:
+      return GL_INT_VEC2;
+   case SLANG_SPEC_IVEC3:
+      return GL_INT_VEC3;
+   case SLANG_SPEC_IVEC4:
+      return GL_INT_VEC4;
+   case SLANG_SPEC_FLOAT:
+      return GL_FLOAT;
+   case SLANG_SPEC_VEC2:
+      return GL_FLOAT_VEC2;
+   case SLANG_SPEC_VEC3:
+      return GL_FLOAT_VEC3;
+   case SLANG_SPEC_VEC4:
+      return GL_FLOAT_VEC4;
+   case SLANG_SPEC_MAT2:
+      return GL_FLOAT_MAT2;
+   case SLANG_SPEC_MAT3:
+      return GL_FLOAT_MAT3;
+   case SLANG_SPEC_MAT4:
+      return GL_FLOAT_MAT4;
+   case SLANG_SPEC_MAT23:
+      return GL_FLOAT_MAT2x3;
+   case SLANG_SPEC_MAT32:
+      return GL_FLOAT_MAT3x2;
+   case SLANG_SPEC_MAT24:
+      return GL_FLOAT_MAT2x4;
+   case SLANG_SPEC_MAT42:
+      return GL_FLOAT_MAT4x2;
+   case SLANG_SPEC_MAT34:
+      return GL_FLOAT_MAT3x4;
+   case SLANG_SPEC_MAT43:
+      return GL_FLOAT_MAT4x3;
+   case SLANG_SPEC_SAMPLER1D:
+      return GL_SAMPLER_1D;
+   case SLANG_SPEC_SAMPLER2D:
+      return GL_SAMPLER_2D;
+   case SLANG_SPEC_SAMPLER3D:
+      return GL_SAMPLER_3D;
+   case SLANG_SPEC_SAMPLERCUBE:
+      return GL_SAMPLER_CUBE;
+   case SLANG_SPEC_SAMPLER1DSHADOW:
+      return GL_SAMPLER_1D_SHADOW;
+   case SLANG_SPEC_SAMPLER2DSHADOW:
+      return GL_SAMPLER_2D_SHADOW;
+   case SLANG_SPEC_SAMPLER2DRECT:
+      return GL_SAMPLER_2D_RECT_ARB;
+   case SLANG_SPEC_SAMPLER2DRECTSHADOW:
+      return GL_SAMPLER_2D_RECT_SHADOW_ARB;
+   case SLANG_SPEC_ARRAY:
+      return _slang_gltype_from_specifier(type->_array);
+   case SLANG_SPEC_STRUCT:
+      /* fall-through */
+   default:
+      return GL_NONE;
+   }
+}
+