[gtk+/wip/otte/shader: 15/38] gsksl: Turn functions into functions



commit 2e79a0b034485680c166fac60b991f2a00d0c776
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 24 23:13:54 2017 +0200

    gsksl: Turn functions into functions
    
    Don't use a GskSlNode subclass to handle declared functions but make
    them a GskSlFunction subclass.

 gsk/gskslfunction.c        |  287 ++++++++++++++++++++++--
 gsk/gskslfunctionprivate.h |   47 +++--
 gsk/gskslnode.c            |  551 +++++++++++++++++---------------------------
 gsk/gskslnodeprivate.h     |    2 +-
 gsk/gskslprogram.c         |   63 ++++--
 gsk/gskslscope.c           |   15 ++-
 gsk/gskslscopeprivate.h    |    5 +-
 7 files changed, 579 insertions(+), 391 deletions(-)
---
diff --git a/gsk/gskslfunction.c b/gsk/gskslfunction.c
index bbff985..fbcaa17 100644
--- a/gsk/gskslfunction.c
+++ b/gsk/gskslfunction.c
@@ -20,7 +20,12 @@
 
 #include "gskslfunctionprivate.h"
 
+#include "gskslnodeprivate.h"
+#include "gskslpreprocessorprivate.h"
+#include "gskslscopeprivate.h"
+#include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
+#include "gskspvwriterprivate.h"
 
 static GskSlFunction *
 gsk_sl_function_alloc (const GskSlFunctionClass *klass,
@@ -58,22 +63,27 @@ gsk_sl_function_constructor_free (GskSlFunction *function)
 }
 
 static GskSlType *
-gsk_sl_function_constructor_get_return_type (GskSlFunction *function)
+gsk_sl_function_constructor_get_return_type (const GskSlFunction *function)
 {
-  GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+  const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function;
 
   return constructor->type;
 }
 
 static void
-gsk_sl_function_constructor_print_name (GskSlFunction *function,
-                                                GString       *string)
+gsk_sl_function_constructor_print_name (const GskSlFunction *function,
+                                        GString             *string)
 {
-  GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+  const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function;
 
   g_string_append (string, gsk_sl_type_get_name (constructor->type));
 }
 
+static void
+gsk_sl_function_constructor_print (const GskSlFunction *function,
+                                   GString             *string)
+{
+}
 
 static guint
 gsk_sl_function_builtin_get_args_by_type (const GskSlType *type)
@@ -89,12 +99,12 @@ gsk_sl_function_builtin_get_args_by_type (const GskSlType *type)
 }
 
 static gboolean
-gsk_sl_function_constructor_matches (GskSlFunction  *function,
-                                             GskSlType     **arguments,
-                                             gsize           n_arguments,
-                                             GError        **error)
+gsk_sl_function_constructor_matches (const GskSlFunction  *function,
+                                     GskSlType           **arguments,
+                                     gsize                 n_arguments,
+                                     GError              **error)
 {
-  GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+  const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function;
   guint needed, provided;
   gsize i;
 
@@ -127,11 +137,161 @@ gsk_sl_function_constructor_matches (GskSlFunction  *function,
   return TRUE;
 }
 
+static guint32
+gsk_sl_function_constructor_write_spv (const GskSlFunction *function,
+                                       GskSpvWriter        *writer)
+{
+  return 0;
+}
+
 static const GskSlFunctionClass GSK_SL_FUNCTION_CONSTRUCTOR = {
   gsk_sl_function_constructor_free,
   gsk_sl_function_constructor_get_return_type,
   gsk_sl_function_constructor_print_name,
+  gsk_sl_function_constructor_print,
   gsk_sl_function_constructor_matches,
+  gsk_sl_function_constructor_write_spv,
+};
+
+/* DECLARED */
+
+typedef struct _GskSlFunctionDeclared GskSlFunctionDeclared;
+
+struct _GskSlFunctionDeclared {
+  GskSlFunction parent;
+
+  GskSlScope *scope;
+  GskSlType *return_type;
+  char *name;
+  GSList *statements;
+};
+
+static void
+gsk_sl_function_declared_free (GskSlFunction *function)
+{
+  GskSlFunctionDeclared *declared = (GskSlFunctionDeclared *) function;
+
+  if (declared->scope)
+    gsk_sl_scope_unref (declared->scope);
+  if (declared->return_type)
+    gsk_sl_type_unref (declared->return_type);
+  g_free (declared->name);
+  g_slist_free_full (declared->statements, (GDestroyNotify) gsk_sl_node_unref);
+
+  g_slice_free (GskSlFunctionDeclared, declared);
+}
+
+static GskSlType *
+gsk_sl_function_declared_get_return_type (const GskSlFunction *function)
+{
+  const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function;
+
+  return declared->return_type;
+}
+
+static void
+gsk_sl_function_declared_print_name (const GskSlFunction *function,
+                                     GString             *string)
+{
+  const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function;
+
+  g_string_append (string, declared->name);
+}
+
+static void
+gsk_sl_function_declared_print (const GskSlFunction *function,
+                                GString             *string)
+{
+  const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function;
+  GSList *l;
+
+  g_string_append (string, gsk_sl_type_get_name (declared->return_type));
+  g_string_append (string, "\n");
+
+  g_string_append (string, declared->name);
+  g_string_append (string, " (");
+  g_string_append (string, ")\n");
+
+  g_string_append (string, "{\n");
+  for (l = declared->statements; l; l = l->next)
+    {
+      g_string_append (string, "  ");
+      gsk_sl_node_print (l->data, string);
+      g_string_append (string, ";\n");
+    }
+  g_string_append (string, "}\n");
+}
+
+static gboolean
+gsk_sl_function_declared_matches (const GskSlFunction  *function,
+                                  GskSlType           **arguments,
+                                  gsize                 n_arguments,
+                                  GError              **error)
+{
+  if (n_arguments > 0)
+    {
+       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Function only takes %u arguments.", 0);
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static guint32
+gsk_sl_function_declared_write_spv (const GskSlFunction *function,
+                                    GskSpvWriter        *writer)
+{
+  GskSlFunctionDeclared *declared = (GskSlFunctionDeclared *) function;
+  guint32 return_type_id, function_type_id, function_id, label_id;
+  GSList *l;
+
+  /* declare type of function */
+  return_type_id = gsk_spv_writer_get_id_for_type (writer, declared->return_type);
+  function_type_id = gsk_spv_writer_next_id (writer);
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_DECLARE,
+                      3, GSK_SPV_OP_TYPE_FUNCTION,
+                      (guint32[2]) { function_type_id,
+                                     return_type_id });
+
+  /* add debug info */
+  /* FIXME */
+
+  /* add function body */
+  function_id = gsk_spv_writer_next_id (writer);
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_CODE,
+                      5, GSK_SPV_OP_FUNCTION,
+                      (guint32[4]) { return_type_id,
+                                     function_id,
+                                     0,
+                                     function_type_id });
+  label_id = gsk_spv_writer_next_id (writer);
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_CODE,
+                      2, GSK_SPV_OP_LABEL,
+                      (guint32[4]) { label_id });
+
+  for (l = declared->statements; l; l = l->next)
+    {
+      gsk_sl_node_write_spv (l->data, writer);
+    }
+
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_CODE,
+                      1, GSK_SPV_OP_FUNCTION_END,
+                      NULL);
+
+  return function_id;
+}
+
+static const GskSlFunctionClass GSK_SL_FUNCTION_DECLARED = {
+  gsk_sl_function_declared_free,
+  gsk_sl_function_declared_get_return_type,
+  gsk_sl_function_declared_print_name,
+  gsk_sl_function_declared_print,
+  gsk_sl_function_declared_matches,
+  gsk_sl_function_declared_write_spv,
 };
 
 /* API */
@@ -149,6 +309,85 @@ gsk_sl_function_new_constructor (GskSlType *type)
 }
 
 GskSlFunction *
+gsk_sl_function_new_parse (GskSlScope        *scope,
+                           GskSlPreprocessor *preproc,
+                           GskSlType         *return_type,
+                           const char        *name)
+{
+  GskSlFunctionDeclared *function;
+  const GskSlToken *token;
+  gboolean success = TRUE;
+
+  function = gsk_sl_function_new (GskSlFunctionDeclared, &GSK_SL_FUNCTION_DECLARED);
+  function->return_type = gsk_sl_type_ref (return_type);
+  function->name = g_strdup (name);
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
+    {
+      gsk_sl_preprocessor_error (preproc, "Expected an openening \"(\"");
+      gsk_sl_function_unref ((GskSlFunction *) function);
+      return NULL;
+    }
+  gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function);
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+    {
+      gsk_sl_preprocessor_error (preproc, "Expected a closing \")\"");
+      gsk_sl_function_unref ((GskSlFunction *) function);
+      return NULL;
+    }
+  gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function);
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
+    {
+      gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function);
+      return (GskSlFunction *) function;
+    }
+
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE))
+    {
+      gsk_sl_preprocessor_error (preproc, "Expected an opening \"{\"");
+      gsk_sl_function_unref ((GskSlFunction *) function);
+      return NULL;
+    }
+  gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function);
+
+  function->scope = gsk_sl_scope_new (scope, function->return_type);
+
+  for (token = gsk_sl_preprocessor_get (preproc);
+       !gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE) && !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF);
+       token = gsk_sl_preprocessor_get (preproc))
+    {
+      GskSlNode *statement;
+
+      statement = gsk_sl_node_parse_statement (function->scope, preproc);
+      if (statement)
+        function->statements = g_slist_append (function->statements, statement);
+      else
+        success = FALSE;
+    }
+
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE))
+    {
+      gsk_sl_preprocessor_error (preproc, "Missing closing \"}\" at end.");
+      gsk_sl_function_unref ((GskSlFunction *) function);
+      return NULL;
+    }
+  gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function);
+
+  if (!success)
+    {
+      gsk_sl_function_unref ((GskSlFunction *) function);
+      return NULL;
+    }
+
+  return (GskSlFunction *) function;
+}
+
+GskSlFunction *
 gsk_sl_function_ref (GskSlFunction *function)
 {
   g_return_val_if_fail (function != NULL, NULL);
@@ -172,24 +411,38 @@ gsk_sl_function_unref (GskSlFunction *function)
 }
 
 GskSlType *
-gsk_sl_function_get_return_type (GskSlFunction *function)
+gsk_sl_function_get_return_type (const GskSlFunction *function)
 {
   return function->class->get_return_type (function);
 }
 
 void
-gsk_sl_function_print_name (GskSlFunction *function,
-                            GString       *string)
+gsk_sl_function_print_name (const GskSlFunction *function,
+                            GString             *string)
 {
   function->class->print_name (function, string);
 }
 
+void
+gsk_sl_function_print (const GskSlFunction *function,
+                       GString             *string)
+{
+  function->class->print (function, string);
+}
+
 gboolean
-gsk_sl_function_matches (GskSlFunction  *function,
-                         GskSlType     **arguments,
-                         gsize           n_arguments,
-                         GError        **error)
+gsk_sl_function_matches (const GskSlFunction  *function,
+                         GskSlType           **arguments,
+                         gsize                 n_arguments,
+                         GError              **error)
 {
   return function->class->matches (function, arguments, n_arguments, error);
 }
 
+guint32
+gsk_sl_function_write_spv (const GskSlFunction *function,
+                           GskSpvWriter        *writer)
+{
+  return function->class->write_spv (function, writer);
+}
+
diff --git a/gsk/gskslfunctionprivate.h b/gsk/gskslfunctionprivate.h
index 7005fd9..99967cb 100644
--- a/gsk/gskslfunctionprivate.h
+++ b/gsk/gskslfunctionprivate.h
@@ -37,27 +37,40 @@ struct _GskSlFunction
 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);
+  GskSlType *           (* get_return_type)                     (const GskSlFunction    *function);
+  void                  (* print_name)                          (const GskSlFunction    *function,
+                                                                 GString                *string);
+  void                  (* print)                               (const GskSlFunction    *function,
+                                                                 GString                *string);
+  gboolean              (* matches)                             (const GskSlFunction    *function,
+                                                                 GskSlType             **arguments,
+                                                                 gsize                   n_arguments,
+                                                                 GError                **error);
+  guint32               (* write_spv)                           (const GskSlFunction    *function,
+                                                                 GskSpvWriter           *writer);
 };
 
-GskSlFunction *         gsk_sl_function_new_constructor         (GskSlType      *type);
+GskSlFunction *         gsk_sl_function_new_constructor         (GskSlType              *type);
+GskSlFunction *         gsk_sl_function_new_parse               (GskSlScope             *scope,
+                                                                 GskSlPreprocessor      *stream,
+                                                                 GskSlType              *return_type,
+                                                                 const char             *name);
 
-GskSlFunction *         gsk_sl_function_ref                     (GskSlFunction  *function);
-void                    gsk_sl_function_unref                   (GskSlFunction  *function);
+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);
+void                    gsk_sl_function_print                   (const GskSlFunction    *function,
+                                                                 GString                *string);
+
+void                    gsk_sl_function_print_name              (const GskSlFunction    *function,
+                                                                 GString                *string);
+GskSlType *             gsk_sl_function_get_return_type         (const GskSlFunction    *function);
+gboolean                gsk_sl_function_matches                 (const GskSlFunction    *function,
+                                                                 GskSlType             **arguments,
+                                                                 gsize                   n_arguments,
+                                                                 GError                **error);
+guint32                 gsk_sl_function_write_spv               (const GskSlFunction    *function,
+                                                                 GskSpvWriter           *writer);
 
 G_END_DECLS
 
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 17e029a..675ada9 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -47,109 +47,42 @@ gsk_sl_node_alloc (const GskSlNodeClass *klass,
 }
 #define gsk_sl_node_new(_name, _klass) ((_name *) gsk_sl_node_alloc ((_klass), sizeof (_name)))
 
-/* FUNCTION */
+/* EMPTY */
 
-typedef struct _GskSlNodeFunction GskSlNodeFunction;
+/* FIXME: This exists only so we dont return NULL from empty statements (ie just a semicolon)
+ */
 
-struct _GskSlNodeFunction {
-  GskSlNode parent;
+typedef struct _GskSlNodeEmpty GskSlNodeEmpty;
 
-  GskSlScope *scope;
-  GskSlType *return_type;
-  char *name;
-  GSList *statements;
+struct _GskSlNodeEmpty {
+  GskSlNode parent;
 };
 
 static void
-gsk_sl_node_function_free (GskSlNode *node)
+gsk_sl_node_empty_free (GskSlNode *node)
 {
-  GskSlNodeFunction *function = (GskSlNodeFunction *) node;
+  GskSlNodeEmpty *empty = (GskSlNodeEmpty *) 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);
-  g_slist_free_full (function->statements, (GDestroyNotify) gsk_sl_node_unref);
-
-  g_slice_free (GskSlNodeFunction, function);
+  g_slice_free (GskSlNodeEmpty, empty);
 }
 
 static void
-gsk_sl_node_function_print (GskSlNode *node,
-                            GString   *string)
+gsk_sl_node_empty_print (GskSlNode *node,
+                         GString   *string)
 {
-  GskSlNodeFunction *function = (GskSlNodeFunction *) node;
-  GSList *l;
-
-  g_string_append (string, gsk_sl_type_get_name (function->return_type));
-  g_string_append (string, "\n");
-
-  g_string_append (string, function->name);
-  g_string_append (string, " (");
-  g_string_append (string, ")\n");
-
-  g_string_append (string, "{\n");
-  for (l = function->statements; l; l = l->next)
-    {
-      g_string_append (string, "  ");
-      gsk_sl_node_print (l->data, string);
-      g_string_append (string, ";\n");
-    }
-  g_string_append (string, "}\n");
 }
 
 static guint32
-gsk_sl_node_function_write_spv (const GskSlNode *node,
-                                GskSpvWriter    *writer)
+gsk_sl_node_empty_write_spv (const GskSlNode *node,
+                             GskSpvWriter    *writer)
 {
-  GskSlNodeFunction *function = (GskSlNodeFunction *) node;
-  guint32 return_type_id, function_type_id, function_id, label_id;
-  GSList *l;
-
-  /* declare type of function */
-  return_type_id = gsk_spv_writer_get_id_for_type (writer, function->return_type);
-  function_type_id = gsk_spv_writer_next_id (writer);
-  gsk_spv_writer_add (writer,
-                      GSK_SPV_WRITER_SECTION_DECLARE,
-                      3, GSK_SPV_OP_TYPE_FUNCTION,
-                      (guint32[2]) { function_type_id,
-                                     return_type_id });
-
-  /* add debug info */
-  /* FIXME */
-
-  /* add function body */
-  function_id = gsk_spv_writer_next_id (writer);
-  gsk_spv_writer_add (writer,
-                      GSK_SPV_WRITER_SECTION_CODE,
-                      5, GSK_SPV_OP_FUNCTION,
-                      (guint32[4]) { return_type_id,
-                                     function_id,
-                                     0,
-                                     function_type_id });
-  label_id = gsk_spv_writer_next_id (writer);
-  gsk_spv_writer_add (writer,
-                      GSK_SPV_WRITER_SECTION_CODE,
-                      2, GSK_SPV_OP_LABEL,
-                      (guint32[4]) { label_id });
-
-  for (l = function->statements; l; l = l->next)
-    {
-      gsk_sl_node_write_spv (l->data, writer);
-    }
-
-  gsk_spv_writer_add (writer,
-                      GSK_SPV_WRITER_SECTION_CODE,
-                      1, GSK_SPV_OP_FUNCTION_END,
-                      NULL);
-  return function_id;
+  return 0;
 }
 
-static const GskSlNodeClass GSK_SL_NODE_FUNCTION = {
-  gsk_sl_node_function_free,
-  gsk_sl_node_function_print,
-  gsk_sl_node_function_write_spv
+static const GskSlNodeClass GSK_SL_NODE_EMPTY = {
+  gsk_sl_node_empty_free,
+  gsk_sl_node_empty_print,
+  gsk_sl_node_empty_write_spv
 };
 
 /* DECLARATION */
@@ -312,52 +245,6 @@ static const GskSlNodeClass GSK_SL_NODE_EXPRESSION = {
 
 /* API */
 
-static GskSlNodeFunction *
-gsk_sl_node_parse_function_prototype (GskSlScope        *scope,
-                                      GskSlPreprocessor *stream)
-{
-  GskSlType *type;
-  GskSlNodeFunction *function;
-  const GskSlToken *token;
-
-  type = gsk_sl_type_new_parse (stream);
-  if (type == NULL)
-    return NULL;
-
-  token = gsk_sl_preprocessor_get (stream);
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
-    {
-      gsk_sl_preprocessor_error (stream, "Expected a function name");
-      gsk_sl_type_unref (type);
-      return NULL;
-    }
-
-  function = gsk_sl_node_new (GskSlNodeFunction, &GSK_SL_NODE_FUNCTION);
-  function->return_type = type;
-  function->name = g_strdup (token->str);
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-
-  token = gsk_sl_preprocessor_get (stream);
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
-    {
-      gsk_sl_preprocessor_error (stream, "Expected an openening \"(\"");
-      gsk_sl_node_unref ((GskSlNode *) function);
-      return NULL;
-    }
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-
-  token = gsk_sl_preprocessor_get (stream);
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
-    {
-      gsk_sl_preprocessor_error (stream, "Expected a closing \")\"");
-      gsk_sl_node_unref ((GskSlNode *) function);
-      return NULL;
-    }
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-
-  return function;
-}
-
 static GskSlNode *
 gsk_sl_node_parse_declaration (GskSlScope        *scope,
                                GskSlPreprocessor *stream,
@@ -391,239 +278,225 @@ gsk_sl_node_parse_declaration (GskSlScope        *scope,
 }
 
 GskSlNode *
-gsk_sl_node_parse_function_definition (GskSlScope        *scope,
-                                       GskSlPreprocessor *stream)
+gsk_sl_node_parse_statement (GskSlScope        *scope,
+                             GskSlPreprocessor *preproc)
 {
-  GskSlNodeFunction *function;
   const GskSlToken *token;
-  gboolean result = TRUE;
+  GskSlNode *node;
 
-  function = gsk_sl_node_parse_function_prototype (scope, stream);
-  if (function == NULL)
-    return FALSE;
+  token = gsk_sl_preprocessor_get (preproc);
 
-  token = gsk_sl_preprocessor_get (stream);
-  if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
-    {
-      gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-      return (GskSlNode *) function;
-    }
+  switch (token->type)
+  {
+    case GSK_SL_TOKEN_SEMICOLON:
+      node = (GskSlNode *) gsk_sl_node_new (GskSlNodeEmpty, &GSK_SL_NODE_EMPTY);
+      break;
 
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE))
-    {
-      gsk_sl_preprocessor_error (stream, "Expected an opening \"{\"");
-      gsk_sl_node_unref ((GskSlNode *) function);
+    case GSK_SL_TOKEN_EOF:
+      gsk_sl_preprocessor_error (preproc, "Unexpected end of document");
       return NULL;
-    }
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-
-  function->scope = gsk_sl_scope_new (scope);
 
-  while (TRUE)
-    {
-      token = gsk_sl_preprocessor_get (stream);
-      switch (token->type)
+    case GSK_SL_TOKEN_CONST:
+    case GSK_SL_TOKEN_IN:
+    case GSK_SL_TOKEN_OUT:
+    case GSK_SL_TOKEN_INOUT:
+    case GSK_SL_TOKEN_INVARIANT:
+    case GSK_SL_TOKEN_COHERENT:
+    case GSK_SL_TOKEN_VOLATILE:
+    case GSK_SL_TOKEN_RESTRICT:
+    case GSK_SL_TOKEN_READONLY:
+    case GSK_SL_TOKEN_WRITEONLY:
+    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:
       {
-      case GSK_SL_TOKEN_SEMICOLON:
-        gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
-        break;
-
-      case GSK_SL_TOKEN_EOF:
-        gsk_sl_preprocessor_error (stream, "Unexpected end of function, expected \"}\"");
-        goto out;
-
-      case GSK_SL_TOKEN_RIGHT_BRACE:
-        goto out;
-
-      case GSK_SL_TOKEN_CONST:
-      case GSK_SL_TOKEN_IN:
-      case GSK_SL_TOKEN_OUT:
-      case GSK_SL_TOKEN_INOUT:
-      case GSK_SL_TOKEN_INVARIANT:
-      case GSK_SL_TOKEN_COHERENT:
-      case GSK_SL_TOKEN_VOLATILE:
-      case GSK_SL_TOKEN_RESTRICT:
-      case GSK_SL_TOKEN_READONLY:
-      case GSK_SL_TOKEN_WRITEONLY:
-      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;
-          GskSlPointerTypeFlags flags;
-          gboolean success;
-          GskSlNode *node = NULL;
-
-          success = gsk_sl_type_qualifier_parse (stream,
-                                                 GSK_SL_POINTER_TYPE_PARAMETER_QUALIFIER 
-                                                 | GSK_SL_POINTER_TYPE_MEMORY_QUALIFIER,
-                                                 &flags);
-
-          type = gsk_sl_type_new_parse (stream);
-          if (type == NULL)
-            break;
-
-          token = gsk_sl_preprocessor_get (stream);
-
-          if (token->type == GSK_SL_TOKEN_LEFT_BRACE)
-            {
-              GskSlExpression *expression = gsk_sl_expression_parse_constructor_call (function->scope, 
stream, type);
-
-              if (expression)
-                {
-                  GskSlNodeExpression *node;
-                  
-                  node = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
-                  node->expression = expression;
-
-                  function->statements = g_slist_append (function->statements, node);
-                }
-              else
-                {
-                  node = NULL;
-                }
-            }
-          else
-            {
-              GskSlPointerType *pointer_type;
-          
-              pointer_type = gsk_sl_pointer_type_new (type, flags | GSK_SL_POINTER_TYPE_LOCAL);
-              node = gsk_sl_node_parse_declaration (function->scope, stream, pointer_type);
-              gsk_sl_pointer_type_unref (pointer_type);
-            }
+        GskSlType *type;
+        GskSlPointerTypeFlags flags;
+        gboolean success;
 
-          gsk_sl_type_unref (type);
-          
-          if (!success)
-            {
-              gsk_sl_node_unref (node);
-            }
-          else if (node)
-            {
-              function->statements = g_slist_append (function->statements, node);
-            }
-        }
-        break;
-
-      case GSK_SL_TOKEN_RETURN:
-        {
-          GskSlNodeReturn *return_node;
-
-          return_node = gsk_sl_node_new (GskSlNodeReturn, &GSK_SL_NODE_RETURN);
-          gsk_sl_preprocessor_consume (stream, (GskSlNode *) return_node);
-          token = gsk_sl_preprocessor_get (stream);
-          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
-            {
-              return_node->value = gsk_sl_expression_parse (function->scope, stream);
-              if (return_node->value == NULL)
-                {
-                  gsk_sl_node_unref ((GskSlNode *) return_node);
-                  break;
-                }
-              if (function->return_type == NULL)
-                {
-                  gsk_sl_preprocessor_error (stream, "Cannot return a value from a void function.");
-                  gsk_sl_node_unref ((GskSlNode *) return_node);
-                  break;
-                }
-              else if (!gsk_sl_type_can_convert (function->return_type, gsk_sl_expression_get_return_type 
(return_node->value)))
-                {
-                  gsk_sl_preprocessor_error (stream, "Cannot convert return type %s to function type %s.",
-                                                     gsk_sl_type_get_name (gsk_sl_expression_get_return_type 
(return_node->value)),
-                                                     gsk_sl_type_get_name (function->return_type));
-                  gsk_sl_node_unref ((GskSlNode *) return_node);
-                  break;
-                }
+        success = gsk_sl_type_qualifier_parse (preproc,
+                                               GSK_SL_POINTER_TYPE_PARAMETER_QUALIFIER 
+                                               | GSK_SL_POINTER_TYPE_MEMORY_QUALIFIER,
+                                               &flags);
+
+        type = gsk_sl_type_new_parse (preproc);
+        if (type == NULL)
+          break;
+
+        token = gsk_sl_preprocessor_get (preproc);
+
+        if (token->type == GSK_SL_TOKEN_LEFT_PAREN)
+          {
+            GskSlExpression *expression = gsk_sl_expression_parse_constructor_call (scope, preproc, type);
+
+            if (expression)
+              {
+                GskSlNodeExpression *node_expression;
+                
+                node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
+                node_expression->expression = expression;
+                node = (GskSlNode *) node_expression;
               }
             else
               {
-                if (function->return_type != NULL)
-                  {
-                    gsk_sl_preprocessor_error (stream, "Return statement does not return a value.");
-                    gsk_sl_node_unref ((GskSlNode *) return_node);
-                    break;
-                  }
+                node = NULL;
               }
-            function->statements = g_slist_append (function->statements, return_node);
           }
-        break;
+        else
+          {
+            GskSlPointerType *pointer_type;
+        
+            pointer_type = gsk_sl_pointer_type_new (type, flags | GSK_SL_POINTER_TYPE_LOCAL);
+            node = gsk_sl_node_parse_declaration (scope, preproc, pointer_type);
+            gsk_sl_pointer_type_unref (pointer_type);
+          }
+
+        gsk_sl_type_unref (type);
+        
+        if (!success)
+          {
+            gsk_sl_node_unref (node);
+            node = NULL;
+          }
+      }
+      break;
 
-      default:
-        {
-          GskSlExpression * expression = gsk_sl_expression_parse (function->scope, stream);
+    case GSK_SL_TOKEN_RETURN:
+      {
+        GskSlNodeReturn *return_node;
+        GskSlType *return_type;
 
-          if (expression)
-            {
-              GskSlNodeExpression *node;
-              
-              node = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
-              node->expression = expression;
+        return_node = gsk_sl_node_new (GskSlNodeReturn, &GSK_SL_NODE_RETURN);
+        gsk_sl_preprocessor_consume (preproc, (GskSlNode *) return_node);
+        token = gsk_sl_preprocessor_get (preproc);
+        if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
+          {
+            return_node->value = gsk_sl_expression_parse (scope, preproc);
 
-              function->statements = g_slist_append (function->statements, node);
-            }
-          else
-            {
-              result = FALSE;
+            if (return_node->value == NULL)
+              {
+                gsk_sl_node_unref ((GskSlNode *) return_node);
+                node = NULL;
+                break;
+              }
+          }
+
+        return_type = gsk_sl_scope_get_return_type (scope);
+        node = (GskSlNode *) return_node;
+
+        if (return_type == NULL)
+          {
+            gsk_sl_preprocessor_error (preproc, "Cannot return from here.");
+            gsk_sl_node_unref (node);
+            node = NULL;
+          }
+        else if (return_node->value == NULL)
+          {
+            if (!gsk_sl_type_equal (return_type, gsk_sl_type_get_scalar (GSK_SL_VOID)))
+              {
+                gsk_sl_preprocessor_error (preproc, "Functions expectes a return value of type %s", 
gsk_sl_type_get_name (return_type));
+                gsk_sl_node_unref (node);
+                node = NULL;
+              }
+          }
+        else
+          {
+            if (gsk_sl_type_equal (return_type, gsk_sl_type_get_scalar (GSK_SL_VOID)))
+              {
+                gsk_sl_preprocessor_error (preproc, "Cannot return a value from a void function.");
+                gsk_sl_node_unref (node);
+                node = NULL;
+              }
+            else if (!gsk_sl_type_can_convert (return_type, gsk_sl_expression_get_return_type 
(return_node->value)))
+              {
+                gsk_sl_preprocessor_error (preproc,
+                                           "Cannot convert type %s to return type %s.",
+                                           gsk_sl_type_get_name (gsk_sl_expression_get_return_type 
(return_node->value)),
+                                           gsk_sl_type_get_name (return_type));
+                gsk_sl_node_unref (node);
+                node = NULL;
+                break;
+              }
             }
         }
-        break;
+      break;
+
+    default:
+      {
+        GskSlExpression * expression = gsk_sl_expression_parse (scope, preproc);
+
+        if (expression)
+          {
+            GskSlNodeExpression *node_expression;
+            
+            node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
+            node_expression->expression = expression;
+
+            node = (GskSlNode *) node_expression;
+          }
+        else
+          {
+            return NULL;
+          }
       }
-    }
+      break;
+  }
 
-out:
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
+  if (node == NULL)
+    return NULL;
 
-  if (result)
-    {
-      return (GskSlNode *) function;
-    }
-  else
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
     {
-      gsk_sl_node_unref ((GskSlNode *) function);
+      gsk_sl_preprocessor_error (preproc, "No semicolon at end of statement.");
+      gsk_sl_node_unref (node);
       return NULL;
     }
+  gsk_sl_preprocessor_consume (preproc, (GskSlNode *) node);
+
+  return node;
 }
 
 GskSlNode *
diff --git a/gsk/gskslnodeprivate.h b/gsk/gskslnodeprivate.h
index ead2280..5cb00c4 100644
--- a/gsk/gskslnodeprivate.h
+++ b/gsk/gskslnodeprivate.h
@@ -41,7 +41,7 @@ struct _GskSlNodeClass {
                                                                  GskSpvWriter        *writer);
 };
 
-GskSlNode *             gsk_sl_node_parse_function_definition   (GskSlScope          *scope,
+GskSlNode *             gsk_sl_node_parse_statement             (GskSlScope          *scope,
                                                                  GskSlPreprocessor   *preproc);
 
 GskSlNode *             gsk_sl_node_ref                         (GskSlNode           *node);
diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c
index dcb0f99..8a1d6de 100644
--- a/gsk/gskslprogram.c
+++ b/gsk/gskslprogram.c
@@ -20,10 +20,12 @@
 
 #include "gskslprogramprivate.h"
 
+#include "gskslfunctionprivate.h"
 #include "gskslnodeprivate.h"
 #include "gskslpreprocessorprivate.h"
 #include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
+#include "gsksltypeprivate.h"
 #include "gskspvwriterprivate.h"
 
 struct _GskSlProgram {
@@ -59,7 +61,48 @@ gsk_sl_program_class_init (GskSlProgramClass *klass)
 static void
 gsk_sl_program_init (GskSlProgram *program)
 {
-  program->scope = gsk_sl_scope_new (NULL);
+  program->scope = gsk_sl_scope_new (NULL, NULL);
+}
+
+static gboolean
+gsk_sl_program_parse_declaration (GskSlProgram      *program,
+                                  GskSlScope        *scope,
+                                  GskSlPreprocessor *preproc)
+{
+  GskSlType *type;
+  GskSlFunction *function;
+  const GskSlToken *token;
+  char *name;
+
+  type = gsk_sl_type_new_parse (preproc);
+  if (type == NULL)
+    {
+      gsk_sl_preprocessor_consume (preproc, program);
+      return FALSE;
+    }
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+    {
+      gsk_sl_preprocessor_error (preproc, "Expected a function name");
+      gsk_sl_type_unref (type);
+      return FALSE;
+    }
+
+  name = g_strdup (token->str);
+  gsk_sl_preprocessor_consume (preproc, program);
+
+  function = gsk_sl_function_new_parse (scope,
+                                        preproc,
+                                        type,
+                                        name);
+  if (function)
+    program->functions = g_slist_append (program->functions, function);
+
+  gsk_sl_type_unref (type);
+  g_free (name);
+
+  return function != NULL;
 }
 
 gboolean
@@ -67,26 +110,16 @@ gsk_sl_program_parse (GskSlProgram      *program,
                       GskSlPreprocessor *preproc)
 {
   const GskSlToken *token;
-  gboolean result = TRUE;
+  gboolean success = TRUE;
 
   for (token = gsk_sl_preprocessor_get (preproc);
        !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF);
        token = gsk_sl_preprocessor_get (preproc))
     {
-      GskSlNode *node = gsk_sl_node_parse_function_definition (program->scope, preproc);
-
-      if (node)
-        {
-          program->functions = g_slist_append (program->functions, node);
-        }
-      else
-        {
-          gsk_sl_preprocessor_consume (preproc, (GskSlNode *) program);
-          result = FALSE;
-        }
+      success &= gsk_sl_program_parse_declaration (program, program->scope, preproc);
     }
 
-  return result;
+  return success;
 }
 
 void
@@ -105,7 +138,7 @@ gsk_sl_program_print (GskSlProgram *program,
     {
       if (l != program->functions || program->declarations != NULL)
         g_string_append (string, "\n");
-      gsk_sl_node_print (l->data, string);
+      gsk_sl_function_print (l->data, string);
     }
 }
 
diff --git a/gsk/gskslscope.c b/gsk/gskslscope.c
index 1e89df6..0c65f28 100644
--- a/gsk/gskslscope.c
+++ b/gsk/gskslscope.c
@@ -20,6 +20,7 @@
 
 #include "gskslscopeprivate.h"
 
+#include "gsksltypeprivate.h"
 #include "gskslvariableprivate.h"
 
 #include <string.h>
@@ -29,12 +30,14 @@ struct _GskSlScope
   int ref_count;
 
   GskSlScope *parent;
+  GskSlType *return_type;
   
   GHashTable *variables;
 };
 
 GskSlScope *
-gsk_sl_scope_new (GskSlScope *parent)
+gsk_sl_scope_new (GskSlScope *parent,
+                  GskSlType  *return_type)
 {
   GskSlScope *scope;
   
@@ -43,6 +46,8 @@ gsk_sl_scope_new (GskSlScope *parent)
 
   if (parent)
     scope->parent = gsk_sl_scope_ref (parent);
+  if (return_type)
+    scope->return_type = gsk_sl_type_ref (return_type);
   scope->variables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) 
gsk_sl_variable_unref);
 
   return scope;
@@ -72,10 +77,18 @@ gsk_sl_scope_unref (GskSlScope *scope)
 
   if (scope->parent)
     gsk_sl_scope_unref (scope->parent);
+  if (scope->return_type)
+    gsk_sl_type_unref (scope->return_type);
 
   g_slice_free (GskSlScope, scope);
 }
 
+GskSlType *
+gsk_sl_scope_get_return_type (const GskSlScope *scope)
+{
+  return scope->return_type;
+}
+
 void
 gsk_sl_scope_add_variable (GskSlScope    *scope,
                            GskSlVariable *variable)
diff --git a/gsk/gskslscopeprivate.h b/gsk/gskslscopeprivate.h
index 1106075..9a41bef 100644
--- a/gsk/gskslscopeprivate.h
+++ b/gsk/gskslscopeprivate.h
@@ -25,11 +25,14 @@
 
 G_BEGIN_DECLS
 
-GskSlScope *            gsk_sl_scope_new                        (GskSlScope           *parent);
+GskSlScope *            gsk_sl_scope_new                        (GskSlScope           *parent,
+                                                                 GskSlType            *return_type);
 
 GskSlScope *            gsk_sl_scope_ref                        (GskSlScope           *scope);
 void                    gsk_sl_scope_unref                      (GskSlScope           *scope);
 
+GskSlType *             gsk_sl_scope_get_return_type            (const GskSlScope     *scope);
+
 void                    gsk_sl_scope_add_variable               (GskSlScope           *scope,
                                                                  GskSlVariable        *variable);
 GskSlVariable *         gsk_sl_scope_lookup_variable            (GskSlScope           *scope,



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