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.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
8
testsuite/gsksl/errors/duplicate-block-member-name.glsl
Normal file
8
testsuite/gsksl/errors/duplicate-block-member-name.glsl
Normal file
@@ -0,0 +1,8 @@
|
||||
uniform Foo {
|
||||
int x;
|
||||
int x;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user