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:
Benjamin Otte
2017-10-25 02:15:43 +02:00
parent ad53eed564
commit a7dac28a3a
5 changed files with 233 additions and 93 deletions

View File

@@ -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))

View File

@@ -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));

View File

@@ -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,

View File

@@ -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,

View File

@@ -0,0 +1,8 @@
uniform Foo {
int x;
int x;
};
void main()
{
}