[gtk+/wip/otte/shader: 109/269] gskslnode: Add variables



commit 202470494a8a61095df408e3aca243dbddded8ad
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 17 02:15:32 2017 +0200

    gskslnode: Add variables
    
    This requires keeping a scope object that we can use to store and load
    variables.

 gsk/gskslnode.c         |  261 +++++++++++++++++++++++++++++++++++++++++------
 gsk/gskslscope.c        |  112 ++++++++++++++++++++
 gsk/gskslscopeprivate.h |   41 ++++++++
 gsk/gsksltypesprivate.h |    4 +-
 gsk/meson.build         |    1 +
 5 files changed, 388 insertions(+), 31 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 7fc6ed3..e53dd6b 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -21,6 +21,7 @@
 #include "gskslnodeprivate.h"
 
 #include "gskslpreprocessorprivate.h"
+#include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
 
@@ -48,6 +49,7 @@ typedef struct _GskSlNodeProgram GskSlNodeProgram;
 struct _GskSlNodeProgram {
   GskSlNode parent;
 
+  GskSlScope *scope;
   GSList *declarations;
   GSList *functions;
 };
@@ -59,6 +61,7 @@ gsk_sl_node_program_free (GskSlNode *node)
 
   g_slist_free (program->declarations);
   g_slist_free (program->functions);
+  gsk_sl_scope_unref (program->scope);
 
   g_slice_free (GskSlNodeProgram, program);
 }
@@ -103,6 +106,7 @@ typedef struct _GskSlNodeFunction GskSlNodeFunction;
 struct _GskSlNodeFunction {
   GskSlNode parent;
 
+  GskSlScope *scope;
   GskSlType *return_type;
   char *name;
   GSList *statements;
@@ -113,6 +117,8 @@ gsk_sl_node_function_free (GskSlNode *node)
 {
   GskSlNodeFunction *function = (GskSlNodeFunction *) node;
 
+  if (function->scope)
+    gsk_sl_scope_unref (function->scope);
   if (function->return_type)
     gsk_sl_type_unref (function->return_type);
   g_free (function->name);
@@ -263,6 +269,128 @@ static const GskSlNodeClass GSK_SL_NODE_ASSIGNMENT = {
   gsk_sl_node_assignment_is_constant
 };
 
+/* DECLARATION */
+
+typedef struct _GskSlNodeDeclaration GskSlNodeDeclaration;
+
+struct _GskSlNodeDeclaration {
+  GskSlNode parent;
+
+  char *name;
+  GskSlType *type;
+  GskSlNode *initial;
+  guint constant :1;
+};
+
+static void
+gsk_sl_node_declaration_free (GskSlNode *node)
+{
+  GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
+
+  g_free (declaration->name);
+  gsk_sl_type_unref (declaration->type);
+  if (declaration->initial)
+    gsk_sl_node_unref (declaration->initial);
+
+  g_slice_free (GskSlNodeDeclaration, declaration);
+}
+
+static void
+gsk_sl_node_declaration_print (GskSlNode *node,
+                               GString   *string)
+{
+  GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
+
+  gsk_sl_type_print (declaration->type, string);
+  if (declaration->name)
+    {
+      g_string_append (string, " ");
+      g_string_append (string, declaration->name);
+      if (declaration->initial)
+        {
+          g_string_append (string, " = ");
+          gsk_sl_node_print (declaration->initial, string);
+        }
+    }
+}
+
+static GskSlType *
+gsk_sl_node_declaration_get_return_type (GskSlNode *node)
+{
+  GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
+
+  return declaration->type;
+}
+
+static gboolean
+gsk_sl_node_declaration_is_constant (GskSlNode *node)
+{
+  GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
+
+  return declaration->constant;
+}
+
+static const GskSlNodeClass GSK_SL_NODE_DECLARATION = {
+  gsk_sl_node_declaration_free,
+  gsk_sl_node_declaration_print,
+  gsk_sl_node_declaration_get_return_type,
+  gsk_sl_node_declaration_is_constant
+};
+
+/* REFERENCE */
+
+typedef struct _GskSlNodeReference GskSlNodeReference;
+
+struct _GskSlNodeReference {
+  GskSlNode parent;
+
+  char *name;
+  GskSlNode *declaration;
+};
+
+static void
+gsk_sl_node_reference_free (GskSlNode *node)
+{
+  GskSlNodeReference *reference = (GskSlNodeReference *) node;
+
+  g_free (reference->name);
+  gsk_sl_node_unref (reference->declaration);
+
+  g_slice_free (GskSlNodeReference, reference);
+}
+
+static void
+gsk_sl_node_reference_print (GskSlNode *node,
+                             GString   *string)
+{
+  GskSlNodeReference *reference = (GskSlNodeReference *) node;
+
+  g_string_append (string, reference->name);
+}
+
+static GskSlType *
+gsk_sl_node_reference_get_return_type (GskSlNode *node)
+{
+  GskSlNodeReference *reference = (GskSlNodeReference *) node;
+
+  return gsk_sl_node_get_return_type (reference->declaration);
+}
+
+static gboolean
+gsk_sl_node_reference_is_constant (GskSlNode *node)
+{
+  GskSlNodeReference *reference = (GskSlNodeReference *) node;
+
+  return gsk_sl_node_is_constant (reference->declaration);
+}
+
+static const GskSlNodeClass GSK_SL_NODE_REFERENCE = {
+  gsk_sl_node_reference_free,
+  gsk_sl_node_reference_print,
+  gsk_sl_node_reference_get_return_type,
+  gsk_sl_node_reference_is_constant
+};
+
 /* CONSTANT */
 
 typedef struct _GskSlNodeConstant GskSlNodeConstant;
@@ -405,60 +533,88 @@ gsk_sl_node_parse_function_prototype (GskSlNodeProgram  *program,
 }
 
 static GskSlNode *
-gsk_sl_node_parse_constant (GskSlNodeProgram  *program,
-                            GskSlPreprocessor *stream)
+gsk_sl_node_parse_primary_expression (GskSlNodeProgram  *program,
+                                      GskSlScope        *scope,
+                                      GskSlPreprocessor *stream)
 {
   GskSlNodeConstant *constant;
   const GskSlToken *token;
 
-  constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
-
   token = gsk_sl_preprocessor_get (stream);
   switch ((guint) token->type)
   {
+    case GSK_SL_TOKEN_IDENTIFIER:
+      {
+        GskSlNodeReference *reference;
+        GskSlNode *decl;
+
+        decl = gsk_sl_scope_lookup_variable (scope, token->str);
+        if (decl == NULL)
+          {
+            gsk_sl_preprocessor_error (stream, "No variable named \"%s\".", token->str);
+            gsk_sl_preprocessor_consume (stream, (GskSlNode *) program);
+            return NULL;
+          }
+
+        reference = gsk_sl_node_new (GskSlNodeReference, &GSK_SL_NODE_REFERENCE);
+        reference->name = g_strdup (token->str);
+        reference->declaration = gsk_sl_node_ref (decl);
+        gsk_sl_preprocessor_consume (stream, (GskSlNode *) reference);
+        return (GskSlNode *) reference;
+      }
+
     case GSK_SL_TOKEN_INTCONSTANT:
+      constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
       constant->type = GSK_SL_INT;
       constant->i32 = token->i32;
-      break;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
+      return (GskSlNode *) constant;
 
     case GSK_SL_TOKEN_UINTCONSTANT:
+      constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
       constant->type = GSK_SL_UINT;
       constant->u32 = token->u32;
-      break;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
+      return (GskSlNode *) constant;
 
     case GSK_SL_TOKEN_FLOATCONSTANT:
+      constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
       constant->type = GSK_SL_FLOAT;
       constant->f = token->f;
-      break;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
+      return (GskSlNode *) constant;
 
     case GSK_SL_TOKEN_BOOLCONSTANT:
+      constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
       constant->type = GSK_SL_BOOL;
       constant->b = token->b;
-      break;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
+      return (GskSlNode *) constant;
 
     case GSK_SL_TOKEN_DOUBLECONSTANT:
+      constant = gsk_sl_node_new (GskSlNodeConstant, &GSK_SL_NODE_CONSTANT);
       constant->type = GSK_SL_DOUBLE;
       constant->d = token->d;
-      break;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
+      return (GskSlNode *) constant;
 
     default:
-      g_assert_not_reached ();
+      gsk_sl_preprocessor_error (stream, "Expected an expression.");
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) program);
       return NULL;
   }
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
-
-  return (GskSlNode *) constant;
 }
 
 static GskSlNode *
 gsk_sl_node_parse_assignment_expression (GskSlNodeProgram  *program,
+                                         GskSlScope        *scope,
                                          GskSlPreprocessor *stream)
 {
   const GskSlToken *token;
   GskSlNode *lvalue;
   GskSlNodeAssignment *assign;
 
-  lvalue = gsk_sl_node_parse_constant (program, stream);
+  lvalue = gsk_sl_node_parse_primary_expression (program, scope, stream);
   if (lvalue == NULL)
     return NULL;
 
@@ -490,7 +646,7 @@ gsk_sl_node_parse_assignment_expression (GskSlNodeProgram  *program,
       gsk_sl_preprocessor_consume (stream, lvalue);
       gsk_sl_node_unref (lvalue);
 
-      return gsk_sl_node_parse_assignment_expression (program, stream);
+      return gsk_sl_node_parse_assignment_expression (program, scope, stream);
     }
 
   assign = gsk_sl_node_new (GskSlNodeAssignment, &GSK_SL_NODE_ASSIGNMENT);
@@ -499,7 +655,7 @@ gsk_sl_node_parse_assignment_expression (GskSlNodeProgram  *program,
 
   gsk_sl_preprocessor_consume (stream, (GskSlNode *) assign);
 
-  assign->rvalue = gsk_sl_node_parse_assignment_expression (program, stream);
+  assign->rvalue = gsk_sl_node_parse_assignment_expression (program, scope, stream);
   if (assign->rvalue == NULL)
     {
       gsk_sl_node_unref ((GskSlNode *) assign);
@@ -511,10 +667,46 @@ gsk_sl_node_parse_assignment_expression (GskSlNodeProgram  *program,
 
 static GskSlNode *
 gsk_sl_node_parse_expression (GskSlNodeProgram  *program,
+                              GskSlScope        *scope,
                               GskSlPreprocessor *stream)
 {
   /* XXX: Allow comma here */
-  return gsk_sl_node_parse_assignment_expression (program, stream);
+  return gsk_sl_node_parse_assignment_expression (program, scope, stream);
+}
+
+static GskSlNode *
+gsk_sl_node_parse_declaration (GskSlNodeProgram  *program,
+                               GskSlScope        *scope,
+                               GskSlPreprocessor *stream)
+{
+  GskSlNodeDeclaration *declaration;
+  const GskSlToken *token;
+  GskSlType *type;
+
+  type = gsk_sl_type_new_parse (stream);
+  if (type == NULL)
+    return FALSE;
+
+  declaration = gsk_sl_node_new (GskSlNodeDeclaration, &GSK_SL_NODE_DECLARATION);
+  declaration->type = type;
+  
+  token = gsk_sl_preprocessor_get (stream);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+    return (GskSlNode *) declaration;
+
+  declaration->name = g_strdup (token->str);
+  gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
+
+  token = gsk_sl_preprocessor_get (stream);
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
+    {
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
+      declaration->initial = gsk_sl_node_parse_assignment_expression (program, scope, stream);
+    }
+
+  gsk_sl_scope_add_variable (scope, declaration->name, (GskSlNode *) declaration);
+
+  return (GskSlNode *) declaration;
 }
 
 static gboolean
@@ -546,6 +738,8 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram  *program,
     }
   gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
 
+  function->scope = gsk_sl_scope_new (program->scope);
+
   while (TRUE)
     {
       token = gsk_sl_preprocessor_get (stream);
@@ -562,23 +756,28 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram  *program,
       case GSK_SL_TOKEN_RIGHT_BRACE:
         goto out;
 
-      case GSK_SL_TOKEN_INTCONSTANT:
-      case GSK_SL_TOKEN_UINTCONSTANT:
-      case GSK_SL_TOKEN_FLOATCONSTANT:
-      case GSK_SL_TOKEN_BOOLCONSTANT:
-      case GSK_SL_TOKEN_DOUBLECONSTANT:
-      case GSK_SL_TOKEN_LEFT_PAREN:
-        node = gsk_sl_node_parse_expression (program, stream);
+      case GSK_SL_TOKEN_VOID:
+      case GSK_SL_TOKEN_FLOAT:
+      case GSK_SL_TOKEN_DOUBLE:
+      case GSK_SL_TOKEN_INT:
+      case GSK_SL_TOKEN_UINT:
+      case GSK_SL_TOKEN_BOOL:
+      case GSK_SL_TOKEN_VEC2:
+      case GSK_SL_TOKEN_VEC3:
+      case GSK_SL_TOKEN_VEC4:
+        node = gsk_sl_node_parse_declaration (program, function->scope, stream);
         if (node)
-          function->statements = g_slist_append (function->statements, node);
-        else
-          result = FALSE;
+          {
+            function->statements = g_slist_append (function->statements, node);
+          }
         break;
 
       default:
-        gsk_sl_preprocessor_error (stream, "Unexpected token in stream.");
-        gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-        result = FALSE;
+        node = gsk_sl_node_parse_expression (program, function->scope, stream);
+        if (node)
+          function->statements = g_slist_append (function->statements, node);
+        else
+          result = FALSE;
         break;
       }
     }
@@ -620,6 +819,8 @@ gsk_sl_node_new_program (GBytes  *source,
   GskSlNodeProgram *program;
 
   program = gsk_sl_node_new (GskSlNodeProgram, &GSK_SL_NODE_PROGRAM);
+  program->scope = gsk_sl_scope_new (NULL);
+
   stream = gsk_sl_preprocessor_new (source);
 
   gsk_sl_node_parse_program (program, stream);
diff --git a/gsk/gskslscope.c b/gsk/gskslscope.c
new file mode 100644
index 0000000..5f8af55
--- /dev/null
+++ b/gsk/gskslscope.c
@@ -0,0 +1,112 @@
+/* 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 "gskslscopeprivate.h"
+
+#include "gskslnodeprivate.h"
+
+#include <string.h>
+
+struct _GskSlScope
+{
+  int ref_count;
+
+  GskSlScope *parent;
+  GSList *children;
+  
+  GHashTable *variables;
+};
+
+GskSlScope *
+gsk_sl_scope_new (GskSlScope *parent)
+{
+  GskSlScope *scope;
+  
+  scope = g_slice_new0 (GskSlScope);
+  scope->ref_count = 1;
+
+  if (parent)
+    {
+      scope->parent = parent;
+      parent->children = g_slist_prepend (parent->children, scope);
+    }
+  scope->variables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) 
gsk_sl_node_unref);
+
+  return scope;
+}
+
+GskSlScope *
+gsk_sl_scope_ref (GskSlScope *scope)
+{
+  g_return_val_if_fail (scope != NULL, NULL);
+
+  scope->ref_count += 1;
+
+  return scope;
+}
+
+void
+gsk_sl_scope_unref (GskSlScope *scope)
+{
+  GSList *l;
+
+  if (scope == NULL)
+    return;
+
+  scope->ref_count -= 1;
+  if (scope->ref_count > 0)
+    return;
+
+  g_hash_table_unref (scope->variables);
+
+  if (scope->parent)
+    scope->parent->children = g_slist_remove (scope->parent->children, scope);
+  for (l = scope->children; l; l = l->next)
+    ((GskSlScope *) l->data)->parent = NULL;
+  g_slist_free (scope->children);
+
+  g_slice_free (GskSlScope, scope);
+}
+
+void
+gsk_sl_scope_add_variable (GskSlScope *scope,
+                           const char *name,
+                           GskSlNode  *declaration)
+{
+  g_hash_table_replace (scope->variables, (gpointer) name, gsk_sl_node_ref (declaration));
+}
+
+GskSlNode *
+gsk_sl_scope_lookup_variable (GskSlScope *scope,
+                              const char *name)
+{
+  GskSlNode *result;
+
+  for (;
+       scope != NULL;
+       scope = scope->parent)
+    {
+      result = g_hash_table_lookup (scope->variables, name);
+      if (result)
+        return result;
+    }
+
+  return NULL;
+}
diff --git a/gsk/gskslscopeprivate.h b/gsk/gskslscopeprivate.h
new file mode 100644
index 0000000..1c69848
--- /dev/null
+++ b/gsk/gskslscopeprivate.h
@@ -0,0 +1,41 @@
+/* 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_SCOPE_PRIVATE_H__
+#define __GSK_SL_SCOPE_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+
+G_BEGIN_DECLS
+
+GskSlScope *            gsk_sl_scope_new                        (GskSlScope           *parent);
+
+GskSlScope *            gsk_sl_scope_ref                        (GskSlScope           *scope);
+void                    gsk_sl_scope_unref                      (GskSlScope           *scope);
+
+void                    gsk_sl_scope_add_variable               (GskSlScope           *scope,
+                                                                 const char           *name,
+                                                                 GskSlNode            *declaration);
+GskSlNode *             gsk_sl_scope_lookup_variable            (GskSlScope           *scope,
+                                                                 const char           *name);
+
+G_END_DECLS
+
+#endif /* __GSK_SL_SCOPE_PRIVATE_H__ */
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index e4e0213..c5db6a5 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -1,5 +1,6 @@
 /* GSK - The GTK Scene Kit
- * Copyright 2016  Benjamin Otte
+ *   
+ * 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
@@ -22,6 +23,7 @@
 
 typedef struct _GskSlNode               GskSlNode;
 typedef struct _GskSlPreprocessor       GskSlPreprocessor;
+typedef struct _GskSlScope              GskSlScope;
 typedef struct _GskSlToken              GskSlToken;
 typedef struct _GskSlType               GskSlType;
 
diff --git a/gsk/meson.build b/gsk/meson.build
index d9ecbef..1a14a2d 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -34,6 +34,7 @@ gsk_private_sources = files([
   'gskshaderbuilder.c',
   'gskslnode.c',
   'gskslpreprocessor.c',
+  'gskslscope.c',
   'gsksltokenizer.c',
   'gsksltype.c'
 ])


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