[gtk+/wip/otte/shader: 98/101] gskslpreprocessor: Implement #if and #elif



commit a6973a3234294e12a361e34f73b7d3b5fe3a8875
Author: Benjamin Otte <otte redhat com>
Date:   Wed Oct 25 21:22:01 2017 +0200

    gskslpreprocessor: Implement #if and #elif
    
    Actually, just implement numbers and defined() parsing. But that's
    enough for now.

 gsk/gskslpreprocessor.c                            |  178 +++++++++++++++++++-
 testsuite/gsksl/errors/if-defined-empty.glsl       |    6 +
 testsuite/gsksl/errors/if-defined-paren-empty.glsl |    6 +
 .../gsksl/errors/if-defined-paren-no-contents.glsl |    6 +
 4 files changed, 188 insertions(+), 8 deletions(-)
---
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index 6a1c6fe..09e29ec 100644
--- a/gsk/gskslpreprocessor.c
+++ b/gsk/gskslpreprocessor.c
@@ -205,6 +205,130 @@ gsk_sl_preprocessor_handle_version (GskSlPreprocessor *preproc,
     }
 }
 
+#define token_array_get_token(array, i) (&g_array_index ((array), GskSlPpToken, (i)).token)
+#define token_array_get_location(array, i) (&g_array_index ((array), GskSlPpToken, (i)).location)
+#define token_array_error(preproc, array, i, ...) gsk_sl_preprocessor_error_full ((preproc), PREPROCESSOR, 
token_array_get_location (array, i), __VA_ARGS__)
+
+static int
+gsk_sl_preprocessor_handle_defined_expression (GskSlPreprocessor *preproc,
+                                               GArray            *tokens,
+                                               gint              *index)
+{
+  const GskSlToken *token;
+  gboolean paren = FALSE;
+  int result;
+
+  (*index)++;
+
+  if (*index >= tokens->len)
+    {
+      token_array_error (preproc, tokens, tokens->len - 1, "\"defined\" without argument.");
+      return 0;
+    }
+
+  token = token_array_get_token (tokens, *index);
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
+    {
+      paren = TRUE;
+      (*index)++;
+      if (*index >= tokens->len)
+        {
+          token_array_error (preproc, tokens, tokens->len - 1, "\"defined()\" without argument.");
+          return 0;
+        }
+      token = token_array_get_token (tokens, *index);
+    }
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+    {
+      (*index)++;
+      if (g_hash_table_lookup (preproc->defines, token->str))
+        result = 1;
+      else
+        result = 0;
+    }
+  else
+    {
+      token_array_error (preproc, tokens, *index, "Expected identifier after \"defined\".");
+    }
+  if (paren)
+    {
+      if (*index >= tokens->len ||
+          !gsk_sl_token_is (token_array_get_token (tokens, *index), GSK_SL_TOKEN_RIGHT_PAREN))
+        {
+          token_array_error (preproc, tokens, *index, "Expected closing \")\" for \"defined()\".");
+          return 0;
+        }
+      else
+        {
+          (*index)++;
+        }
+    }
+  return result;
+}
+
+static int
+gsk_sl_preprocessor_handle_primary_expression (GskSlPreprocessor *preproc,
+                                               GArray            *tokens,
+                                               gint              *index)
+{
+  const GskSlToken *token;
+
+  if (*index >= tokens->len)
+    {
+      token_array_error (preproc, tokens, tokens->len - 1, "Expected value.");
+      return 0;
+    }
+
+  token = token_array_get_token (tokens, (*index));
+
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+    {
+      if (g_str_equal (token->str, "defined"))
+        {
+          return gsk_sl_preprocessor_handle_defined_expression (preproc, tokens, index);
+        }
+      else
+        {
+          token_array_error (preproc, tokens, *index, "Unexpected identifier \"%s\".", token->str);
+          (*index)++;
+          return 0;
+        }
+    }
+  else if (gsk_sl_token_is (token, GSK_SL_TOKEN_INTCONSTANT))
+    {
+      (*index)++;
+      return token->i32;
+    }
+  else if (gsk_sl_token_is (token, GSK_SL_TOKEN_UINTCONSTANT))
+    {
+      (*index)++;
+      return token->u32;
+    }
+  else
+    {
+      token_array_error (preproc, tokens, *index, "Unexpected token in #if statement.");
+      (*index)++;
+      return 0;
+    }
+}
+
+static int
+gsk_sl_preprocessor_handle_expression (GskSlPreprocessor *preproc,
+                                       GArray            *tokens,
+                                       gint              *index)
+{
+  int result;
+
+  result = gsk_sl_preprocessor_handle_primary_expression (preproc, tokens, index);
+
+  if (*index < tokens->len)
+    {
+      token_array_error (preproc, tokens, *index, "Expected newline after expression.");
+    }
+
+  return result;
+}
+
 static gboolean
 gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
                                 GskSlPpToken      *pp,
@@ -232,10 +356,6 @@ gsk_sl_preprocessor_handle_token (GskSlPreprocessor *preproc,
                                   gboolean           was_newline,
                                   gboolean           was_start_of_document);
 
-#define token_array_get_token(array, i) (&g_array_index ((array), GskSlPpToken, (i)).token)
-#define token_array_get_location(array, i) (&g_array_index ((array), GskSlPpToken, (i)).location)
-#define token_array_error(preproc, array, i, ...) gsk_sl_preprocessor_error_full ((preproc), PREPROCESSOR, 
token_array_get_location (array, i), __VA_ARGS__)
-
 static gboolean
 gsk_sl_preprocessor_include (GskSlPreprocessor *preproc,
                              GArray            *tokens,
@@ -419,11 +539,47 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc,
       if (tokens->len > 1)
         token_array_error (preproc, tokens, 1, "Expected newline after #else.");
     }
-#if 0
   else if (g_str_equal (token->str, "elif"))
     {
+      if (gsk_sl_preprocessor_has_conditional (preproc))
+        {
+          GskConditional cond = gsk_sl_preprocessor_pop_conditional (preproc);
+
+          if (cond & GSK_COND_ELSE)
+            {
+              token_array_error (preproc, tokens, 0, "#elif after #else.");
+              cond |= GSK_COND_IGNORE;
+            }
+          else
+            {
+              int expr, index;
+              
+              index = 1;
+              expr = gsk_sl_preprocessor_handle_expression (preproc, tokens, &index);
+            
+              if (cond & GSK_COND_MATCH)
+                {
+                  cond |= GSK_COND_IGNORE;
+                }
+              else if (expr)
+                {
+                  cond &= ~GSK_COND_IGNORE;
+                  cond |= GSK_COND_MATCH;
+                }
+              else
+                {
+                  cond |= GSK_COND_IGNORE;
+                }
+            }
+
+          gsk_sl_preprocessor_push_conditional (preproc, cond);
+        }
+      else
+        {
+          token_array_error (preproc, tokens, 0, "#elif without #if.");
+        }
+
     }
-#endif
   else if (g_str_equal (token->str, "endif"))
     {
       if (gsk_sl_preprocessor_has_conditional (preproc))
@@ -438,11 +594,17 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc,
       if (tokens->len > 1)
           token_array_error (preproc, tokens, 1, "Expected newline after #endif.");
     }
-#if 0
   else if (g_str_equal (token->str, "if"))
     {
+      int expr, index;
+      
+      index = 1;
+      expr = gsk_sl_preprocessor_handle_expression (preproc, tokens, &index);
+      if (expr)
+        gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_MATCH);
+      else
+        gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_IGNORE);
     }
-#endif
   else if (g_str_equal (token->str, "ifdef"))
     {
       if (tokens->len == 1)
diff --git a/testsuite/gsksl/errors/if-defined-empty.glsl b/testsuite/gsksl/errors/if-defined-empty.glsl
new file mode 100644
index 0000000..7635862
--- /dev/null
+++ b/testsuite/gsksl/errors/if-defined-empty.glsl
@@ -0,0 +1,6 @@
+#if defined
+
+void
+main ()
+{
+}
diff --git a/testsuite/gsksl/errors/if-defined-paren-empty.glsl 
b/testsuite/gsksl/errors/if-defined-paren-empty.glsl
new file mode 100644
index 0000000..04b0df8
--- /dev/null
+++ b/testsuite/gsksl/errors/if-defined-paren-empty.glsl
@@ -0,0 +1,6 @@
+#if defined (
+
+void
+main ()
+{
+}
diff --git a/testsuite/gsksl/errors/if-defined-paren-no-contents.glsl 
b/testsuite/gsksl/errors/if-defined-paren-no-contents.glsl
new file mode 100644
index 0000000..34e301c
--- /dev/null
+++ b/testsuite/gsksl/errors/if-defined-paren-no-contents.glsl
@@ -0,0 +1,6 @@
+#if defined ()
+
+void
+main ()
+{
+}


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