[gtk+/wip/otte/shader: 175/176] gsksl: Redo block parsing



commit 4881353e8c07b76974679c2850c26a04b8dcb468
Author: Benjamin Otte <otte redhat com>
Date:   Wed Oct 25 02:15:43 2017 +0200

    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 +
 .../gsksl/errors/duplicate-block-member-name.glsl  |    8 +
 5 files changed, 233 insertions(+), 93 deletions(-)
---
diff --git a/gsk/gsksldeclaration.c b/gsk/gsksldeclaration.c
index a8f785a..5431093 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 4668d70..45d9a97 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 3a91757..56a3ca7 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 *
@@ -394,6 +452,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,
                              const GskSlQualifier *qualifier,
diff --git a/gsk/gskslvariableprivate.h b/gsk/gskslvariableprivate.h
index da3592c..50ccece 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 0000000..191c64a
--- /dev/null
+++ b/testsuite/gsksl/errors/duplicate-block-member-name.glsl
@@ -0,0 +1,8 @@
+uniform Foo {
+  int x;
+  int x;
+};
+
+void main()
+{
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]