From a7dac28a3a669eea5394e511c27a8d661944173f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 25 Oct 2017 02:15:43 +0200 Subject: [PATCH] gsksl: Redo block parsing Do not parse blocks while parsing types, instead move it to the declaration parsing. Also, add a special variable type for the case of unnamed blocks, so that we can access them directly. --- gsk/gsksldeclaration.c | 144 +++++++++++++++++- gsk/gsksltype.c | 92 +---------- gsk/gskslvariable.c | 80 +++++++++- gsk/gskslvariableprivate.h | 2 + .../errors/duplicate-block-member-name.glsl | 8 + 5 files changed, 233 insertions(+), 93 deletions(-) create mode 100644 testsuite/gsksl/errors/duplicate-block-member-name.glsl diff --git a/gsk/gsksldeclaration.c b/gsk/gsksldeclaration.c index a8f785a186..5431093a22 100644 --- a/gsk/gsksldeclaration.c +++ b/gsk/gsksldeclaration.c @@ -219,6 +219,136 @@ static const GskSlDeclarationClass GSK_SL_DECLARATION_FUNCTION = { /* API */ +static GskSlType * +gsk_sl_declaration_parse_block_type (GskSlScope *scope, + GskSlPreprocessor *preproc) +{ + GskSlType *type; + const GskSlToken *token; + GskSlTypeBuilder *builder; + + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) + { + builder = gsk_sl_type_builder_new_block (token->str); + gsk_sl_preprocessor_consume (preproc, NULL); + } + else + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected block name."); + return gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT)); + } + + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE)) + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected opening \"{\" after block declaration."); + goto out; + } + gsk_sl_preprocessor_consume (preproc, NULL); + + for (token = gsk_sl_preprocessor_get (preproc); + !gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE) && !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF); + token = gsk_sl_preprocessor_get (preproc)) + { + type = gsk_sl_type_new_parse (scope, preproc); + + while (TRUE) + { + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected identifier for type name."); + break; + } + if (gsk_sl_type_builder_has_member (builder, token->str)) + gsk_sl_preprocessor_error (preproc, DECLARATION, "Duplicate block member name \"%s\".", token->str); + else + gsk_sl_type_builder_add_member (builder, type, token->str); + gsk_sl_preprocessor_consume (preproc, NULL); + + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA)) + break; + + gsk_sl_preprocessor_consume (preproc, NULL); + } + gsk_sl_type_unref (type); + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected semicolon after block member declaration."); + else + gsk_sl_preprocessor_consume (preproc, NULL); + } + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE)) + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \"}\" after block declaration."); + gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_BRACE); + } + gsk_sl_preprocessor_consume (preproc, NULL); + +out: + return gsk_sl_type_builder_free (builder); +} + +static GskSlDeclaration * +gsk_sl_declaration_parse_block (GskSlScope *scope, + GskSlPreprocessor *preproc, + const GskSlQualifier *qualifier) +{ + GskSlDeclarationVariable *variable; + const GskSlToken *token; + GskSlType *type; + + type = gsk_sl_declaration_parse_block_type (scope, preproc); + + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) + { + char *name; + + name = g_strdup (token->str); + gsk_sl_preprocessor_consume (preproc, NULL); + + type = gsk_sl_type_parse_array (type, scope, preproc); + gsk_sl_qualifier_check_type (qualifier, preproc, type); + + variable = gsk_sl_declaration_new (&GSK_SL_DECLARATION_VARIABLE); + variable->variable = gsk_sl_variable_new (name, type, qualifier, NULL); + gsk_sl_scope_add_variable (scope, variable->variable); + + token = gsk_sl_preprocessor_get (preproc); + } + else + { + gsize i; + + gsk_sl_qualifier_check_type (qualifier, preproc, type); + + variable = gsk_sl_declaration_new (&GSK_SL_DECLARATION_VARIABLE); + variable->variable = gsk_sl_variable_new (NULL, type, qualifier, NULL); + + for (i = 0; i < gsk_sl_type_get_n_members (type); i++) + { + GskSlVariable *sub; + + sub = gsk_sl_variable_new_block_member (variable->variable, i); + gsk_sl_scope_add_variable (scope, sub); + gsk_sl_variable_unref (sub); + } + } + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "No semicolon at end of variable declaration."); + gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_SEMICOLON); + } + gsk_sl_preprocessor_consume (preproc, NULL); + + return &variable->parent; +} + static GskSlDeclaration * gsk_sl_declaration_parse_variable (GskSlScope *scope, GskSlPreprocessor *preproc, @@ -302,7 +432,19 @@ gsk_sl_declaration_parse (GskSlScope *scope, gsk_sl_qualifier_parse (&qualifier, scope, preproc, GSK_SL_QUALIFIER_GLOBAL); - type = gsk_sl_type_new_parse (scope, preproc); + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) + { + type = gsk_sl_scope_lookup_type (scope, token->str); + if (type == NULL) + return gsk_sl_declaration_parse_block (scope, preproc, &qualifier); + gsk_sl_type_ref (type); + gsk_sl_preprocessor_consume (preproc, NULL); + } + else + { + type = gsk_sl_type_new_parse (scope, preproc); + } token = gsk_sl_preprocessor_get (preproc); if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c index 4668d7040a..45d9a97835 100644 --- a/gsk/gsksltype.c +++ b/gsk/gsksltype.c @@ -1880,6 +1880,7 @@ gsk_sl_type_block_write_spv (GskSlType *type, ids, block->n_members); + gsk_spv_writer_name (writer, result_id, block->name); gsk_spv_writer_decorate (writer, result_id, GSK_SPV_DECORATION_BLOCK, NULL, 0); for (i = 0; i < block->n_members; i++) @@ -2090,85 +2091,6 @@ out: return type; } -static GskSlType * -gsk_sl_type_parse_block (GskSlScope *scope, - GskSlPreprocessor *preproc) -{ - GskSlType *type; - const GskSlToken *token; - GskSlTypeBuilder *builder; - - if (!gsk_sl_scope_is_global (scope)) - { - gsk_sl_preprocessor_error (preproc, SYNTAX, "Blocks are only allowed in global scope."); - return gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT)); - } - - token = gsk_sl_preprocessor_get (preproc); - if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) - { - builder = gsk_sl_type_builder_new_block (token->str); - gsk_sl_preprocessor_consume (preproc, NULL); - } - else - { - gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected block name."); - return gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT)); - } - - token = gsk_sl_preprocessor_get (preproc); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE)) - { - gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected opening \"{\" after block declaration."); - goto out; - } - gsk_sl_preprocessor_consume (preproc, NULL); - - for (token = gsk_sl_preprocessor_get (preproc); - !gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE) && !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF); - token = gsk_sl_preprocessor_get (preproc)) - { - type = gsk_sl_type_new_parse (scope, preproc); - - while (TRUE) - { - token = gsk_sl_preprocessor_get (preproc); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) - { - gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected identifier for type name."); - break; - } - if (gsk_sl_type_builder_has_member (builder, token->str)) - gsk_sl_preprocessor_error (preproc, DECLARATION, "struct already has a member named \"%s\".", token->str); - else - gsk_sl_type_builder_add_member (builder, type, token->str); - gsk_sl_preprocessor_consume (preproc, NULL); - - token = gsk_sl_preprocessor_get (preproc); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA)) - break; - - gsk_sl_preprocessor_consume (preproc, NULL); - } - gsk_sl_type_unref (type); - - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) - gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected semicolon after block member declaration."); - else - gsk_sl_preprocessor_consume (preproc, NULL); - } - - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE)) - { - gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \"}\" after block declaration."); - gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_BRACE); - } - gsk_sl_preprocessor_consume (preproc, NULL); - -out: - return gsk_sl_type_builder_free (builder); -} - GskSlType * gsk_sl_type_get_matching (GskSlType *type, GskSlScalarType scalar) @@ -2510,18 +2432,6 @@ gsk_sl_type_new_parse (GskSlScope *scope, break; case GSK_SL_TOKEN_STRUCT: return gsk_sl_type_parse_struct (scope, preproc); - case GSK_SL_TOKEN_IDENTIFIER: - { - type = gsk_sl_scope_lookup_type (scope, token->str); - - if (type) - { - type = gsk_sl_type_ref (type); - break; - } - - return gsk_sl_type_parse_block (scope, preproc); - } default: gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected type specifier"); return gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT)); diff --git a/gsk/gskslvariable.c b/gsk/gskslvariable.c index 3a917573ad..56a3ca7e6a 100644 --- a/gsk/gskslvariable.c +++ b/gsk/gskslvariable.c @@ -171,7 +171,8 @@ gsk_sl_variable_standard_write_spv (const GskSlVariable *variable, storage_class, value_id); - gsk_spv_writer_name (writer, result_id, variable->name); + if (variable->name) + gsk_spv_writer_name (writer, result_id, variable->name); gsk_sl_qualifier_write_spv_decorations (&variable->qualifier, writer, result_id); @@ -344,6 +345,63 @@ static const GskSlVariableClass GSK_SL_VARIABLE_CONST_PARAMETER = { gsk_sl_variable_const_parameter_load_spv }; +/* MEMBER */ + +typedef struct _GskSlVariableMember GskSlVariableMember; + +struct _GskSlVariableMember { + GskSlVariable parent; + + GskSlVariable *block; + gsize member_id; +}; + +static void +gsk_sl_variable_member_free (GskSlVariable *variable) +{ + const GskSlVariableMember *member = (const GskSlVariableMember *) variable; + + gsk_sl_variable_unref (member->block); + + gsk_sl_variable_free (variable); +} + +static GskSpvAccessChain * +gsk_sl_variable_member_get_access_chain (GskSlVariable *variable, + GskSpvWriter *writer) +{ + const GskSlVariableMember *member = (const GskSlVariableMember *) variable; + GskSpvAccessChain *chain; + GskSlValue *value; + + chain = gsk_sl_variable_get_access_chain (member->block, writer); + value = gsk_sl_value_new_for_data (gsk_sl_type_get_scalar (GSK_SL_INT), &(gint32) { member->member_id }, NULL, NULL); + gsk_spv_access_chain_add_index (chain, + variable->type, + gsk_spv_writer_get_id_for_value (writer, value)); + gsk_sl_value_free (value); + + return chain; +} + +static guint32 +gsk_sl_variable_member_write_spv (const GskSlVariable *variable, + GskSpvWriter *writer) +{ + const GskSlVariableMember *member = (const GskSlVariableMember *) variable; + + return gsk_spv_writer_get_id_for_variable (writer, member->block); +} + +static const GskSlVariableClass GSK_SL_VARIABLE_MEMBER = { + sizeof (GskSlVariableMember), + gsk_sl_variable_member_free, + gsk_sl_variable_default_get_initial_value, + gsk_sl_variable_member_get_access_chain, + gsk_sl_variable_member_write_spv, + gsk_sl_variable_default_load_spv +}; + /* API */ GskSlVariable * @@ -393,6 +451,26 @@ gsk_sl_variable_new (const char *name, } } +GskSlVariable * +gsk_sl_variable_new_block_member (GskSlVariable *block, + guint member_id) +{ + GskSlVariableMember *member; + + g_return_val_if_fail (block != NULL, NULL); + g_return_val_if_fail (gsk_sl_type_is_block (block->type), NULL); + g_return_val_if_fail (member_id < gsk_sl_type_get_n_members (block->type), NULL); + + member = gsk_sl_variable_alloc (&GSK_SL_VARIABLE_MEMBER, + gsk_sl_type_get_member_name (block->type, member_id), + &block->qualifier, + gsk_sl_type_get_member_type (block->type, member_id)); + member->block = gsk_sl_variable_ref (block); + member->member_id = member_id; + + return &member->parent; +} + GskSlVariable * gsk_sl_variable_new_builtin (const char *name, GskSlType *type, diff --git a/gsk/gskslvariableprivate.h b/gsk/gskslvariableprivate.h index da3592ccfa..50ccece38d 100644 --- a/gsk/gskslvariableprivate.h +++ b/gsk/gskslvariableprivate.h @@ -30,6 +30,8 @@ GskSlVariable * gsk_sl_variable_new (const char GskSlType *type, const GskSlQualifier *qualifier, GskSlValue *initial_value); +GskSlVariable * gsk_sl_variable_new_block_member (GskSlVariable *block, + guint member_id); GskSlVariable * gsk_sl_variable_new_builtin (const char *name, GskSlType *type, const GskSlQualifier *qualifier, diff --git a/testsuite/gsksl/errors/duplicate-block-member-name.glsl b/testsuite/gsksl/errors/duplicate-block-member-name.glsl new file mode 100644 index 0000000000..191c64a2ab --- /dev/null +++ b/testsuite/gsksl/errors/duplicate-block-member-name.glsl @@ -0,0 +1,8 @@ +uniform Foo { + int x; + int x; +}; + +void main() +{ +}