[gtk+/wip/otte/shader: 10/12] gskslnode: Add builtin constructors



commit fc0912ba738eb022c34b91d977fc6124db68932f
Author: Benjamin Otte <otte redhat com>
Date:   Mon Sep 18 18:03:40 2017 +0200

    gskslnode: Add builtin constructors
    
    Do this by implementing function call nodes and adding GskSlFunction,
    which is meant to be used for anything that is callable.

 gsk/gskslfunction.c        |  192 ++++++++++++++++++++++++++++++++
 gsk/gskslfunctionprivate.h |   64 +++++++++++
 gsk/gskslnode.c            |  263 +++++++++++++++++++++++++++++++++++++++++---
 gsk/gsksltypesprivate.h    |    1 +
 gsk/meson.build            |    1 +
 5 files changed, 506 insertions(+), 15 deletions(-)
---
diff --git a/gsk/gskslfunction.c b/gsk/gskslfunction.c
new file mode 100644
index 0000000..d6eddb3
--- /dev/null
+++ b/gsk/gskslfunction.c
@@ -0,0 +1,192 @@
+/* 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 "gskslfunctionprivate.h"
+
+#include "gsksltypeprivate.h"
+
+static GskSlFunction *
+gsk_sl_function_alloc (const GskSlFunctionClass *klass,
+                       gsize                     size)
+{
+  GskSlFunction *function;
+
+  function = g_slice_alloc0 (size);
+
+  function->class = klass;
+  function->ref_count = 1;
+
+  return function;
+}
+#define gsk_sl_function_new(_name, _klass) ((_name *) gsk_sl_function_alloc ((_klass), sizeof (_name)))
+
+/* BUILTIN CONSTRUCTOR */
+
+typedef struct _GskSlFunctionBuiltinConstructor GskSlFunctionBuiltinConstructor;
+
+struct _GskSlFunctionBuiltinConstructor {
+  GskSlFunction parent;
+
+  GskSlType *type;
+};
+
+static void
+gsk_sl_function_builtin_constructor_free (GskSlFunction *function)
+{
+  GskSlFunctionBuiltinConstructor *builtin_constructor = (GskSlFunctionBuiltinConstructor *) function;
+
+  gsk_sl_type_unref (builtin_constructor->type);
+
+  g_slice_free (GskSlFunctionBuiltinConstructor, builtin_constructor);
+}
+
+static GskSlType *
+gsk_sl_function_builtin_constructor_get_return_type (GskSlFunction *function)
+{
+  GskSlFunctionBuiltinConstructor *builtin_constructor = (GskSlFunctionBuiltinConstructor *) function;
+
+  return builtin_constructor->type;
+}
+
+static void
+gsk_sl_function_builtin_constructor_print_name (GskSlFunction *function,
+                                                GString       *string)
+{
+  GskSlFunctionBuiltinConstructor *builtin_constructor = (GskSlFunctionBuiltinConstructor *) function;
+
+  gsk_sl_type_print (builtin_constructor->type, string);
+}
+
+
+static guint
+gsk_sl_function_builtin_get_args_by_type (const GskSlType *type)
+{
+  if (gsk_sl_type_is_scalar (type))
+    return 1;
+  else if (gsk_sl_type_is_vector (type))
+    return gsk_sl_type_get_length (type);
+  else if (gsk_sl_type_is_matrix (type))
+    return gsk_sl_type_get_length (type) * gsk_sl_function_builtin_get_args_by_type 
(gsk_sl_type_get_index_type (type));
+  else
+    return 0;
+}
+
+static gboolean
+gsk_sl_function_builtin_constructor_matches (GskSlFunction  *function,
+                                             GskSlType     **arguments,
+                                             gsize           n_arguments,
+                                             GError        **error)
+{
+  GskSlFunctionBuiltinConstructor *builtin_constructor = (GskSlFunctionBuiltinConstructor *) function;
+  guint needed, provided;
+  gsize i;
+
+  if (n_arguments == 1 && gsk_sl_type_is_scalar (arguments[0]))
+    return TRUE;
+
+  needed = gsk_sl_function_builtin_get_args_by_type (builtin_constructor->type);
+
+  for (i = 0; i < n_arguments; i++)
+    {
+      if (needed == 0)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Too many arguments given to constructor, 
only the first %"G_GSIZE_FORMAT" are necessary.", i);
+          return FALSE;
+        }
+
+      provided = gsk_sl_function_builtin_get_args_by_type (arguments[i]);
+      if (provided == 0)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Invalid type for constructor in argument 
%"G_GSIZE_FORMAT, i + 1);
+          return FALSE;
+        }
+
+      needed -= MIN (needed, provided);
+    }
+
+  return TRUE;
+}
+
+static const GskSlFunctionClass GSK_SL_FUNCTION_BUILTIN_CONSTRUCTOR = {
+  gsk_sl_function_builtin_constructor_free,
+  gsk_sl_function_builtin_constructor_get_return_type,
+  gsk_sl_function_builtin_constructor_print_name,
+  gsk_sl_function_builtin_constructor_matches,
+};
+
+/* API */
+
+GskSlFunction *
+gsk_sl_function_new_constructor (GskSlType *type)
+{
+  GskSlFunctionBuiltinConstructor *builtin_constructor;
+
+  builtin_constructor = gsk_sl_function_new (GskSlFunctionBuiltinConstructor, 
&GSK_SL_FUNCTION_BUILTIN_CONSTRUCTOR);
+
+  builtin_constructor->type = gsk_sl_type_ref (type);
+
+  return &builtin_constructor->parent;
+}
+
+GskSlFunction *
+gsk_sl_function_ref (GskSlFunction *function)
+{
+  g_return_val_if_fail (function != NULL, NULL);
+
+  function->ref_count += 1;
+
+  return function;
+}
+
+void
+gsk_sl_function_unref (GskSlFunction *function)
+{
+  if (function == NULL)
+    return;
+
+  function->ref_count -= 1;
+  if (function->ref_count > 0)
+    return;
+
+  function->class->free (function);
+}
+
+GskSlType *
+gsk_sl_function_get_return_type (GskSlFunction *function)
+{
+  return function->class->get_return_type (function);
+}
+
+void
+gsk_sl_function_print_name (GskSlFunction *function,
+                            GString       *string)
+{
+  function->class->print_name (function, string);
+}
+
+gboolean
+gsk_sl_function_matches (GskSlFunction  *function,
+                         GskSlType     **arguments,
+                         gsize           n_arguments,
+                         GError        **error)
+{
+  return function->class->matches (function, arguments, n_arguments, error);
+}
+
diff --git a/gsk/gskslfunctionprivate.h b/gsk/gskslfunctionprivate.h
new file mode 100644
index 0000000..7005fd9
--- /dev/null
+++ b/gsk/gskslfunctionprivate.h
@@ -0,0 +1,64 @@
+/* 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_FUNCTION_PRIVATE_H__
+#define __GSK_SL_FUNCTION_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskSlFunctionClass GskSlFunctionClass;
+
+struct _GskSlFunction
+{
+  const GskSlFunctionClass *class;
+
+  int ref_count;
+};
+
+struct _GskSlFunctionClass {
+  void                  (* free)                                (GskSlFunction  *function);
+
+  GskSlType *           (* get_return_type)                     (GskSlFunction  *function);
+  void                  (* print_name)                          (GskSlFunction  *function,
+                                                                 GString        *string);
+  gboolean              (* matches)                             (GskSlFunction  *function,
+                                                                 GskSlType     **arguments,
+                                                                 gsize           n_arguments,
+                                                                 GError        **error);
+};
+
+GskSlFunction *         gsk_sl_function_new_constructor         (GskSlType      *type);
+
+GskSlFunction *         gsk_sl_function_ref                     (GskSlFunction  *function);
+void                    gsk_sl_function_unref                   (GskSlFunction  *function);
+
+void                    gsk_sl_function_print_name              (GskSlFunction  *function,
+                                                                 GString        *string);
+GskSlType *             gsk_sl_function_get_return_type         (GskSlFunction  *function);
+gboolean                gsk_sl_function_matches                 (GskSlFunction  *function,
+                                                                 GskSlType     **arguments,
+                                                                 gsize           n_arguments,
+                                                                 GError        **error);
+
+G_END_DECLS
+
+#endif /* __GSK_SL_FUNCTION_PRIVATE_H__ */
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index f9b8ec0..8f8384d 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -20,6 +20,7 @@
 
 #include "gskslnodeprivate.h"
 
+#include "gskslfunctionprivate.h"
 #include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltokenstreamprivate.h"
@@ -77,7 +78,11 @@ gsk_sl_node_program_print (GskSlNode *node,
     gsk_sl_node_print (l->data, string);
 
   for (l = program->functions; l; l = l->next)
-    gsk_sl_node_print (l->data, string);
+    {
+      if (l != program->functions || program->declarations != NULL)
+        g_string_append (string, "\n");
+      gsk_sl_node_print (l->data, string);
+    }
 }
 
 static GskSlType *
@@ -832,6 +837,76 @@ static const GskSlNodeClass GSK_SL_NODE_REFERENCE = {
   gsk_sl_node_reference_is_constant
 };
 
+/* FUNCTION_CALL */
+
+typedef struct _GskSlNodeFunctionCall GskSlNodeFunctionCall;
+
+struct _GskSlNodeFunctionCall {
+  GskSlNode parent;
+
+  GskSlFunction *function;
+  GskSlNode **arguments;
+  guint n_arguments;
+};
+
+static void
+gsk_sl_node_function_call_free (GskSlNode *node)
+{
+  GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+  guint i;
+
+  for (i = 0; i < function_call->n_arguments; i++)
+    {
+      gsk_sl_node_unref (function_call->arguments[i]);
+    }
+  g_free (function_call->arguments);
+
+  gsk_sl_function_unref (function_call->function);
+
+  g_slice_free (GskSlNodeFunctionCall, function_call);
+}
+
+static void
+gsk_sl_node_function_call_print (GskSlNode *node,
+                                 GString   *string)
+{
+  GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+  guint i;
+
+  gsk_sl_function_print_name (function_call->function, string);
+  g_string_append (string, " (");
+  
+  for (i = 0; i < function_call->n_arguments; i++)
+    {
+      if (i > 0)
+        g_string_append (string, ", ");
+      gsk_sl_node_print (function_call->arguments[i], string);
+    }
+
+  g_string_append (string, ")");
+}
+
+static GskSlType *
+gsk_sl_node_function_call_get_return_type (GskSlNode *node)
+{
+  GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+
+  return gsk_sl_function_get_return_type (function_call->function);
+}
+
+static gboolean
+gsk_sl_node_function_call_is_constant (GskSlNode *node)
+{
+  return FALSE;
+}
+
+static const GskSlNodeClass GSK_SL_NODE_FUNCTION_CALL = {
+  gsk_sl_node_function_call_free,
+  gsk_sl_node_function_call_print,
+  gsk_sl_node_function_call_get_return_type,
+  gsk_sl_node_function_call_is_constant
+};
+
 /* CONSTANT */
 
 typedef struct _GskSlNodeConstant GskSlNodeConstant;
@@ -969,6 +1044,89 @@ gsk_sl_node_parse_function_prototype (GskSlNodeProgram *program,
 }
 
 static GskSlNode *
+gsk_sl_node_parse_assignment_expression (GskSlNodeProgram *program,
+                                         GskSlScope       *scope,
+                                         GskSlTokenStream *stream);
+
+static GskSlNode *
+gsk_sl_node_parse_constructor_call (GskSlNodeProgram *program,
+                                    GskSlScope       *scope,
+                                    GskSlTokenStream *stream,
+                                    GskSlType        *type)
+{
+  GskSlNodeFunctionCall *call;
+  const GskSlToken *token;
+  GskSlType **types;
+  GError *error = NULL;
+  gboolean fail = FALSE;
+  guint i;
+
+  call = gsk_sl_node_new (GskSlNodeFunctionCall, &GSK_SL_NODE_FUNCTION_CALL);
+  call->function = gsk_sl_function_new_constructor (type);
+  g_assert (call->function);
+
+  token = gsk_sl_token_stream_get (stream);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
+    {
+      gsk_sl_token_stream_error (stream, "Expected opening \"(\" when calling constructor");
+      gsk_sl_node_unref ((GskSlNode *) call);
+      return NULL;
+    }
+  gsk_sl_token_stream_consume (stream, (GskSlNode *) call);
+
+  token = gsk_sl_token_stream_get (stream);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+    {
+      GPtrArray *arguments;
+  
+      arguments = g_ptr_array_new ();
+      while (TRUE)
+        {
+          GskSlNode *node = gsk_sl_node_parse_assignment_expression (program, scope, stream);
+
+          if (node != NULL)
+            g_ptr_array_add (arguments, node);
+          else
+            fail = TRUE;
+          
+          token = gsk_sl_token_stream_get (stream);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA))
+            break;
+          gsk_sl_token_stream_consume (stream, (GskSlNode *) call);
+        }
+
+      call->n_arguments = arguments->len;
+      call->arguments = (GskSlNode **) g_ptr_array_free (arguments, FALSE);
+    }
+
+  types = g_newa (GskSlType *, call->n_arguments);
+  for (i = 0; i < call->n_arguments; i++)
+    types[i] = gsk_sl_node_get_return_type (call->arguments[i]);
+  if (!gsk_sl_function_matches (call->function, types, call->n_arguments, &error))
+    {
+      gsk_sl_token_stream_error (stream, "%s", error->message);
+      g_clear_error (&error);
+      fail = TRUE;
+    }
+
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+    {
+      gsk_sl_token_stream_error (stream, "Expected closing \")\" after arguments.");
+      gsk_sl_node_unref ((GskSlNode *) call);
+      return NULL;
+    }
+  gsk_sl_token_stream_consume (stream, (GskSlNode *) call);
+
+  if (fail)
+    {
+      gsk_sl_node_unref ((GskSlNode *) call);
+      return NULL;
+    }
+
+  return (GskSlNode *) call;
+}
+
+static GskSlNode *
 gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
                                       GskSlScope       *scope,
                                       GskSlTokenStream *stream)
@@ -1034,6 +1192,61 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
       gsk_sl_token_stream_consume (stream, (GskSlNode *) constant);
       return (GskSlNode *) constant;
 
+    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_BVEC2:
+    case GSK_SL_TOKEN_BVEC3:
+    case GSK_SL_TOKEN_BVEC4:
+    case GSK_SL_TOKEN_IVEC2:
+    case GSK_SL_TOKEN_IVEC3:
+    case GSK_SL_TOKEN_IVEC4:
+    case GSK_SL_TOKEN_UVEC2:
+    case GSK_SL_TOKEN_UVEC3:
+    case GSK_SL_TOKEN_UVEC4:
+    case GSK_SL_TOKEN_VEC2:
+    case GSK_SL_TOKEN_VEC3:
+    case GSK_SL_TOKEN_VEC4:
+    case GSK_SL_TOKEN_DVEC2:
+    case GSK_SL_TOKEN_DVEC3:
+    case GSK_SL_TOKEN_DVEC4:
+    case GSK_SL_TOKEN_MAT2:
+    case GSK_SL_TOKEN_MAT3:
+    case GSK_SL_TOKEN_MAT4:
+    case GSK_SL_TOKEN_DMAT2:
+    case GSK_SL_TOKEN_DMAT3:
+    case GSK_SL_TOKEN_DMAT4:
+    case GSK_SL_TOKEN_MAT2X2:
+    case GSK_SL_TOKEN_MAT2X3:
+    case GSK_SL_TOKEN_MAT2X4:
+    case GSK_SL_TOKEN_MAT3X2:
+    case GSK_SL_TOKEN_MAT3X3:
+    case GSK_SL_TOKEN_MAT3X4:
+    case GSK_SL_TOKEN_MAT4X2:
+    case GSK_SL_TOKEN_MAT4X3:
+    case GSK_SL_TOKEN_MAT4X4:
+    case GSK_SL_TOKEN_DMAT2X2:
+    case GSK_SL_TOKEN_DMAT2X3:
+    case GSK_SL_TOKEN_DMAT2X4:
+    case GSK_SL_TOKEN_DMAT3X2:
+    case GSK_SL_TOKEN_DMAT3X3:
+    case GSK_SL_TOKEN_DMAT3X4:
+    case GSK_SL_TOKEN_DMAT4X2:
+    case GSK_SL_TOKEN_DMAT4X3:
+    case GSK_SL_TOKEN_DMAT4X4:
+      {
+        GskSlType *type;
+
+        type = gsk_sl_type_new_parse (stream);
+        if (type == NULL)
+          return NULL;
+
+        return gsk_sl_node_parse_constructor_call (program, scope, stream, type);
+      }
+
     default:
       gsk_sl_token_stream_error (stream, "Expected an expression.");
       gsk_sl_token_stream_consume (stream, (GskSlNode *) program);
@@ -1042,11 +1255,19 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
 }
 
 static GskSlNode *
+gsk_sl_node_parse_postfix_expression (GskSlNodeProgram *program,
+                                      GskSlScope       *scope,
+                                      GskSlTokenStream *stream)
+{
+  return gsk_sl_node_parse_primary_expression (program, scope, stream);
+}
+
+static GskSlNode *
 gsk_sl_node_parse_unary_expression (GskSlNodeProgram *program,
                                     GskSlScope       *scope,
                                     GskSlTokenStream *stream)
 {
-  return gsk_sl_node_parse_primary_expression (program, scope, stream);
+  return gsk_sl_node_parse_postfix_expression (program, scope, stream);
 }
 
 static GskSlNode *
@@ -1692,18 +1913,14 @@ gsk_sl_node_parse_expression (GskSlNodeProgram *program,
 static GskSlNode *
 gsk_sl_node_parse_declaration (GskSlNodeProgram *program,
                                GskSlScope       *scope,
-                               GskSlTokenStream *stream)
+                               GskSlTokenStream *stream,
+                               GskSlType        *type)
 {
   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;
+  declaration->type = gsk_sl_type_ref (type);
   
   token = gsk_sl_token_stream_get (stream);
   if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
@@ -1816,11 +2033,27 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram *program,
       case GSK_SL_TOKEN_DMAT4X2:
       case GSK_SL_TOKEN_DMAT4X3:
       case GSK_SL_TOKEN_DMAT4X4:
-        node = gsk_sl_node_parse_declaration (program, function->scope, stream);
-        if (node)
-          {
-            function->statements = g_slist_append (function->statements, node);
-          }
+        {
+          GskSlType *type;
+
+          type = gsk_sl_type_new_parse (stream);
+          if (type == NULL)
+            return FALSE;
+
+          token = gsk_sl_token_stream_get (stream);
+
+          if (token->type == GSK_SL_TOKEN_LEFT_BRACE)
+            node = gsk_sl_node_parse_constructor_call (program, function->scope, stream, type);
+          else
+            node = gsk_sl_node_parse_declaration (program, function->scope, stream, type);
+
+          gsk_sl_type_unref (type);
+
+          if (node)
+            {
+              function->statements = g_slist_append (function->statements, node);
+            }
+        }
         break;
 
       default:
@@ -1836,7 +2069,7 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram *program,
 out:
   gsk_sl_token_stream_consume (stream, (GskSlNode *) function);
 
-  program->functions = g_slist_prepend (program->functions, function);
+  program->functions = g_slist_append (program->functions, function);
   return result;
 }
 
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index ced42a1..c0b7489 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -21,6 +21,7 @@
 
 #include <gsk/gsktypes.h>
 
+typedef struct _GskSlFunction           GskSlFunction;
 typedef struct _GskSlNode               GskSlNode;
 typedef struct _GskSlScope              GskSlScope;
 typedef struct _GskSlToken              GskSlToken;
diff --git a/gsk/meson.build b/gsk/meson.build
index 659cec9..f874f10 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -32,6 +32,7 @@ gsk_private_sources = files([
   'gskprivate.c',
   'gskprofiler.c',
   'gskshaderbuilder.c',
+  'gskslfunction.c',
   'gskslnode.c',
   'gskslscope.c',
   'gsksltokenizer.c',


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