*/
#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"
_mesa_glsl_initialize_variables(instructions, state);
+ state->current_function = NULL;
+
foreach (ptr, & state->translation_unit) {
((ast_node *)ptr)->hir(instructions, state);
}
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()) {
}
+/**
+ * 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)
}
}
- /* 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);
* 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;
}
if (is_error_type(type) && !error_emitted)
- _mesa_glsl_error(& loc, NULL, "type mismatch");
+ _mesa_glsl_error(& loc, state, "type mismatch");
return result;
}
-ir_instruction *
-ast_function_expression::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- /* 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.
- */
- (void) instructions;
- (void) state;
- return NULL;
-}
-
ir_instruction *
ast_expression_statement::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
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.
*/
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.
*/
}
* FINISHME: declaration at a higher scope.
*/
- if (decl_type == NULL) {
+ if ((decl_type == NULL) || decl_type->is_void()) {
YYLTYPE loc;
loc = this->get_location();
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).
*/
/* 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",
continue;
}
+ const bool added_variable =
+ state->symbols->add_variable(decl->identifier, var);
+ assert(added_variable);
+
instructions->push_tail(var);
/* FINISHME: Process the declaration initializer. */
* 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);
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();
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;
}
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
}
+ 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;
}
* 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
*/
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;
+}