[gtk+/wip/otte/shader: 73/176] gsksl: Redo qualifier handling



commit 4295317aff075637e07b4164c595e1c982a62b69
Author: Benjamin Otte <otte redhat com>
Date:   Sun Oct 1 20:06:53 2017 +0200

    gsksl: Redo qualifier handling
    
    This is the 3rd time at least that I've rewritten it. This time, I've
    added a GskSlQualifier struct that contains all the information relevant
    to qualifiers. It replaces the previous GskSlDecorationList.

 gsk/gskslfunction.c           |   11 +-
 gsk/gskslpointertype.c        |  334 +--------------------------
 gsk/gskslpointertypeprivate.h |   41 +---
 gsk/gskslprogram.c            |   29 ++--
 gsk/gskslqualifier.c          |  511 +++++++++++++++++++++++++++++++++++++++++
 gsk/gskslqualifierprivate.h   |   86 +++++++
 gsk/gskslstatement.c          |   21 +-
 gsk/gsksltypesprivate.h       |    1 +
 gsk/gskslvariable.c           |   12 +-
 gsk/gskslvariableprivate.h    |    3 +-
 gsk/meson.build               |    1 +
 11 files changed, 648 insertions(+), 402 deletions(-)
---
diff --git a/gsk/gskslfunction.c b/gsk/gskslfunction.c
index cdb150c..79117b8 100644
--- a/gsk/gskslfunction.c
+++ b/gsk/gskslfunction.c
@@ -25,6 +25,7 @@
 #include "gskslpointertypeprivate.h"
 #include "gskslpreprocessorprivate.h"
 #include "gskslprinterprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
@@ -530,13 +531,11 @@ gsk_sl_function_new_parse (GskSlScope        *scope,
 
       while (TRUE)
         {
-          GskSlDecorations decoration;
+          GskSlQualifier qualifier;
           GskSlType *type;
           GskSlVariable *variable;
 
-          gsk_sl_decoration_list_parse (scope,
-                                        preproc,
-                                        &decoration);
+          gsk_sl_qualifier_parse (&qualifier, scope, preproc, GSK_SL_QUALIFIER_PARAMETER);
 
           type = gsk_sl_type_new_parse (scope, preproc);
 
@@ -560,8 +559,8 @@ gsk_sl_function_new_parse (GskSlScope        *scope,
                     gsk_sl_preprocessor_warn (preproc, SHADOW, "Function argument \"%s\" shadows global 
variable of same name.", token->str);
                 }
 
-              pointer_type = gsk_sl_pointer_type_new (type, TRUE, 
decoration.values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-              variable = gsk_sl_variable_new (pointer_type, g_strdup (token->str), NULL, 
decoration.values[GSK_SL_DECORATION_CONST].set);
+              pointer_type = gsk_sl_pointer_type_new (type, &qualifier);
+              variable = gsk_sl_variable_new (pointer_type, g_strdup (token->str), NULL);
               gsk_sl_pointer_type_unref (pointer_type);
               g_ptr_array_add (arguments, variable);
               
diff --git a/gsk/gskslpointertype.c b/gsk/gskslpointertype.c
index cdc9dbe..e96c88a 100644
--- a/gsk/gskslpointertype.c
+++ b/gsk/gskslpointertype.c
@@ -23,6 +23,7 @@
 #include "gskslexpressionprivate.h"
 #include "gskslpreprocessorprivate.h"
 #include "gskslprinterprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
 #include "gskslvalueprivate.h"
@@ -32,15 +33,12 @@ struct _GskSlPointerType {
   int ref_count;
 
   GskSlType *type;
-
-  gboolean local;
-  GskSlDecorationAccess access;
+  GskSlQualifier qualifier;
 };
 
 GskSlPointerType *
 gsk_sl_pointer_type_new (GskSlType             *type,
-                         gboolean               local,
-                         GskSlDecorationAccess  access)
+                         const GskSlQualifier  *qualifier)
 {
   GskSlPointerType *result;
 
@@ -48,303 +46,11 @@ gsk_sl_pointer_type_new (GskSlType             *type,
 
   result->ref_count = 1;
   result->type = gsk_sl_type_ref (type);
-  result->local = local;
-  result->access = access;
+  result->qualifier = *qualifier;
 
   return result;
 }
 
-static void
-gsk_sl_decoration_list_set (GskSlPreprocessor *preproc,
-                            GskSlDecorations  *list,
-                            GskSlDecoration    decoration,
-                            gint               value)
-{
-  list->values[decoration].set = TRUE;
-  list->values[decoration].value = value;
-}
-
-static void
-gsk_sl_decoration_list_add_simple (GskSlPreprocessor *preproc,
-                                   GskSlDecorations  *list,
-                                   GskSlDecoration    decoration)
-{
-  if (list->values[decoration].set)
-    {
-      gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate qualifier.");
-      return;
-    }
-
-  gsk_sl_decoration_list_set (preproc, list, decoration, 1);
-}
-
-static void
-gsk_sl_decoration_list_parse_assignment (GskSlPreprocessor *preproc,
-                                         GskSlScope        *scope,
-                                         GskSlDecorations  *list,
-                                         GskSlDecoration    decoration)
-{
-  GskSlExpression *expression;
-  const GskSlToken *token;
-  GskSlValue *value;
-  GskSlType *type;
-
-  gsk_sl_preprocessor_consume (preproc, NULL);
-  
-  token = gsk_sl_preprocessor_get (preproc);
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
-    {
-      gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \"=\" sign to assign a value.");
-      return;
-    }
-  gsk_sl_preprocessor_consume (preproc, NULL);
-
-  expression = gsk_sl_expression_parse_constant (scope, preproc);
-  if (expression == NULL)
-    return;
-
-  value = gsk_sl_expression_get_constant (expression);
-  gsk_sl_expression_unref (expression);
-
-  if (value == NULL)
-    {
-      gsk_sl_preprocessor_error (preproc, CONSTANT, "Expression is not constant.");
-      return;
-    }
-
-  type = gsk_sl_value_get_type (value);
-  if (gsk_sl_type_is_scalar (type) && gsk_sl_type_get_scalar_type (type) == GSK_SL_INT)
-    {
-      gsk_sl_decoration_list_set (preproc, list, decoration, *(gint32 *) gsk_sl_value_get_data (value));
-    }
-  else if (gsk_sl_type_is_scalar (type) && gsk_sl_type_get_scalar_type (type) == GSK_SL_UINT)
-    {
-      gsk_sl_decoration_list_set (preproc, list, decoration, *(guint32 *) gsk_sl_value_get_data (value));
-    }
-  else
-    {
-      gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Type of expression is not an integer type, but 
%s", gsk_sl_type_get_name (type));
-    }
-  gsk_sl_value_free (value);
-}
-
-static void
-gsk_sl_decoration_list_parse_layout (GskSlPreprocessor *preproc,
-                                     GskSlScope        *scope,
-                                     GskSlDecorations  *list)
-{
-  const GskSlToken *token;
-
-  memset (list, 0, sizeof (GskSlDecorations));
-
-  while (TRUE)
-    {
-      token = gsk_sl_preprocessor_get (preproc);
-
-      if (gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
-        {
-          gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected layout identifier.");
-          break;
-        }
-      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
-        {
-          if (g_str_equal (token->str, "location"))
-            {
-              gsk_sl_decoration_list_parse_assignment (preproc,
-                                                       scope,
-                                                       list, 
-                                                       GSK_SL_DECORATION_LAYOUT_LOCATION);
-            }
-          else if (g_str_equal (token->str, "component"))
-            {
-              gsk_sl_decoration_list_parse_assignment (preproc,
-                                                       scope,
-                                                       list, 
-                                                       GSK_SL_DECORATION_LAYOUT_COMPONENT);
-            }
-          else if (g_str_equal (token->str, "binding"))
-            {
-              gsk_sl_decoration_list_parse_assignment (preproc,
-                                                       scope,
-                                                       list, 
-                                                       GSK_SL_DECORATION_LAYOUT_BINDING);
-            }
-          else if (g_str_equal (token->str, "set"))
-            {
-              gsk_sl_decoration_list_parse_assignment (preproc,
-                                                       scope,
-                                                       list, 
-                                                       GSK_SL_DECORATION_LAYOUT_SET);
-            }
-          else
-            {
-              gsk_sl_preprocessor_error (preproc, UNSUPPORTED, "Unknown layout identifier.");
-              gsk_sl_preprocessor_consume (preproc, NULL);
-            }
-        }
-      else
-        {
-          gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected layout identifier.");
-          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);
-    }
-}
-
-void
-gsk_sl_decoration_list_parse (GskSlScope        *scope,
-                              GskSlPreprocessor *preproc,
-                              GskSlDecorations  *list)
-{
-  const GskSlToken *token;
-
-  memset (list, 0, sizeof (GskSlDecorations));
-
-  while (TRUE)
-    {
-      token = gsk_sl_preprocessor_get (preproc);
-      switch ((guint) token->type)
-      {
-        case GSK_SL_TOKEN_CONST:
-          gsk_sl_decoration_list_add_simple (preproc, list, GSK_SL_DECORATION_CONST);
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_IN:
-          if (list->values[GSK_SL_DECORATION_CALLER_ACCESS].value & GSK_SL_DECORATION_ACCESS_READ)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"in\" qualifier specified twice.");
-            }
-          else
-            {
-              gsk_sl_decoration_list_set (preproc, list,
-                                          GSK_SL_DECORATION_CALLER_ACCESS,
-                                          list->values[GSK_SL_DECORATION_CALLER_ACCESS].value | 
GSK_SL_DECORATION_ACCESS_READ);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_OUT:
-          if (list->values[GSK_SL_DECORATION_CALLER_ACCESS].value & GSK_SL_DECORATION_ACCESS_WRITE)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"out\" qualifier specified twice.");
-            }
-          else
-            {
-              gsk_sl_decoration_list_set (preproc, list,
-                                          GSK_SL_DECORATION_CALLER_ACCESS,
-                                          list->values[GSK_SL_DECORATION_CALLER_ACCESS].value | 
GSK_SL_DECORATION_ACCESS_WRITE);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_INOUT:
-          if (list->values[GSK_SL_DECORATION_CALLER_ACCESS].value & GSK_SL_DECORATION_ACCESS_READ)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"in\" qualifier already used.");
-            }
-          else if (list->values[GSK_SL_DECORATION_CALLER_ACCESS].value & GSK_SL_DECORATION_ACCESS_WRITE)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"out\" qualifier already used.");
-            }
-          else
-            {
-              gsk_sl_decoration_list_set (preproc, list,
-                                          GSK_SL_DECORATION_CALLER_ACCESS,
-                                          GSK_SL_DECORATION_ACCESS_READWRITE);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_INVARIANT:
-          gsk_sl_decoration_list_add_simple (preproc, list, GSK_SL_DECORATION_INVARIANT);
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_COHERENT:
-          gsk_sl_decoration_list_add_simple (preproc, list, GSK_SL_DECORATION_COHERENT);
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_VOLATILE:
-          gsk_sl_decoration_list_add_simple (preproc, list, GSK_SL_DECORATION_VOLATILE);
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_RESTRICT:
-          gsk_sl_decoration_list_add_simple (preproc, list, GSK_SL_DECORATION_RESTRICT);
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-
-        case GSK_SL_TOKEN_READONLY:
-          if (list->values[GSK_SL_DECORATION_ACCESS].value & GSK_SL_DECORATION_ACCESS_READ)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"readonly\" qualifier specified twice.");
-            }
-          else if (list->values[GSK_SL_DECORATION_ACCESS].value & GSK_SL_DECORATION_ACCESS_WRITE)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"writeonly\" qualifier already used.");
-            }
-          else
-            {
-              gsk_sl_decoration_list_set (preproc, list,
-                                          GSK_SL_DECORATION_ACCESS,
-                                          GSK_SL_DECORATION_ACCESS_READ);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_WRITEONLY:
-          if (list->values[GSK_SL_DECORATION_ACCESS].value & GSK_SL_DECORATION_ACCESS_READ)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"readonly\" qualifier already used.");
-            }
-          else if (list->values[GSK_SL_DECORATION_ACCESS].value & GSK_SL_DECORATION_ACCESS_WRITE)
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "\"writeonly\" qualifier specified twice.");
-            }
-          else
-            {
-              gsk_sl_decoration_list_set (preproc, list,
-                                          GSK_SL_DECORATION_ACCESS,
-                                          GSK_SL_DECORATION_ACCESS_WRITE);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        case GSK_SL_TOKEN_LAYOUT:
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          token = gsk_sl_preprocessor_get (preproc);
-          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected opening \"(\" after layout specifier");
-              break;
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-
-          gsk_sl_decoration_list_parse_layout (preproc, scope, list);
-
-          token = gsk_sl_preprocessor_get (preproc);
-          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
-            {
-              gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \")\" at end of layout 
specifier");
-              gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_PAREN);
-            }
-          gsk_sl_preprocessor_consume (preproc, NULL);
-          break;
-
-        default:
-          return;
-      }
-    }
-}
-
 GskSlPointerType *
 gsk_sl_pointer_type_ref (GskSlPointerType *type)
 {
@@ -374,13 +80,8 @@ void
 gsk_sl_pointer_type_print (const GskSlPointerType *type,
                            GskSlPrinter           *printer)
 {
-  if (type->access == GSK_SL_DECORATION_ACCESS_READWRITE)
-    gsk_sl_printer_append (printer, "inout ");
-  else if (type->access == GSK_SL_DECORATION_ACCESS_READ)
-    gsk_sl_printer_append (printer, "in ");
-  else if (type->access == GSK_SL_DECORATION_ACCESS_WRITE)
-    gsk_sl_printer_append (printer, "out ");
-
+  if (gsk_sl_qualifier_print (&type->qualifier, printer))
+    gsk_sl_printer_append (printer, " ");
   gsk_sl_printer_append (printer, gsk_sl_type_get_name (type->type));
 }
 
@@ -390,19 +91,10 @@ gsk_sl_pointer_type_get_type (const GskSlPointerType *type)
   return type->type;
 }
 
-GskSpvStorageClass
-gsk_sl_pointer_type_get_storage_class (const GskSlPointerType *type)
+const GskSlQualifier *
+gsk_sl_pointer_type_get_qualifier (const GskSlPointerType *type)
 {
-  if (type->local)
-    return GSK_SPV_STORAGE_CLASS_FUNCTION;
-
-  if (type->access & GSK_SL_DECORATION_ACCESS_WRITE)
-    return GSK_SPV_STORAGE_CLASS_OUTPUT;
-
-  if (type->access & GSK_SL_DECORATION_ACCESS_READ)
-    return GSK_SPV_STORAGE_CLASS_INPUT;
-
-  return GSK_SPV_STORAGE_CLASS_PRIVATE;
+  return &type->qualifier;
 }
 
 gboolean
@@ -415,8 +107,8 @@ gsk_sl_pointer_type_equal (gconstpointer a,
   if (!gsk_sl_type_equal (typea->type, typeb->type))
     return FALSE;
 
-  return gsk_sl_pointer_type_get_storage_class (typea)
-      == gsk_sl_pointer_type_get_storage_class (typeb);
+  return gsk_sl_qualifier_get_storage_class (&typea->qualifier)
+      == gsk_sl_qualifier_get_storage_class (&typeb->qualifier);
 }
 
 guint
@@ -425,7 +117,7 @@ gsk_sl_pointer_type_hash (gconstpointer t)
   const GskSlPointerType *type = t;
 
   return gsk_sl_type_hash (type->type)
-       ^ gsk_sl_pointer_type_get_storage_class (type);
+       ^ gsk_sl_qualifier_get_storage_class (&type->qualifier);
 }
 
 guint32
@@ -441,7 +133,7 @@ gsk_sl_pointer_type_write_spv (const GskSlPointerType *type,
                       GSK_SPV_WRITER_SECTION_DECLARE,
                       4, GSK_SPV_OP_TYPE_POINTER,
                       (guint32[3]) { result_id,
-                                     gsk_sl_pointer_type_get_storage_class (type),
+                                     gsk_sl_qualifier_get_storage_class (&type->qualifier),
                                      type_id });
 
   return result_id;
diff --git a/gsk/gskslpointertypeprivate.h b/gsk/gskslpointertypeprivate.h
index 1a891a2..444089f 100644
--- a/gsk/gskslpointertypeprivate.h
+++ b/gsk/gskslpointertypeprivate.h
@@ -26,45 +26,8 @@
 
 G_BEGIN_DECLS
 
-typedef enum {
-  GSK_SL_DECORATION_CONST,
-  GSK_SL_DECORATION_CALLER_ACCESS,
-  GSK_SL_DECORATION_INVARIANT,
-  GSK_SL_DECORATION_COHERENT,
-  GSK_SL_DECORATION_VOLATILE,
-  GSK_SL_DECORATION_RESTRICT,
-  GSK_SL_DECORATION_ACCESS,
-  GSK_SL_DECORATION_LAYOUT_LOCATION,
-  GSK_SL_DECORATION_LAYOUT_COMPONENT,
-  GSK_SL_DECORATION_LAYOUT_SET,
-  GSK_SL_DECORATION_LAYOUT_BINDING,
-  /* add */
-  GSK_SL_N_DECORATIONS
-} GskSlDecoration;
-
-typedef enum {
-  GSK_SL_DECORATION_ACCESS_READ = (1 << 0),
-  GSK_SL_DECORATION_ACCESS_WRITE = (2 << 0),
-  GSK_SL_DECORATION_ACCESS_READWRITE = GSK_SL_DECORATION_ACCESS_READ | GSK_SL_DECORATION_ACCESS_WRITE,
-} GskSlDecorationAccess;
-
-typedef struct _GskSlDecorations GskSlDecorations;
-
-struct _GskSlDecorations
-{
-  struct {
-    gboolean set;
-    gint value;
-  } values[GSK_SL_N_DECORATIONS];
-};
-
-void                    gsk_sl_decoration_list_parse                    (GskSlScope                 *scope,
-                                                                         GskSlPreprocessor          *stream,
-                                                                         GskSlDecorations           *list);
-
 GskSlPointerType *      gsk_sl_pointer_type_new                         (GskSlType                  *type,
-                                                                         gboolean                    local,
-                                                                         GskSlDecorationAccess       access);
+                                                                         const GskSlQualifier       
*qualifier);
 
 GskSlPointerType *      gsk_sl_pointer_type_ref                         (GskSlPointerType           *type);
 void                    gsk_sl_pointer_type_unref                       (GskSlPointerType           *type);
@@ -73,12 +36,12 @@ void                    gsk_sl_pointer_type_print                       (const G
                                                                          GskSlPrinter               
*printer);
 
 GskSlType *             gsk_sl_pointer_type_get_type                    (const GskSlPointerType     *type);
+const GskSlQualifier *  gsk_sl_pointer_type_get_qualifier               (const GskSlPointerType     *type);
 
 gboolean                gsk_sl_pointer_type_equal                       (gconstpointer               a,
                                                                          gconstpointer               b);
 guint                   gsk_sl_pointer_type_hash                        (gconstpointer               type);
 
-GskSpvStorageClass      gsk_sl_pointer_type_get_storage_class           (const GskSlPointerType     *type);
 guint32                 gsk_sl_pointer_type_write_spv                   (const GskSlPointerType     *type,
                                                                          GskSpvWriter               *writer);
 
diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c
index f149d82..503b535 100644
--- a/gsk/gskslprogram.c
+++ b/gsk/gskslprogram.c
@@ -26,6 +26,7 @@
 #include "gskslpreprocessorprivate.h"
 #include "gskslprinterprivate.h"
 #include "gskslscopeprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
 #include "gskslvalueprivate.h"
@@ -69,12 +70,12 @@ gsk_sl_program_init (GskSlProgram *program)
 }
 
 static void
-gsk_sl_program_parse_variable (GskSlProgram      *program,
-                               GskSlScope        *scope,
-                               GskSlPreprocessor *preproc,
-                               GskSlDecorations  *decoration,
-                               GskSlType         *type,
-                               const char        *name)
+gsk_sl_program_parse_variable (GskSlProgram         *program,
+                               GskSlScope           *scope,
+                               GskSlPreprocessor    *preproc,
+                               const GskSlQualifier *qualifier,
+                               GskSlType            *type,
+                               const char           *name)
 {
   GskSlVariable *variable;
   const GskSlToken *token;
@@ -125,8 +126,8 @@ gsk_sl_program_parse_variable (GskSlProgram      *program,
     }
   gsk_sl_preprocessor_consume (preproc, NULL);
 
-  pointer_type = gsk_sl_pointer_type_new (type, FALSE, 
decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-  variable = gsk_sl_variable_new (pointer_type, g_strdup (name), value, 
decoration->values[GSK_SL_DECORATION_CONST].set);
+  pointer_type = gsk_sl_pointer_type_new (type, qualifier);
+  variable = gsk_sl_variable_new (pointer_type, g_strdup (name), value);
   gsk_sl_pointer_type_unref (pointer_type);
       
   program->variables = g_slist_append (program->variables, variable);
@@ -140,20 +141,18 @@ gsk_sl_program_parse_declaration (GskSlProgram      *program,
 {
   GskSlType *type;
   const GskSlToken *token;
-  GskSlDecorations decoration;
+  GskSlQualifier qualifier;
   char *name;
 
-  gsk_sl_decoration_list_parse (scope,
-                                preproc,
-                                &decoration);
+  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_SEMICOLON))
     {
-      GskSlPointerType *ptype = gsk_sl_pointer_type_new (type, FALSE, 
decoration.values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-      GskSlVariable *variable = gsk_sl_variable_new (ptype, NULL, NULL, 
decoration.values[GSK_SL_DECORATION_CONST].set);
+      GskSlPointerType *ptype = gsk_sl_pointer_type_new (type, &qualifier);
+      GskSlVariable *variable = gsk_sl_variable_new (ptype, NULL, NULL);
       gsk_sl_pointer_type_unref (ptype);
       program->variables = g_slist_append (program->variables, variable);
       gsk_sl_preprocessor_consume (preproc, program);
@@ -193,7 +192,7 @@ gsk_sl_program_parse_declaration (GskSlProgram      *program,
     }
   else
     {
-      gsk_sl_program_parse_variable (program, scope, preproc, &decoration, type, name);
+      gsk_sl_program_parse_variable (program, scope, preproc, &qualifier, type, name);
     }
 
   g_free (name);
diff --git a/gsk/gskslqualifier.c b/gsk/gskslqualifier.c
new file mode 100644
index 0000000..21f286f
--- /dev/null
+++ b/gsk/gskslqualifier.c
@@ -0,0 +1,511 @@
+/* GTK - The GIMP Toolkit
+ *   
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gskslqualifierprivate.h"
+
+#include "gskslexpressionprivate.h"
+#include "gskslpreprocessorprivate.h"
+#include "gskslprinterprivate.h"
+#include "gsksltokenizerprivate.h"
+#include "gsksltypeprivate.h"
+#include "gskslvalueprivate.h"
+
+void
+gsk_sl_qualifier_init (GskSlQualifier *qualifier)
+{
+  *qualifier = (GskSlQualifier) { .storage = GSK_SL_STORAGE_DEFAULT,
+                                  .layout = { -1, -1, -1, -1 },
+                                };
+}
+
+static void
+gsk_sl_qualifier_parse_layout_assignment (GskSlPreprocessor *preproc,
+                                          GskSlScope        *scope,
+                                          int               *target)
+{
+  GskSlExpression *expression;
+  const GskSlToken *token;
+  GskSlValue *value;
+  GskSlType *type;
+
+  gsk_sl_preprocessor_consume (preproc, NULL);
+  
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
+    {
+      gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \"=\" sign to assign a value.");
+      return;
+    }
+  gsk_sl_preprocessor_consume (preproc, NULL);
+
+  expression = gsk_sl_expression_parse_constant (scope, preproc);
+  if (expression == NULL)
+    return;
+
+  value = gsk_sl_expression_get_constant (expression);
+  gsk_sl_expression_unref (expression);
+
+  if (value == NULL)
+    {
+      gsk_sl_preprocessor_error (preproc, CONSTANT, "Expression is not constant.");
+      return;
+    }
+
+  type = gsk_sl_value_get_type (value);
+  if (gsk_sl_type_is_scalar (type) && gsk_sl_type_get_scalar_type (type) == GSK_SL_INT)
+    {
+      gint32 i = *(gint32 *) gsk_sl_value_get_data (value);
+
+      if (i < 0)
+        gsk_sl_preprocessor_error (preproc, CONSTANT, "Expression may not be negative.");
+      else
+        *target = i;
+    }
+  else if (gsk_sl_type_is_scalar (type) && gsk_sl_type_get_scalar_type (type) == GSK_SL_UINT)
+    {
+      *target = *(guint32 *) gsk_sl_value_get_data (value);
+    }
+  else
+    {
+      gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Type of expression is not an integer type, but 
%s", gsk_sl_type_get_name (type));
+    }
+  gsk_sl_value_free (value);
+}
+
+static void
+gsk_sl_qualifier_parse_layout (GskSlQualifier    *qualifier,
+                               GskSlPreprocessor *preproc,
+                               GskSlScope        *scope)
+{
+  const GskSlToken *token;
+
+  while (TRUE)
+    {
+      token = gsk_sl_preprocessor_get (preproc);
+
+      if (gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+        {
+          gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected layout identifier.");
+          break;
+        }
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+        {
+          if (g_str_equal (token->str, "location"))
+            gsk_sl_qualifier_parse_layout_assignment (preproc, scope, &qualifier->layout.location);
+          else if (g_str_equal (token->str, "component"))
+            gsk_sl_qualifier_parse_layout_assignment (preproc, scope, &qualifier->layout.component);
+          else if (g_str_equal (token->str, "binding"))
+            gsk_sl_qualifier_parse_layout_assignment (preproc, scope, &qualifier->layout.binding);
+          else if (g_str_equal (token->str, "set"))
+            gsk_sl_qualifier_parse_layout_assignment (preproc, scope, &qualifier->layout.set);
+          else
+            {
+              gsk_sl_preprocessor_error (preproc, UNSUPPORTED, "Unknown layout identifier.");
+              gsk_sl_preprocessor_consume (preproc, NULL);
+            }
+        }
+      else
+        {
+          gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected layout identifier.");
+          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);
+    }
+}
+
+static const char * 
+gsk_sl_storage_get_name (GskSlStorage storage)
+{
+  switch (storage)
+    {
+    default:
+    case GSK_SL_STORAGE_DEFAULT:
+      g_assert_not_reached ();
+      return "???";
+    case GSK_SL_STORAGE_GLOBAL:
+    case GSK_SL_STORAGE_LOCAL:
+    case GSK_SL_STORAGE_PARAMETER_IN:
+      return "";
+    case GSK_SL_STORAGE_GLOBAL_CONST:
+    case GSK_SL_STORAGE_LOCAL_CONST:
+    case GSK_SL_STORAGE_PARAMETER_CONST:
+      return "const";
+    case GSK_SL_STORAGE_GLOBAL_IN:
+      return "in";
+    case GSK_SL_STORAGE_GLOBAL_OUT:
+    case GSK_SL_STORAGE_PARAMETER_OUT:
+      return "out";
+    case GSK_SL_STORAGE_PARAMETER_INOUT:
+      return "inout";
+    }
+}
+
+static gboolean
+gsk_sl_storage_allows_const (GskSlStorage storage)
+{
+  switch (storage)
+    {
+    case GSK_SL_STORAGE_GLOBAL_CONST:
+    case GSK_SL_STORAGE_LOCAL_CONST:
+    case GSK_SL_STORAGE_PARAMETER_CONST:
+    default:
+      g_assert_not_reached ();
+    case GSK_SL_STORAGE_GLOBAL_OUT:
+    case GSK_SL_STORAGE_PARAMETER_OUT:
+    case GSK_SL_STORAGE_PARAMETER_INOUT:
+      return FALSE;
+    case GSK_SL_STORAGE_DEFAULT:
+    case GSK_SL_STORAGE_GLOBAL:
+    case GSK_SL_STORAGE_GLOBAL_IN:
+    case GSK_SL_STORAGE_LOCAL:
+    case GSK_SL_STORAGE_PARAMETER_IN:
+      return TRUE;
+    }
+}
+
+void
+gsk_sl_qualifier_parse (GskSlQualifier         *qualifier,
+                        GskSlScope             *scope,
+                        GskSlPreprocessor      *preproc,
+                        GskSlQualifierLocation  location)
+{
+  const GskSlToken *token;
+  gboolean seen_const = FALSE;
+
+  gsk_sl_qualifier_init (qualifier);
+
+  while (TRUE)
+    {
+      token = gsk_sl_preprocessor_get (preproc);
+      switch ((guint) token->type)
+      {
+        case GSK_SL_TOKEN_CONST:
+          if (seen_const)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"const\" qualifier.");
+          if (!gsk_sl_storage_allows_const (qualifier->storage))
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "\"%s\" qualifier cannot be const.", 
gsk_sl_storage_get_name (qualifier->storage));
+          else
+            seen_const = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_IN:
+          if (qualifier->storage == GSK_SL_STORAGE_DEFAULT)
+            {
+              if (location == GSK_SL_QUALIFIER_LOCAL)
+                gsk_sl_preprocessor_error (preproc, SYNTAX, "Local variables cannot have \"in\" qualifier.");
+              else
+                qualifier->storage = location == GSK_SL_QUALIFIER_GLOBAL ? GSK_SL_STORAGE_GLOBAL_IN
+                                                                         : GSK_SL_STORAGE_PARAMETER_IN;
+            }
+          else if (qualifier->storage == GSK_SL_STORAGE_PARAMETER_OUT)
+            qualifier->storage = GSK_SL_STORAGE_PARAMETER_INOUT;
+          else
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Qualifiers \"%s\" and \"in\" cannot be combined.", 
gsk_sl_storage_get_name (qualifier->storage));
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_OUT:
+          if (seen_const)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Const variables cannot have \"out\" qualifier.");
+          else if (qualifier->storage == GSK_SL_STORAGE_DEFAULT)
+            {
+              if (location == GSK_SL_QUALIFIER_LOCAL)
+                gsk_sl_preprocessor_error (preproc, SYNTAX, "Local variables cannot have \"out\" 
qualifier.");
+              else
+                qualifier->storage = location == GSK_SL_QUALIFIER_GLOBAL ? GSK_SL_STORAGE_GLOBAL_OUT
+                                                                         : GSK_SL_STORAGE_PARAMETER_OUT;
+            }
+          else if (qualifier->storage == GSK_SL_STORAGE_PARAMETER_IN)
+            qualifier->storage = GSK_SL_STORAGE_PARAMETER_INOUT;
+          else
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Qualifiers \"%s\" and \"out\" cannot be combined.", 
gsk_sl_storage_get_name (qualifier->storage));
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_INOUT:
+          if (seen_const)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Const variables cannot have \"inout\" qualifier.");
+          else if (qualifier->storage == GSK_SL_STORAGE_DEFAULT)
+            {
+              if (location != GSK_SL_QUALIFIER_PARAMETER)
+                gsk_sl_preprocessor_error (preproc, SYNTAX, "\"inout\" can only be used on parameters.");
+              else
+                qualifier->storage = GSK_SL_STORAGE_PARAMETER_INOUT;
+            }
+          else
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Qualifiers \"%s\" and \"inout\" cannot be 
combined.", gsk_sl_storage_get_name (qualifier->storage));
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_INVARIANT:
+          if (qualifier->invariant)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"invariant\" qualifier.");
+          qualifier->invariant = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_COHERENT:
+          if (qualifier->coherent)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"coherent\" qualifier.");
+          qualifier->coherent = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_VOLATILE:
+          if (qualifier->volatile_)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"volatile\" qualifier.");
+          qualifier->volatile_ = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_RESTRICT:
+          if (qualifier->restrict_)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"restrict\" qualifier.");
+          qualifier->restrict_ = TRUE;
+          break;
+
+        case GSK_SL_TOKEN_READONLY:
+          if (qualifier->readonly)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"readonly\" qualifier.");
+          qualifier->readonly = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_WRITEONLY:
+          if (qualifier->writeonly)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Duplicate \"writeonly\" qualifier.");
+          qualifier->writeonly = TRUE;
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        case GSK_SL_TOKEN_LAYOUT:
+          if (location != GSK_SL_QUALIFIER_GLOBAL)
+            gsk_sl_preprocessor_error (preproc, SYNTAX, "Only global variables can have layout qualifiers.");
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          token = gsk_sl_preprocessor_get (preproc);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
+            {
+              gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected opening \"(\" after layout specifier");
+              break;
+            }
+          gsk_sl_preprocessor_consume (preproc, NULL);
+
+          gsk_sl_qualifier_parse_layout (qualifier, preproc, scope);
+
+          token = gsk_sl_preprocessor_get (preproc);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+            {
+              gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \")\" at end of layout 
specifier");
+              gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_PAREN);
+            }
+          gsk_sl_preprocessor_consume (preproc, NULL);
+          break;
+
+        default:
+          goto out;
+      }
+    }
+
+out:
+  /* fixup storage qualifier */
+  switch (qualifier->storage)
+    {
+    case GSK_SL_STORAGE_DEFAULT:
+      if (location == GSK_SL_QUALIFIER_GLOBAL)
+        qualifier->storage = seen_const ? GSK_SL_STORAGE_GLOBAL_CONST : GSK_SL_STORAGE_GLOBAL;
+      else if (location == GSK_SL_QUALIFIER_LOCAL)
+        qualifier->storage = seen_const ? GSK_SL_STORAGE_LOCAL_CONST : GSK_SL_STORAGE_LOCAL;
+      else if (location == GSK_SL_QUALIFIER_PARAMETER)
+        qualifier->storage = seen_const ? GSK_SL_STORAGE_PARAMETER_CONST : GSK_SL_STORAGE_PARAMETER_IN;
+      else
+        {
+          g_assert_not_reached ();
+        }
+      break;
+
+    case GSK_SL_STORAGE_GLOBAL:
+      if (seen_const)
+        qualifier->storage = GSK_SL_STORAGE_GLOBAL_CONST;
+      break;
+
+    case GSK_SL_STORAGE_LOCAL:
+      if (seen_const)
+        qualifier->storage = GSK_SL_STORAGE_LOCAL_CONST;
+      break;
+
+    case GSK_SL_STORAGE_PARAMETER_IN:
+      if (seen_const)
+        qualifier->storage = GSK_SL_STORAGE_PARAMETER_CONST;
+      break;
+
+    case GSK_SL_STORAGE_GLOBAL_IN:
+    case GSK_SL_STORAGE_GLOBAL_OUT:
+    case GSK_SL_STORAGE_PARAMETER_OUT:
+    case GSK_SL_STORAGE_PARAMETER_INOUT:
+      g_assert (!seen_const);
+      break;
+
+    case GSK_SL_STORAGE_GLOBAL_CONST:
+    case GSK_SL_STORAGE_LOCAL_CONST:
+    case GSK_SL_STORAGE_PARAMETER_CONST:
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+static gboolean
+gsk_sl_qualifier_has_layout (const GskSlQualifier *qualifier)
+{
+  return qualifier->layout.set >= 0
+      || qualifier->layout.binding >= 0
+      || qualifier->layout.location >= 0
+      || qualifier->layout.component >= 0;
+}
+
+static gboolean
+print_qualifier (GskSlPrinter *printer,
+                 const char   *name,
+                 gint          value,
+                 gboolean      needs_comma)
+{
+  if (value < 0)
+    return needs_comma;
+
+  if (needs_comma)
+    gsk_sl_printer_append (printer, ", ");
+  gsk_sl_printer_append (printer, name);
+  gsk_sl_printer_append (printer, "=");
+  gsk_sl_printer_append_uint (printer, value);
+
+  return TRUE;
+}
+
+static gboolean
+append_with_space (GskSlPrinter *printer,
+                   const char   *s,
+                   gboolean      need_space)
+{
+  if (s[0] == '\0')
+    return need_space;
+
+  if (need_space)
+    gsk_sl_printer_append_c (printer, ' ');
+  gsk_sl_printer_append (printer, s);
+  return TRUE;
+}
+
+gboolean
+gsk_sl_qualifier_print (const GskSlQualifier *qualifier,
+                        GskSlPrinter         *printer)
+{
+  gboolean need_space = FALSE;
+
+  if (qualifier->invariant)
+    need_space = append_with_space (printer, "invariant ", need_space);
+  if (qualifier->volatile_)
+    need_space = append_with_space (printer, "volatile ", need_space);
+  if (qualifier->restrict_)
+    need_space = append_with_space (printer, "restrict ", need_space);
+  if (qualifier->coherent)
+    need_space = append_with_space (printer, "coherent ", need_space);
+  if (qualifier->readonly)
+    need_space = append_with_space (printer, "readonly ", need_space);
+  if (qualifier->writeonly)
+    need_space = append_with_space (printer, "writeonly ", need_space);
+
+  if (gsk_sl_qualifier_has_layout (qualifier))
+    {
+      gboolean had_value;
+      gsk_sl_printer_append (printer, "layout(");
+      had_value = print_qualifier (printer, "set", qualifier->layout.set, FALSE);
+      had_value = print_qualifier (printer, "binding", qualifier->layout.binding, had_value);
+      had_value = print_qualifier (printer, "location", qualifier->layout.location, had_value);
+      had_value = print_qualifier (printer, "component", qualifier->layout.component, had_value);
+      gsk_sl_printer_append (printer, ")");
+      need_space = TRUE;
+    }
+
+  need_space = append_with_space (printer, gsk_sl_storage_get_name (qualifier->storage), need_space);
+
+  return need_space;
+}
+
+gboolean
+gsk_sl_qualifier_is_constant (const GskSlQualifier *qualifier)
+{
+  switch (qualifier->storage)
+    {
+    case GSK_SL_STORAGE_DEFAULT:
+    default:
+      g_assert_not_reached ();
+      return TRUE;
+
+    case GSK_SL_STORAGE_GLOBAL_CONST:
+    case GSK_SL_STORAGE_LOCAL_CONST:
+    case GSK_SL_STORAGE_PARAMETER_CONST:
+      return TRUE;
+
+    case GSK_SL_STORAGE_GLOBAL:
+    case GSK_SL_STORAGE_GLOBAL_IN:
+    case GSK_SL_STORAGE_GLOBAL_OUT:
+    case GSK_SL_STORAGE_LOCAL:
+    case GSK_SL_STORAGE_PARAMETER_IN:
+    case GSK_SL_STORAGE_PARAMETER_OUT:
+    case GSK_SL_STORAGE_PARAMETER_INOUT:
+      return FALSE;
+    }
+}
+
+GskSpvStorageClass
+gsk_sl_qualifier_get_storage_class (const GskSlQualifier *qualifier)
+{
+  switch (qualifier->storage)
+    {
+    case GSK_SL_STORAGE_DEFAULT:
+    case GSK_SL_STORAGE_PARAMETER_IN:
+    case GSK_SL_STORAGE_PARAMETER_OUT:
+    case GSK_SL_STORAGE_PARAMETER_INOUT:
+    case GSK_SL_STORAGE_PARAMETER_CONST:
+    default:
+      g_assert_not_reached ();
+      return GSK_SPV_STORAGE_CLASS_FUNCTION;
+
+    case GSK_SL_STORAGE_GLOBAL:
+    case GSK_SL_STORAGE_GLOBAL_CONST:
+      return GSK_SPV_STORAGE_CLASS_PRIVATE;
+
+    case GSK_SL_STORAGE_GLOBAL_IN:
+      return GSK_SPV_STORAGE_CLASS_INPUT;
+
+    case GSK_SL_STORAGE_GLOBAL_OUT:
+      return GSK_SPV_STORAGE_CLASS_OUTPUT;
+
+    case GSK_SL_STORAGE_LOCAL:
+    case GSK_SL_STORAGE_LOCAL_CONST:
+      return GSK_SPV_STORAGE_CLASS_FUNCTION;
+    }
+}
diff --git a/gsk/gskslqualifierprivate.h b/gsk/gskslqualifierprivate.h
new file mode 100644
index 0000000..a11f08a
--- /dev/null
+++ b/gsk/gskslqualifierprivate.h
@@ -0,0 +1,86 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GSK_SL_QUALIFIER_PRIVATE_H__
+#define __GSK_SL_QUALIFIER_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+#include "gskslqualifierprivate.h"
+#include "gskspvwriterprivate.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GSK_SL_QUALIFIER_GLOBAL,
+  GSK_SL_QUALIFIER_PARAMETER,
+  GSK_SL_QUALIFIER_LOCAL
+} GskSlQualifierLocation;
+
+typedef enum {
+  GSK_SL_STORAGE_DEFAULT,
+
+  GSK_SL_STORAGE_GLOBAL,
+  GSK_SL_STORAGE_GLOBAL_CONST,
+  GSK_SL_STORAGE_GLOBAL_IN,
+  GSK_SL_STORAGE_GLOBAL_OUT,
+
+  GSK_SL_STORAGE_LOCAL,
+  GSK_SL_STORAGE_LOCAL_CONST,
+
+  GSK_SL_STORAGE_PARAMETER_IN,
+  GSK_SL_STORAGE_PARAMETER_OUT,
+  GSK_SL_STORAGE_PARAMETER_INOUT,
+  GSK_SL_STORAGE_PARAMETER_CONST
+} GskSlStorage;
+
+struct _GskSlQualifier
+{
+  GskSlStorage storage;
+
+  struct {
+    gint set;
+    gint binding;
+    gint location;
+    gint component;
+  } layout;
+
+  guint invariant :1;
+  guint volatile_ :1;
+  guint restrict_ :1;
+  guint coherent :1;
+  guint readonly :1;
+  guint writeonly :1;
+};
+
+void                    gsk_sl_qualifier_init                           (GskSlQualifier             
*qualifier);
+void                    gsk_sl_qualifier_parse                          (GskSlQualifier             
*qualifier,
+                                                                         GskSlScope                 *scope,
+                                                                         GskSlPreprocessor          *stream,
+                                                                         GskSlQualifierLocation      
location);
+
+gboolean                gsk_sl_qualifier_print                          (const GskSlQualifier       
*qualifier,
+                                                                         GskSlPrinter               
*printer);
+
+gboolean                gsk_sl_qualifier_is_constant                    (const GskSlQualifier       
*qualifier);
+GskSpvStorageClass      gsk_sl_qualifier_get_storage_class              (const GskSlQualifier       
*qualifier);
+
+G_END_DECLS
+
+#endif /* __GSK_SL_QUALIFIER_PRIVATE_H__ */
diff --git a/gsk/gskslstatement.c b/gsk/gskslstatement.c
index bc8f1e6..85687da 100644
--- a/gsk/gskslstatement.c
+++ b/gsk/gskslstatement.c
@@ -28,6 +28,7 @@
 #include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gskslvalueprivate.h"
 #include "gskslvariableprivate.h"
 #include "gskspvwriterprivate.h"
@@ -496,10 +497,10 @@ static const GskSlStatementClass GSK_SL_STATEMENT_EXPRESSION = {
 /* API */
 
 static GskSlStatement *
-gsk_sl_statement_parse_declaration (GskSlScope        *scope,
-                                    GskSlPreprocessor *stream,
-                                    GskSlDecorations  *decoration,
-                                    GskSlType         *type)
+gsk_sl_statement_parse_declaration (GskSlScope           *scope,
+                                    GskSlPreprocessor    *stream,
+                                    const GskSlQualifier *qualifier,
+                                    GskSlType            *type)
 {
   GskSlStatementDeclaration *declaration;
   GskSlPointerType *pointer_type;
@@ -548,8 +549,8 @@ gsk_sl_statement_parse_declaration (GskSlScope        *scope,
       value = NULL;
     }
 
-  pointer_type = gsk_sl_pointer_type_new (type, TRUE, 
decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-  declaration->variable = gsk_sl_variable_new (pointer_type, name, value, 
decoration->values[GSK_SL_DECORATION_CONST].set);
+  pointer_type = gsk_sl_pointer_type_new (type, qualifier);
+  declaration->variable = gsk_sl_variable_new (pointer_type, name, value);
   gsk_sl_pointer_type_unref (pointer_type);
   gsk_sl_scope_add_variable (scope, declaration->variable);
 
@@ -744,12 +745,10 @@ gsk_sl_statement_parse (GskSlScope        *scope,
     case GSK_SL_TOKEN_STRUCT:
       {
         GskSlType *type;
-        GskSlDecorations decoration;
+        GskSlQualifier qualifier;
 
 its_a_type:
-        gsk_sl_decoration_list_parse (scope,
-                                      preproc,
-                                      &decoration);
+        gsk_sl_qualifier_parse (&qualifier, scope, preproc, GSK_SL_QUALIFIER_LOCAL);
 
         type = gsk_sl_type_new_parse (scope, preproc);
 
@@ -778,7 +777,7 @@ its_a_type:
           }
         else
           {
-            statement = gsk_sl_statement_parse_declaration (scope, preproc, &decoration, type);
+            statement = gsk_sl_statement_parse_declaration (scope, preproc, &qualifier, type);
           }
 
         gsk_sl_type_unref (type);
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index c1c3329..ff379cc 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -28,6 +28,7 @@ typedef struct _GskSlNativeFunction     GskSlNativeFunction;
 typedef struct _GskSlPreprocessor       GskSlPreprocessor;
 typedef struct _GskSlPointerType        GskSlPointerType;
 typedef struct _GskSlPrinter            GskSlPrinter;
+typedef struct _GskSlQualifier          GskSlQualifier;
 typedef struct _GskSlScope              GskSlScope;
 typedef struct _GskSlStatement          GskSlStatement;
 typedef struct _GskSlToken              GskSlToken;
diff --git a/gsk/gskslvariable.c b/gsk/gskslvariable.c
index 5dc722f..fa7ca24 100644
--- a/gsk/gskslvariable.c
+++ b/gsk/gskslvariable.c
@@ -22,6 +22,7 @@
 
 #include "gskslpointertypeprivate.h"
 #include "gskslprinterprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gsksltypeprivate.h"
 #include "gskslvalueprivate.h"
 #include "gskspvwriterprivate.h"
@@ -32,14 +33,12 @@ struct _GskSlVariable {
   GskSlPointerType *type;
   char *name;
   GskSlValue *initial_value;
-  gboolean constant;
 };
 
 GskSlVariable *
 gsk_sl_variable_new (GskSlPointerType *type,
                      char             *name,
-                     GskSlValue       *initial_value,
-                     gboolean          constant)
+                     GskSlValue       *initial_value)
 {
   GskSlVariable *variable;
 
@@ -50,7 +49,6 @@ gsk_sl_variable_new (GskSlPointerType *type,
   variable->type = gsk_sl_pointer_type_ref (type);
   variable->name = name;
   variable->initial_value = initial_value;
-  variable->constant = constant;
 
   return variable;
 }
@@ -87,8 +85,6 @@ void
 gsk_sl_variable_print (const GskSlVariable *variable,
                        GskSlPrinter        *printer)
 {
-  if (variable->constant)
-    gsk_sl_printer_append (printer, "const ");
   gsk_sl_pointer_type_print (variable->type, printer);
   if (variable->name)
     {
@@ -118,7 +114,7 @@ gsk_sl_variable_get_initial_value (const GskSlVariable *variable)
 gboolean
 gsk_sl_variable_is_constant (const GskSlVariable *variable)
 {
-  return variable->constant;
+  return gsk_sl_qualifier_is_constant (gsk_sl_pointer_type_get_qualifier (variable->type));
 }
 
 guint32
@@ -138,7 +134,7 @@ gsk_sl_variable_write_spv (const GskSlVariable *variable,
                       variable->initial_value ? 5 : 4, GSK_SPV_OP_VARIABLE,
                       (guint32[4]) { pointer_type_id,
                                      variable_id,
-                                     gsk_sl_pointer_type_get_storage_class (variable->type),
+                                     gsk_sl_qualifier_get_storage_class (gsk_sl_pointer_type_get_qualifier 
(variable->type)),
                                      value_id });
 
   return variable_id;
diff --git a/gsk/gskslvariableprivate.h b/gsk/gskslvariableprivate.h
index cc24660..2c169ff 100644
--- a/gsk/gskslvariableprivate.h
+++ b/gsk/gskslvariableprivate.h
@@ -27,8 +27,7 @@ G_BEGIN_DECLS
 
 GskSlVariable *         gsk_sl_variable_new                     (GskSlPointerType       *type,
                                                                  char                   *name,
-                                                                 GskSlValue             *initial_value,
-                                                                 gboolean                constant);
+                                                                 GskSlValue             *initial_value);
 
 GskSlVariable *         gsk_sl_variable_ref                     (GskSlVariable          *variable);
 void                    gsk_sl_variable_unref                   (GskSlVariable          *variable);
diff --git a/gsk/meson.build b/gsk/meson.build
index 3e70a9f..fd3ffbe 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -41,6 +41,7 @@ gsk_private_sources = files([
   'gskslpreprocessor.c',
   'gskslpointertype.c',
   'gskslprinter.c',
+  'gskslqualifier.c',
   'gskslscope.c',
   'gskslstatement.c',
   'gsksltokenizer.c',


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