summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2017-10-25 21:22:01 +0200
committerBenjamin Otte <otte@redhat.com>2017-10-30 02:58:03 +0100
commit39a277260f48fc8b1f3eb665e8b9c5a69095b634 (patch)
tree82989a51175dcd77ad1751d2ea4200c2bb5d584d
parent5bb7c2ecc3f1fa238ff8a8486bec30809eda18b2 (diff)
downloadgtk+-39a277260f48fc8b1f3eb665e8b9c5a69095b634.tar.gz
gskslpreprocessor: Implement #if and #elif
Actually, just implement numbers and defined() parsing. But that's enough for now.
-rw-r--r--gsk/gskslpreprocessor.c178
-rw-r--r--testsuite/gsksl/errors/if-defined-empty.glsl6
-rw-r--r--testsuite/gsksl/errors/if-defined-paren-empty.glsl6
-rw-r--r--testsuite/gsksl/errors/if-defined-paren-no-contents.glsl6
4 files changed, 188 insertions, 8 deletions
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index 6a1c6fe321..09e29ec295 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 0000000000..763586296e
--- /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 0000000000..04b0df87d9
--- /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 0000000000..34e301c998
--- /dev/null
+++ b/testsuite/gsksl/errors/if-defined-paren-no-contents.glsl
@@ -0,0 +1,6 @@
+#if defined ()
+
+void
+main ()
+{
+}