summaryrefslogtreecommitdiff
path: root/src/mesa/slang/slang_typeinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/slang/slang_typeinfo.c')
-rw-r--r--src/mesa/slang/slang_typeinfo.c1177
1 files changed, 1177 insertions, 0 deletions
diff --git a/src/mesa/slang/slang_typeinfo.c b/src/mesa/slang/slang_typeinfo.c
new file mode 100644
index 0000000000..0f96768b02
--- /dev/null
+++ b/src/mesa/slang/slang_typeinfo.c
@@ -0,0 +1,1177 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file slang_typeinfo.c
+ * slang type info
+ * \author Michal Krol
+ */
+
+#include "main/imports.h"
+#include "shader/prog_instruction.h"
+#include "slang_typeinfo.h"
+#include "slang_compile.h"
+#include "slang_log.h"
+#include "slang_mem.h"
+
+
+/**
+ * Checks if a field selector is a general swizzle (an r-value swizzle
+ * with replicated components or an l-value swizzle mask) for a
+ * vector. Returns GL_TRUE if this is the case, <swz> is filled with
+ * swizzle information. Returns GL_FALSE otherwise.
+ */
+GLboolean
+_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
+{
+ GLuint i;
+ GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
+
+ /* init to undefined.
+ * We rely on undefined/nil values to distinguish between
+ * regular swizzles and writemasks.
+ * For example, the swizzle ".xNNN" is the writemask ".x".
+ * That's different than the swizzle ".xxxx".
+ */
+ for (i = 0; i < 4; i++)
+ swz->swizzle[i] = SWIZZLE_NIL;
+
+ /* the swizzle can be at most 4-component long */
+ swz->num_components = slang_string_length(field);
+ if (swz->num_components > 4)
+ return GL_FALSE;
+
+ for (i = 0; i < swz->num_components; i++) {
+ /* mark which swizzle group is used */
+ switch (field[i]) {
+ case 'x':
+ case 'y':
+ case 'z':
+ case 'w':
+ xyzw = GL_TRUE;
+ break;
+ case 'r':
+ case 'g':
+ case 'b':
+ case 'a':
+ rgba = GL_TRUE;
+ break;
+ case 's':
+ case 't':
+ case 'p':
+ case 'q':
+ stpq = GL_TRUE;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ /* collect swizzle component */
+ switch (field[i]) {
+ case 'x':
+ case 'r':
+ case 's':
+ swz->swizzle[i] = 0;
+ break;
+ case 'y':
+ case 'g':
+ case 't':
+ swz->swizzle[i] = 1;
+ break;
+ case 'z':
+ case 'b':
+ case 'p':
+ swz->swizzle[i] = 2;
+ break;
+ case 'w':
+ case 'a':
+ case 'q':
+ swz->swizzle[i] = 3;
+ break;
+ }
+
+ /* check if the component is valid for given vector's row count */
+ if (rows <= swz->swizzle[i])
+ return GL_FALSE;
+ }
+
+ /* only one swizzle group can be used */
+ if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+
+/**
+ * Checks if a general swizzle is an l-value swizzle - these swizzles
+ * do not have duplicated fields. Returns GL_TRUE if this is a
+ * swizzle mask. Returns GL_FALSE otherwise
+ */
+static GLboolean
+_slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
+{
+ GLuint i, c = 0;
+
+ /* the swizzle may not be longer than the vector dim */
+ if (swz->num_components > rows)
+ return GL_FALSE;
+
+ /* the swizzle components cannot be duplicated */
+ for (i = 0; i < swz->num_components; i++) {
+ if ((c & (1 << swz->swizzle[i])) != 0)
+ return GL_FALSE;
+ c |= 1 << swz->swizzle[i];
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Combines (multiplies) two swizzles to form single swizzle.
+ * Example: "vec.wzyx.yx" --> "vec.zw".
+ */
+static void
+_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]];
+}
+
+
+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_SAMPLER_1D},
+ {"sampler2D", SLANG_SPEC_SAMPLER_2D},
+ {"sampler3D", SLANG_SPEC_SAMPLER_3D},
+ {"samplerCube", SLANG_SPEC_SAMPLER_CUBE},
+ {"sampler1DShadow", SLANG_SPEC_SAMPLER_1D_SHADOW},
+ {"sampler2DShadow", SLANG_SPEC_SAMPLER_2D_SHADOW},
+ {"sampler2DRect", SLANG_SPEC_SAMPLER_RECT},
+ {"sampler2DRectShadow", SLANG_SPEC_SAMPLER_RECT_SHADOW},
+ {"sampler1DArray", SLANG_SPEC_SAMPLER_1D_ARRAY},
+ {"sampler2DArray", SLANG_SPEC_SAMPLER_2D_ARRAY},
+ {"sampler1DArrayShadow", SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW},
+ {"sampler2DArrayShadow", SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW},
+ {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.layout = y->layout;
+ 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;
+}
+
+
+/**
+ * Test if two fully specified types are compatible. This is a bit
+ * looser than testing for equality. We don't check the precision,
+ * variant, centroid, etc. information.
+ * XXX this may need some tweaking.
+ */
+GLboolean
+slang_fully_specified_types_compatible(const slang_fully_specified_type * x,
+ const slang_fully_specified_type * y)
+{
+ if (!slang_type_specifier_equal(&x->specifier, &y->specifier))
+ return GL_FALSE;
+
+ if (x->qualifier == SLANG_QUAL_FIXEDINPUT &&
+ y->qualifier == SLANG_QUAL_VARYING)
+ ; /* ok */
+ else if (x->qualifier != y->qualifier)
+ return GL_FALSE;
+
+ /* Note: don't compare precision, variant, centroid */
+
+ /* XXX array length? */
+
+ return GL_TRUE;
+}
+
+
+GLvoid
+slang_type_specifier_ctr(slang_type_specifier * self)
+{
+ self->type = SLANG_SPEC_VOID;
+ self->_struct = NULL;
+ self->_array = NULL;
+}
+
+GLvoid
+slang_type_specifier_dtr(slang_type_specifier * self)
+{
+ if (self->_struct != NULL) {
+ slang_struct_destruct(self->_struct);
+ _slang_free(self->_struct);
+ }
+ if (self->_array != NULL) {
+ slang_type_specifier_dtr(self->_array);
+ _slang_free(self->_array);
+ }
+}
+
+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)
+{
+ slang_type_specifier z;
+
+ slang_type_specifier_ctr(&z);
+ z.type = y->type;
+ 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_free(z._struct);
+ slang_type_specifier_dtr(&z);
+ return GL_FALSE;
+ }
+ if (!slang_struct_copy(z._struct, y->_struct)) {
+ slang_type_specifier_dtr(&z);
+ return GL_FALSE;
+ }
+ }
+ 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;
+ }
+ slang_type_specifier_ctr(z._array);
+ if (!slang_type_specifier_copy(z._array, y->_array)) {
+ slang_type_specifier_dtr(&z);
+ return GL_FALSE;
+ }
+ }
+ slang_type_specifier_dtr(x);
+ *x = z;
+ 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 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_equal(x->_array, y->_array);
+ return GL_TRUE;
+}
+
+
+/**
+ * As above, but allow float/int casting.
+ */
+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;
+}
+
+
+GLboolean
+slang_typeinfo_construct(slang_typeinfo * ti)
+{
+ memset(ti, 0, sizeof(*ti));
+ slang_type_specifier_ctr(&ti->spec);
+ ti->array_len = 0;
+ return GL_TRUE;
+}
+
+GLvoid
+slang_typeinfo_destruct(slang_typeinfo * ti)
+{
+ slang_type_specifier_dtr(&ti->spec);
+}
+
+
+
+/**
+ * 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 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)
+{
+ GLboolean error;
+
+ *funFound = _slang_function_locate(space->funcs, a_name, params,
+ num_params, space, atoms, log, &error);
+ if (error)
+ return GL_FALSE;
+
+ 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
+ * \param spec returns the function's type
+ * \param atoms atom pool
+ * \return GL_TRUE for success, GL_FALSE if failure
+ */
+static GLboolean
+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)
+{
+ 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;
+
+ if (fun) {
+ /* Save pointer to save time in future */
+ call->fun = fun;
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Determine the return type of an operation.
+ * \param op the operation node
+ * \param space the namespace to use
+ * \param ti the returned type
+ * \param atoms atom pool
+ * \return GL_TRUE for success, GL_FALSE if failure
+ */
+GLboolean
+_slang_typeof_operation(slang_operation * op,
+ const slang_name_space * space,
+ slang_typeinfo * ti,
+ 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_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, log))
+ return GL_FALSE;
+ break;
+ 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_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_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_VARIABLE_DECL:
+ {
+ slang_variable *var;
+ 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);
+ 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;
+ 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)) {
+ 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:
+ /* TODO: check [1] and [2] if they match */
+ 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:
+ assert(op->num_children == 2);
+ if (!typeof_math_call("+", op, space, &ti->spec, atoms, log))
+ return GL_FALSE;
+ break;
+ 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:
+ assert(op->num_children == 2);
+ if (!typeof_math_call("*", op, space, &ti->spec, atoms, log))
+ return GL_FALSE;
+ break;
+ 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, log))
+ return GL_FALSE;
+ ti->can_be_referenced = GL_FALSE;
+ ti->is_swizzled = GL_FALSE;
+ break;
+ 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:
+ {
+ slang_typeinfo _ti;
+
+ if (!slang_typeinfo_construct(&_ti))
+ return GL_FALSE;
+ if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) {
+ slang_typeinfo_destruct(&_ti);
+ return GL_FALSE;
+ }
+ ti->can_be_referenced = _ti.can_be_referenced;
+ if (_ti.spec.type == SLANG_SPEC_ARRAY) {
+ if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) {
+ slang_typeinfo_destruct(&_ti);
+ return GL_FALSE;
+ }
+ }
+ else {
+ if (!_slang_type_is_vector(_ti.spec.type)
+ && !_slang_type_is_matrix(_ti.spec.type)) {
+ slang_typeinfo_destruct(&_ti);
+ 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:
+ 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);
+ }
+ else {
+ slang_function *fun;
+ if (!_slang_typeof_function(op->a_id, op->children, op->num_children,
+ 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) {
+ /* struct initializer */
+ ti->spec.type = SLANG_SPEC_STRUCT;
+ ti->spec._struct =
+ (slang_struct *) _slang_alloc(sizeof(slang_struct));
+ if (ti->spec._struct == NULL)
+ return GL_FALSE;
+ if (!slang_struct_construct(ti->spec._struct)) {
+ _slang_free(ti->spec._struct);
+ ti->spec._struct = NULL;
+ return GL_FALSE;
+ }
+ if (!slang_struct_copy(ti->spec._struct, s))
+ 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) {
+ slang_info_log_error(log, "undefined function '%s'", name);
+ return GL_FALSE;
+ }
+ ti->spec.type = type;
+ }
+ }
+ }
+ break;
+ case SLANG_OPER_METHOD:
+ /* at this time, GLSL 1.20 only has one method: array.length()
+ * which returns an integer.
+ */
+ ti->spec.type = SLANG_SPEC_INT;
+ break;
+ case SLANG_OPER_FIELD:
+ {
+ slang_typeinfo _ti;
+
+ if (!slang_typeinfo_construct(&_ti))
+ return GL_FALSE;
+ 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_variable_locate(_ti.spec._struct->fields, op->a_id,
+ GL_FALSE);
+ if (field == NULL) {
+ slang_typeinfo_destruct(&_ti);
+ return GL_FALSE;
+ }
+ if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) {
+ slang_typeinfo_destruct(&_ti);
+ return GL_FALSE;
+ }
+ ti->can_be_referenced = _ti.can_be_referenced;
+ ti->array_len = field->array_len;
+ }
+ else {
+ GLuint rows;
+ const char *swizzle;
+ slang_type_specifier_type base;
+
+ /* determine the swizzle of the field expression */
+ if (!_slang_type_is_vector(_ti.spec.type)) {
+ slang_typeinfo_destruct(&_ti);
+ slang_info_log_error(log, "Can't swizzle scalar expression");
+ return GL_FALSE;
+ }
+ 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);
+ 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
+ && _slang_is_swizzle_mask(&ti->swz, rows);
+ if (_ti.is_swizzled) {
+ slang_swizzle swz;
+
+ /* swizzle the swizzle */
+ _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz);
+ ti->swz = swz;
+ }
+ base = _slang_type_base(_ti.spec.type);
+ switch (ti->swz.num_components) {
+ case 1:
+ ti->spec.type = base;
+ break;
+ case 2:
+ switch (base) {
+ case SLANG_SPEC_FLOAT:
+ ti->spec.type = SLANG_SPEC_VEC2;
+ break;
+ case SLANG_SPEC_INT:
+ ti->spec.type = SLANG_SPEC_IVEC2;
+ break;
+ case SLANG_SPEC_BOOL:
+ ti->spec.type = SLANG_SPEC_BVEC2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (base) {
+ case SLANG_SPEC_FLOAT:
+ ti->spec.type = SLANG_SPEC_VEC3;
+ break;
+ case SLANG_SPEC_INT:
+ ti->spec.type = SLANG_SPEC_IVEC3;
+ break;
+ case SLANG_SPEC_BOOL:
+ ti->spec.type = SLANG_SPEC_BVEC3;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ switch (base) {
+ case SLANG_SPEC_FLOAT:
+ ti->spec.type = SLANG_SPEC_VEC4;
+ break;
+ case SLANG_SPEC_INT:
+ ti->spec.type = SLANG_SPEC_IVEC4;
+ break;
+ case SLANG_SPEC_BOOL:
+ ti->spec.type = SLANG_SPEC_BVEC4;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ slang_typeinfo_destruct(&_ti);
+ }
+ break;
+ 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 GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Determine if a type is a matrix.
+ * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
+ */
+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_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;
+ }
+}
+
+
+/**
+ * Determine if a type is a vector.
+ * \return GL_TRUE if is a vector, GL_FALSE otherwise.
+ */
+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:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Determine if a type is a float, float vector or float matrix.
+ * \return GL_TRUE if so, GL_FALSE otherwise
+ */
+GLboolean
+_slang_type_is_float_vec_mat(slang_type_specifier_type ty)
+{
+ switch (ty) {
+ case SLANG_SPEC_FLOAT:
+ case SLANG_SPEC_VEC2:
+ case SLANG_SPEC_VEC3:
+ case SLANG_SPEC_VEC4:
+ 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;
+ }
+}
+
+
+/**
+ * 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_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 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:
+ return 1;
+ 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:
+ return 3;
+ 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_SAMPLER_1D:
+ return GL_SAMPLER_1D;
+ case SLANG_SPEC_SAMPLER_2D:
+ return GL_SAMPLER_2D;
+ case SLANG_SPEC_SAMPLER_3D:
+ return GL_SAMPLER_3D;
+ case SLANG_SPEC_SAMPLER_CUBE:
+ return GL_SAMPLER_CUBE;
+ case SLANG_SPEC_SAMPLER_1D_SHADOW:
+ return GL_SAMPLER_1D_SHADOW;
+ case SLANG_SPEC_SAMPLER_2D_SHADOW:
+ return GL_SAMPLER_2D_SHADOW;
+ case SLANG_SPEC_SAMPLER_RECT:
+ return GL_SAMPLER_2D_RECT_ARB;
+ case SLANG_SPEC_SAMPLER_RECT_SHADOW:
+ return GL_SAMPLER_2D_RECT_SHADOW_ARB;
+ case SLANG_SPEC_SAMPLER_1D_ARRAY:
+ return GL_SAMPLER_1D_ARRAY_EXT;
+ case SLANG_SPEC_SAMPLER_2D_ARRAY:
+ return GL_SAMPLER_2D_ARRAY_EXT;
+ case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW:
+ return GL_SAMPLER_1D_ARRAY_SHADOW_EXT;
+ case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW:
+ return GL_SAMPLER_2D_ARRAY_SHADOW_EXT;
+ case SLANG_SPEC_ARRAY:
+ return _slang_gltype_from_specifier(type->_array);
+ case SLANG_SPEC_STRUCT:
+ /* fall-through */
+ default:
+ return GL_NONE;
+ }
+}
+