[gtk+/wip/otte/shader: 42/48] gskslpreprocessor: Implement #include



commit 1e01c92e210e8d3498694ed4fbf609657867028d
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 2 05:26:20 2017 +0200

    gskslpreprocessor: Implement #include

 gsk/gskcodesource.c        |    3 +-
 gsk/gskslcompiler.c        |   41 +++++++++++++++++++
 gsk/gskslcompilerprivate.h |    6 +++
 gsk/gskslpreprocessor.c    |   93 +++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 137 insertions(+), 6 deletions(-)
---
diff --git a/gsk/gskcodesource.c b/gsk/gskcodesource.c
index 155994f..92b1cac 100644
--- a/gsk/gskcodesource.c
+++ b/gsk/gskcodesource.c
@@ -146,6 +146,7 @@ gsk_code_source_load (GskCodeSource  *source,
                              error))
     return NULL;
 
-  return g_bytes_new_take (data, length);
+  source->bytes = g_bytes_new_take (data, length);
+  return g_bytes_ref (source->bytes);
 }
 
diff --git a/gsk/gskslcompiler.c b/gsk/gskslcompiler.c
index ec1e0c2..e9a6d6f 100644
--- a/gsk/gskslcompiler.c
+++ b/gsk/gskslcompiler.c
@@ -189,6 +189,47 @@ gsk_sl_compiler_copy_defines (GskSlCompiler *compiler)
   return copy;
 }
 
+GskCodeSource *
+gsk_sl_compiler_resolve_include (GskSlCompiler  *compiler,
+                                 GskCodeSource  *source,
+                                 gboolean        local,
+                                 const char     *name,
+                                 GError        **error)
+{
+  GskCodeSource *result;
+  GBytes *bytes;
+
+  if (local)
+    {
+      GFile *source_file = gsk_code_source_get_file (source);
+      if (source_file)
+        {
+          GFile *parent, *file;
+
+          parent = g_file_get_parent (source_file);
+          file = g_file_resolve_relative_path (parent, name);
+          result = gsk_code_source_new_for_file (file);
+          g_object_unref (parent);
+          g_object_unref (file);
+          bytes = gsk_code_source_load (result, error);
+          if (bytes)
+            {
+              g_bytes_unref (bytes);
+              return result;
+            }
+
+          g_object_unref (result);
+        }
+    }
+  else
+    {
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_EXIST,
+                   "Could not resolve \"%s\" in search path.", name);
+    }
+
+  return NULL;
+}
+
 static GskSlProgram *
 gsk_sl_compiler_compile (GskSlCompiler *compiler,
                          GskCodeSource *source)
diff --git a/gsk/gskslcompilerprivate.h b/gsk/gskslcompilerprivate.h
index 184502f..32e5660 100644
--- a/gsk/gskslcompilerprivate.h
+++ b/gsk/gskslcompilerprivate.h
@@ -25,6 +25,12 @@ G_BEGIN_DECLS
 
 GHashTable *            gsk_sl_compiler_copy_defines            (GskSlCompiler          *compiler);
 
+GskCodeSource *         gsk_sl_compiler_resolve_include         (GskSlCompiler          *compiler,
+                                                                 GskCodeSource          *source,
+                                                                 gboolean                local,
+                                                                 const char             *name,
+                                                                 GError                **error);
+
 G_END_DECLS
 
 #endif /* __GSK_SL_COMPILER_PRIVATE_H__ */
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index 4ee7bfc..801f797 100644
--- a/gsk/gskslpreprocessor.c
+++ b/gsk/gskslpreprocessor.c
@@ -38,6 +38,7 @@ struct _GskSlPreprocessor
 
   GskSlCompiler *compiler;
   GskSlTokenizer *tokenizer;
+  GSList *pending_tokenizers;
   GArray *tokens;
   GHashTable *defines;
   gboolean fatal_error;
@@ -117,6 +118,7 @@ gsk_sl_preprocessor_unref (GskSlPreprocessor *preproc)
 
   g_slist_free (preproc->conditionals);
   g_hash_table_destroy (preproc->defines);
+  g_slist_free_full (preproc->pending_tokenizers, (GDestroyNotify) gsk_sl_tokenizer_unref);
   gsk_sl_tokenizer_unref (preproc->tokenizer);
   g_object_unref (preproc->compiler);
   g_array_free (preproc->tokens, TRUE);
@@ -168,6 +170,54 @@ gsk_sl_preprocessor_in_ignored_conditional (GskSlPreprocessor *preproc)
 }
 
 static gboolean
+gsk_sl_preprocessor_include (GskSlPreprocessor *preproc,
+                             GskSlPpToken      *pp,
+                             gboolean           include_local)
+{
+  GskCodeSource *source;
+  GError *error = NULL;
+    
+  source = gsk_sl_compiler_resolve_include (preproc->compiler,
+                                            gsk_sl_tokenizer_get_location (preproc->tokenizer)->source,
+                                            include_local,
+                                            pp->token.str,
+                                            &error);
+  if (source == NULL)
+    {
+      gsk_sl_preprocessor_emit_error (preproc, TRUE, &pp->location, error);
+      gsk_sl_preprocessor_clear_token (pp);
+      g_error_free (error);
+      return FALSE;
+    }
+
+  if (g_slist_length (preproc->pending_tokenizers) > 20)
+    {
+      gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp->location, "#include nested too deeply.");
+      gsk_sl_preprocessor_clear_token (pp);
+      return FALSE;
+    }
+
+  gsk_sl_preprocessor_clear_token (pp);
+  pp->location = *gsk_sl_tokenizer_get_location (preproc->tokenizer);
+  gsk_sl_tokenizer_read_token (preproc->tokenizer, &pp->token);
+  if (!gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_NEWLINE) &&
+      !gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_EOF))
+    {
+      gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp->location, "Extra content after #include 
directive");
+      gsk_sl_preprocessor_clear_token (pp);
+      return FALSE;
+    }
+
+  gsk_sl_preprocessor_clear_token (pp);
+  preproc->pending_tokenizers = g_slist_prepend (preproc->pending_tokenizers, preproc->tokenizer);
+  preproc->tokenizer = gsk_sl_tokenizer_new (source, 
+                                             gsk_sl_preprocessor_error_func,
+                                             preproc,
+                                             NULL);
+  return TRUE;
+}
+
+static gboolean
 gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
                                 GskSlPpToken      *pp,
                                 gboolean          *last_was_newline)
@@ -189,10 +239,28 @@ gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
 }
 
 static void
+gsk_sl_preprocessor_handle_token (GskSlPreprocessor *preproc,
+                                  GskSlPpToken      *pp,
+                                  gboolean           was_newline);
+
+static void
 gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
                                   GskSlPpToken      *pp,
                                   GSList            *used_defines)
 {
+  if (gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_EOF) &&
+      preproc->pending_tokenizers)
+    {
+      gboolean was_newline;
+      gsk_sl_tokenizer_unref (preproc->tokenizer);
+      preproc->tokenizer = preproc->pending_tokenizers->data;
+      preproc->pending_tokenizers = g_slist_remove (preproc->pending_tokenizers, preproc->tokenizer);
+      gsk_sl_preprocessor_clear_token (pp);
+      gsk_sl_preprocessor_next_token (preproc, pp, &was_newline);
+      gsk_sl_preprocessor_handle_token (preproc, pp, TRUE);
+      return;
+    }
+
   if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
     {
       gsk_sl_preprocessor_clear_token (pp);
@@ -236,11 +304,6 @@ gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
 }
 
 static void
-gsk_sl_preprocessor_handle_token (GskSlPreprocessor *preproc,
-                                  GskSlPpToken      *pp,
-                                  gboolean           was_newline);
-
-static void
 gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
 {
   GskSlPpToken pp;
@@ -440,6 +503,26 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
               return;
             }
         }
+      else if (g_str_equal (pp.token.str, "include"))
+        {
+          gsk_sl_preprocessor_clear_token (&pp);
+          if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No filename after 
#include.");
+              gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+              return;
+            }
+          if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_STRING))
+            {
+              if (gsk_sl_preprocessor_include (preproc, &pp, TRUE))
+                return;
+            }
+          else
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected filename after 
#include.");
+              gsk_sl_preprocessor_clear_token (&pp);
+            }
+        }
 #if 0
       else if (g_str_equal (pp.token.str, "line"))
         {


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