diff options
-rw-r--r-- | src/glsl/ast.h | 5 | ||||
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 14 | ||||
-rw-r--r-- | src/glsl/glsl_parser.yy | 51 | ||||
-rw-r--r-- | src/glsl/glsl_parser_extras.cpp | 188 |
4 files changed, 257 insertions, 1 deletions
diff --git a/src/glsl/ast.h b/src/glsl/ast.h index 44e9f1874b5..9b119edbb2f 100644 --- a/src/glsl/ast.h +++ b/src/glsl/ast.h @@ -915,6 +915,11 @@ _mesa_ast_array_index_to_hir(void *mem_ctx, ir_rvalue *array, ir_rvalue *idx, YYLTYPE &loc, YYLTYPE &idx_loc); +extern void +_mesa_ast_set_aggregate_type(const ast_type_specifier *type, + ast_expression *expr, + _mesa_glsl_parse_state *state); + void emit_function(_mesa_glsl_parse_state *state, ir_function *f); diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index c316127ff89..01203134d6d 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -4005,7 +4005,19 @@ ast_type_specifier::hir(exec_list *instructions, return NULL; } - if (this->structure != NULL) + /* _mesa_ast_set_aggregate_type() sets the <structure> field so that + * process_record_constructor() can do type-checking on C-style initializer + * expressions of structs, but ast_struct_specifier should only be translated + * to HIR if it is declaring the type of a structure. + * + * The ->is_declaration field is false for initializers of variables + * declared separately from the struct's type definition. + * + * struct S { ... }; (is_declaration = true) + * struct T { ... } t = { ... }; (is_declaration = true) + * S s = { ... }; (is_declaration = false) + */ + if (this->structure != NULL && this->structure->is_declaration) return this->structure->hir(instructions, state); return NULL; diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy index afbafce4cba..78f5bf6f4f2 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -221,6 +221,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %type <declarator_list> init_declarator_list %type <declarator_list> single_declaration %type <expression> initializer +%type <expression> initializer_list %type <node> declaration %type <node> declaration_statement %type <node> jump_statement @@ -961,6 +962,11 @@ init_declarator_list: $$ = $1; $$->declarations.push_tail(&decl->link); state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); + if ($7->oper == ast_aggregate) { + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7; + ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, NULL); + _mesa_ast_set_aggregate_type(type, ai, state); + } } | init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer { @@ -971,6 +977,11 @@ init_declarator_list: $$ = $1; $$->declarations.push_tail(&decl->link); state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); + if ($8->oper == ast_aggregate) { + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$8; + ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, $5); + _mesa_ast_set_aggregate_type(type, ai, state); + } } | init_declarator_list ',' any_identifier '=' initializer { @@ -981,6 +992,10 @@ init_declarator_list: $$ = $1; $$->declarations.push_tail(&decl->link); state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto)); + if ($5->oper == ast_aggregate) { + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$5; + _mesa_ast_set_aggregate_type($1->type->specifier, ai, state); + } } ; @@ -1028,6 +1043,11 @@ single_declaration: $$ = new(ctx) ast_declarator_list($1); $$->set_location(yylloc); $$->declarations.push_tail(&decl->link); + if ($6->oper == ast_aggregate) { + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$6; + ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, NULL); + _mesa_ast_set_aggregate_type(type, ai, state); + } } | fully_specified_type any_identifier '[' constant_expression ']' '=' initializer { @@ -1037,6 +1057,11 @@ single_declaration: $$ = new(ctx) ast_declarator_list($1); $$->set_location(yylloc); $$->declarations.push_tail(&decl->link); + if ($7->oper == ast_aggregate) { + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7; + ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, $4); + _mesa_ast_set_aggregate_type(type, ai, state); + } } | fully_specified_type any_identifier '=' initializer { @@ -1046,6 +1071,9 @@ single_declaration: $$ = new(ctx) ast_declarator_list($1); $$->set_location(yylloc); $$->declarations.push_tail(&decl->link); + if ($4->oper == ast_aggregate) { + _mesa_ast_set_aggregate_type($1->specifier, $4, state); + } } | INVARIANT variable_identifier // Vertex only. { @@ -1506,6 +1534,7 @@ struct_specifier: $$ = new(ctx) ast_struct_specifier($2, $4); $$->set_location(yylloc); state->symbols->add_type($2, glsl_type::void_type); + state->symbols->add_type_ast($2, new(ctx) ast_type_specifier($$)); } | STRUCT '{' struct_declaration_list '}' { @@ -1573,6 +1602,28 @@ struct_declarator: initializer: assignment_expression + | '{' initializer_list '}' + { + $$ = $2; + } + | '{' initializer_list ',' '}' + { + $$ = $2; + } + ; + +initializer_list: + initializer + { + void *ctx = state; + $$ = new(ctx) ast_aggregate_initializer(); + $$->set_location(yylloc); + $$->expressions.push_tail(& $1->link); + } + | initializer_list ',' initializer + { + $1->expressions.push_tail(& $3->link); + } ; declaration_statement: diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 602ec08328b..055dfa9937c 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -663,6 +663,194 @@ _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, return true; } + +/** + * Returns the name of the type of a column of a matrix. E.g., + * + * "mat3" -> "vec3" + * "mat4x2" -> "vec2" + */ +static const char * +_mesa_ast_get_matrix_column_type_name(const char *matrix_type_name) +{ + static const char *vec_name[] = { "vec2", "vec3", "vec4" }; + + /* The number of elements in a row of a matrix is specified by the last + * character of the matrix type name. + */ + long rows = strtol(matrix_type_name + strlen(matrix_type_name) - 1, + NULL, 10); + return vec_name[rows - 2]; +} + +/** + * Recurses through <type> and <expr> if <expr> is an aggregate initializer + * and sets <expr>'s <constructor_type> field to <type>. Gives later functions + * (process_array_constructor, et al) sufficient information to do type + * checking. + * + * Operates on assignments involving an aggregate initializer. E.g., + * + * vec4 pos = {1.0, -1.0, 0.0, 1.0}; + * + * or more ridiculously, + * + * struct S { + * vec4 v[2]; + * }; + * + * struct { + * S a[2], b; + * int c; + * } aggregate = { + * { + * { + * { + * {1.0, 2.0, 3.0, 4.0}, // a[0].v[0] + * {5.0, 6.0, 7.0, 8.0} // a[0].v[1] + * } // a[0].v + * }, // a[0] + * { + * { + * {1.0, 2.0, 3.0, 4.0}, // a[1].v[0] + * {5.0, 6.0, 7.0, 8.0} // a[1].v[1] + * } // a[1].v + * } // a[1] + * }, // a + * { + * { + * {1.0, 2.0, 3.0, 4.0}, // b.v[0] + * {5.0, 6.0, 7.0, 8.0} // b.v[1] + * } // b.v + * }, // b + * 4 // c + * }; + * + * This pass is necessary because the right-hand side of <type> e = { ... } + * doesn't contain sufficient information to determine if the types match. + */ +void +_mesa_ast_set_aggregate_type(const ast_type_specifier *type, + ast_expression *expr, + _mesa_glsl_parse_state *state) +{ + void *ctx = state; + ast_aggregate_initializer *ai = (ast_aggregate_initializer *)expr; + ai->constructor_type = (ast_type_specifier *)type; + + bool is_declaration = ai->constructor_type->structure != NULL; + if (!is_declaration) { + /* Look up <type> name in the symbol table to see if it's a struct. */ + const ast_type_specifier *struct_type = + state->symbols->get_type_ast(type->type_name); + ai->constructor_type->structure = + struct_type ? new(ctx) ast_struct_specifier(*struct_type->structure) + : NULL; + } + + /* If the aggregate is an array, recursively set its elements' types. */ + if (type->is_array) { + /* We want to set the element type which is not an array itself, so make + * a copy of the array type and set its is_array field to false. + * + * E.g., if <type> if struct S[2] we want to set each element's type to + * struct S. + * + * FINISHME: Update when ARB_array_of_arrays is supported. + */ + const ast_type_specifier *non_array_type = + new(ctx) ast_type_specifier(type, false, NULL); + + for (exec_node *expr_node = ai->expressions.head; + !expr_node->is_tail_sentinel(); + expr_node = expr_node->next) { + ast_expression *expr = exec_node_data(ast_expression, expr_node, + link); + + if (expr->oper == ast_aggregate) + _mesa_ast_set_aggregate_type(non_array_type, expr, state); + } + + /* If the aggregate is a struct, recursively set its fields' types. */ + } else if (ai->constructor_type->structure) { + ai->constructor_type->structure->is_declaration = is_declaration; + exec_node *expr_node = ai->expressions.head; + + /* Iterate through the struct's fields' declarations. E.g., iterate from + * "float a, b" to "int c" in the struct below. + * + * struct { + * float a, b; + * int c; + * } s; + */ + for (exec_node *decl_list_node = + ai->constructor_type->structure->declarations.head; + !decl_list_node->is_tail_sentinel(); + decl_list_node = decl_list_node->next) { + ast_declarator_list *decl_list = exec_node_data(ast_declarator_list, + decl_list_node, link); + + for (exec_node *decl_node = decl_list->declarations.head; + !decl_node->is_tail_sentinel() && !expr_node->is_tail_sentinel(); + decl_node = decl_node->next, expr_node = expr_node->next) { + ast_declaration *decl = exec_node_data(ast_declaration, decl_node, + link); + ast_expression *expr = exec_node_data(ast_expression, expr_node, + link); + + bool is_array = decl_list->type->specifier->is_array; + ast_expression *array_size = decl_list->type->specifier->array_size; + + /* Recognize variable declarations with the bracketed size attached + * to the type rather than the variable name as arrays. E.g., + * + * float a[2]; + * float[2] b; + * + * are both arrays, but <a>'s array_size is decl->array_size, while + * <b>'s array_size is decl_list->type->specifier->array_size. + */ + if (!is_array) { + /* FINISHME: Update when ARB_array_of_arrays is supported. */ + is_array = decl->is_array; + array_size = decl->array_size; + } + + /* Declaration shadows the <type> parameter. */ + ast_type_specifier *type = + new(ctx) ast_type_specifier(decl_list->type->specifier, + is_array, array_size); + + if (expr->oper == ast_aggregate) + _mesa_ast_set_aggregate_type(type, expr, state); + } + } + } else { + /* If the aggregate is a matrix, set its columns' types. */ + const char *name; + const glsl_type *const constructor_type = + ai->constructor_type->glsl_type(&name, state); + + if (constructor_type->is_matrix()) { + for (exec_node *expr_node = ai->expressions.head; + !expr_node->is_tail_sentinel(); + expr_node = expr_node->next) { + ast_expression *expr = exec_node_data(ast_expression, expr_node, + link); + + /* Declaration shadows the <type> parameter. */ + ast_type_specifier *type = new(ctx) + ast_type_specifier(_mesa_ast_get_matrix_column_type_name(name)); + + if (expr->oper == ast_aggregate) + _mesa_ast_set_aggregate_type(type, expr, state); + } + } + } +} + + void _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) { |