From 67b60b54ac24a9a60f87d617e0e40ec8a189609d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 24 Sep 2017 03:34:31 +0200 Subject: [PATCH] gskslcompiler: Add support for adding defines gtk-glsl implements this via the usual -D and -U options. Preprocessor directives aren't implemented yet, but defines are replaced in the source code already. --- gsk/gskslcompiler.c | 130 ++++++++++++++++- gsk/gskslcompiler.h | 9 ++ gsk/gskslcompilerprivate.h | 30 ++++ gsk/gsksldefine.c | 132 +++++++++++++++++ gsk/gsksldefineprivate.h | 51 +++++++ gsk/gskslpreprocessor.c | 145 +++++++++++++------ gsk/gsksltokenizer.c | 277 ++++++++++++++++++++++++++++++++++++ gsk/gsksltokenizerprivate.h | 5 +- gsk/meson.build | 1 + gtk/glsl.c | 44 +++++- 10 files changed, 774 insertions(+), 50 deletions(-) create mode 100644 gsk/gskslcompilerprivate.h create mode 100644 gsk/gsksldefine.c create mode 100644 gsk/gsksldefineprivate.h diff --git a/gsk/gskslcompiler.c b/gsk/gskslcompiler.c index 66ad1da6f3..a97f277aca 100644 --- a/gsk/gskslcompiler.c +++ b/gsk/gskslcompiler.c @@ -18,13 +18,17 @@ #include "config.h" -#include "gskslcompiler.h" +#include "gskslcompilerprivate.h" +#include "gsksldefineprivate.h" #include "gskslpreprocessorprivate.h" #include "gskslprogramprivate.h" +#include "gsksltokenizerprivate.h" struct _GskSlCompiler { GObject parent_instance; + + GHashTable *defines; }; G_DEFINE_TYPE (GskSlCompiler, gsk_sl_compiler, G_TYPE_OBJECT) @@ -32,7 +36,9 @@ G_DEFINE_TYPE (GskSlCompiler, gsk_sl_compiler, G_TYPE_OBJECT) static void gsk_sl_compiler_dispose (GObject *object) { - //GskSlCompiler *compiler = GSK_SL_COMPILER (object); + GskSlCompiler *compiler = GSK_SL_COMPILER (object); + + g_hash_table_destroy (compiler->defines); G_OBJECT_CLASS (gsk_sl_compiler_parent_class)->dispose (object); } @@ -48,6 +54,8 @@ gsk_sl_compiler_class_init (GskSlCompilerClass *klass) static void gsk_sl_compiler_init (GskSlCompiler *compiler) { + compiler->defines = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) gsk_sl_define_unref); } GskSlCompiler * @@ -56,6 +64,124 @@ gsk_sl_compiler_new (void) return g_object_new (GSK_TYPE_SL_COMPILER, NULL); } +static void +gsk_sl_compiler_add_define_error_func (GskSlTokenizer *parser, + gboolean fatal, + const GskCodeLocation *location, + const GskSlToken *token, + const GError *error, + gpointer user_data) +{ + GError **real_error = user_data; + + if (!fatal) + return; + + if (*real_error) + return; + + *real_error = g_error_copy (error); + g_prefix_error (real_error, + "%3zu:%2zu: ", + location->lines + 1, + location->line_bytes); +} + +gboolean +gsk_sl_compiler_add_define (GskSlCompiler *compiler, + const char *name, + const char *definition, + GError **error) +{ + GskSlTokenizer *tokenizer; + GskSlDefine *define; + GskCodeLocation location; + GskSlToken token = { 0, }; + GError *real_error = NULL; + GBytes *bytes; + + g_return_val_if_fail (GSK_IS_SL_COMPILER (compiler), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!gsk_sl_string_is_valid_identifier (name)) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Define name \"%s\" is not a valid identifier", name); + return FALSE; + } + + if (definition == NULL) + definition = "1"; + + define = gsk_sl_define_new (name, NULL); + bytes = g_bytes_new_static (definition, strlen (definition)); + tokenizer = gsk_sl_tokenizer_new (bytes, + gsk_sl_compiler_add_define_error_func, + &real_error, + NULL); + + while (TRUE) + { + do + { + gsk_sl_token_clear (&token); + location = *gsk_sl_tokenizer_get_location (tokenizer); + gsk_sl_tokenizer_read_token (tokenizer, &token); + } + while (gsk_sl_token_is_skipped (&token)); + + if (gsk_sl_token_is (&token, GSK_SL_TOKEN_EOF)) + break; + + gsk_sl_define_add_token (define, &location, &token); + } + + gsk_sl_token_clear (&token); + gsk_sl_tokenizer_unref (tokenizer); + g_bytes_unref (bytes); + + if (real_error == NULL) + { + g_hash_table_replace (compiler->defines, (gpointer) gsk_sl_define_get_name (define), define); + return TRUE; + } + else + { + gsk_sl_define_unref (define); + g_propagate_error (error, real_error); + return FALSE; + } +} + +void +gsk_sl_compiler_remove_define (GskSlCompiler *compiler, + const char *name) +{ + g_return_if_fail (GSK_IS_SL_COMPILER (compiler)); + g_return_if_fail (name != NULL); + + g_hash_table_remove (compiler->defines, name); +} + +GHashTable * +gsk_sl_compiler_copy_defines (GskSlCompiler *compiler) +{ + GHashTable *copy; + GHashTableIter iter; + gpointer key, value; + + copy = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) gsk_sl_define_unref); + + g_hash_table_iter_init (&iter, compiler->defines); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + g_hash_table_replace (copy, key, gsk_sl_define_ref (value)); + } + + return copy; +} + GskSlProgram * gsk_sl_compiler_compile (GskSlCompiler *compiler, GBytes *source) diff --git a/gsk/gskslcompiler.h b/gsk/gskslcompiler.h index 910897dbfd..94c2763558 100644 --- a/gsk/gskslcompiler.h +++ b/gsk/gskslcompiler.h @@ -34,6 +34,15 @@ G_DECLARE_FINAL_TYPE (GskSlCompiler, gsk_sl_compiler, GSK, SL_COMPILER, GObject) GDK_AVAILABLE_IN_3_92 GskSlCompiler * gsk_sl_compiler_new (void); +GDK_AVAILABLE_IN_3_92 +gboolean gsk_sl_compiler_add_define (GskSlCompiler *compiler, + const char *name, + const char *definition, + GError **error); +GDK_AVAILABLE_IN_3_92 +void gsk_sl_compiler_remove_define (GskSlCompiler *compiler, + const char *name); + GDK_AVAILABLE_IN_3_92 GskSlProgram * gsk_sl_compiler_compile (GskSlCompiler *compiler, GBytes *source); diff --git a/gsk/gskslcompilerprivate.h b/gsk/gskslcompilerprivate.h new file mode 100644 index 0000000000..184502f1f8 --- /dev/null +++ b/gsk/gskslcompilerprivate.h @@ -0,0 +1,30 @@ +/* GTK - The GIMP Toolkit + * + * Copyright © 2017 Benjamin Otte + * + * 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 . + */ + +#ifndef __GSK_SL_COMPILER_PRIVATE_H__ +#define __GSK_SL_COMPILER_PRIVATE_H__ + +#include "gsk/gskslcompiler.h" + +G_BEGIN_DECLS + +GHashTable * gsk_sl_compiler_copy_defines (GskSlCompiler *compiler); + +G_END_DECLS + +#endif /* __GSK_SL_COMPILER_PRIVATE_H__ */ diff --git a/gsk/gsksldefine.c b/gsk/gsksldefine.c new file mode 100644 index 0000000000..c3ad56ba35 --- /dev/null +++ b/gsk/gsksldefine.c @@ -0,0 +1,132 @@ +/* GTK - The GIMP Toolkit + * + * Copyright © 2017 Benjamin Otte + * + * 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 . + */ + +#include "config.h" + +#include "gsksldefineprivate.h" + +typedef struct _GskSlDefineToken GskSlDefineToken; + +struct _GskSlDefineToken { + GskCodeLocation location; + GskSlToken token; +}; + +struct _GskSlDefine { + int ref_count; + + char *name; + GFile *source_file; + + GArray *tokens; +}; + +GskSlDefine * +gsk_sl_define_new (const char *name, + GFile *source_file) +{ + GskSlDefine *result; + + result = g_slice_new0 (GskSlDefine); + + result->ref_count = 1; + result->name = g_strdup (name); + if (source_file) + result->source_file = g_object_ref (source_file); + result->tokens = g_array_new (FALSE, FALSE, sizeof (GskSlDefineToken)); + + return result; +} + +GskSlDefine * +gsk_sl_define_ref (GskSlDefine *define) +{ + g_return_val_if_fail (define != NULL, NULL); + + define->ref_count += 1; + + return define; +} + +void +gsk_sl_define_unref (GskSlDefine *define) +{ + if (define == NULL) + return; + + define->ref_count -= 1; + if (define->ref_count > 0) + return; + + g_array_free (define->tokens, TRUE); + + if (define->source_file) + g_object_unref (define->source_file); + g_free (define->name); + + g_slice_free (GskSlDefine, define); +} + +const char * +gsk_sl_define_get_name (GskSlDefine *define) +{ + return define->name; +} + +GFile * +gsk_sl_define_get_source_file (GskSlDefine *define) +{ + return define->source_file; +} + +guint +gsk_sl_define_get_n_tokens (GskSlDefine *define) +{ + return define->tokens->len; +} + +void +gsk_sl_define_get_token (GskSlDefine *define, + guint i, + GskCodeLocation *location, + GskSlToken *token) +{ + GskSlDefineToken *dt; + + dt = &g_array_index (define->tokens, GskSlDefineToken, i); + + if (location) + *location = dt->location; + if (token) + gsk_sl_token_copy (token, &dt->token); +} + +void +gsk_sl_define_add_token (GskSlDefine *define, + const GskCodeLocation *location, + const GskSlToken *token) +{ + GskSlDefineToken dt; + + dt.location = *location; + gsk_sl_token_copy (&dt.token, token); + + g_array_append_val (define->tokens, dt); +} + + diff --git a/gsk/gsksldefineprivate.h b/gsk/gsksldefineprivate.h new file mode 100644 index 0000000000..92ac0db95b --- /dev/null +++ b/gsk/gsksldefineprivate.h @@ -0,0 +1,51 @@ +/* GTK - The GIMP Toolkit + * + * Copyright © 2017 Benjamin Otte + * + * 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 . + */ + +#ifndef __GSK_SL_DEFINE_PRIVATE_H__ +#define __GSK_SL_DEFINE_PRIVATE_H__ + +#include + +#include "gsksltokenizerprivate.h" +#include "gsksltypesprivate.h" + +G_BEGIN_DECLS + +typedef struct _GskSlDefine GskSlDefine; + +GskSlDefine * gsk_sl_define_new (const char *name, + GFile *source_file); + +GskSlDefine * gsk_sl_define_ref (GskSlDefine *define); +void gsk_sl_define_unref (GskSlDefine *define); + +const char * gsk_sl_define_get_name (GskSlDefine *define); +GFile * gsk_sl_define_get_source_file (GskSlDefine *define); +guint gsk_sl_define_get_n_tokens (GskSlDefine *define); +void gsk_sl_define_get_token (GskSlDefine *define, + guint i, + GskCodeLocation *location, + GskSlToken *token); + +void gsk_sl_define_add_token (GskSlDefine *define, + const GskCodeLocation *location, + const GskSlToken *token); + +G_END_DECLS + +#endif /* __GSK_SL_DEFINE_PRIVATE_H__ */ diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c index eec8d0b7d3..efa154fdc8 100644 --- a/gsk/gskslpreprocessor.c +++ b/gsk/gskslpreprocessor.c @@ -20,16 +20,25 @@ #include "gskslpreprocessorprivate.h" +#include "gskslcompilerprivate.h" +#include "gsksldefineprivate.h" #include "gsksltokenizerprivate.h" +typedef struct _GskSlPpToken GskSlPpToken; + +struct _GskSlPpToken { + GskCodeLocation location; + GskSlToken token; +}; + struct _GskSlPreprocessor { int ref_count; GskSlCompiler *compiler; GskSlTokenizer *tokenizer; - GskCodeLocation location; - GskSlToken token; + GArray *tokens; + GHashTable *defines; }; /* API */ @@ -48,6 +57,14 @@ gsk_sl_preprocessor_error_func (GskSlTokenizer *parser, error->message); } +static void +gsk_sl_preprocessor_clear_token (gpointer data) +{ + GskSlPpToken *pp = data; + + gsk_sl_token_clear (&pp->token); +} + GskSlPreprocessor * gsk_sl_preprocessor_new (GskSlCompiler *compiler, GBytes *source) @@ -62,6 +79,9 @@ gsk_sl_preprocessor_new (GskSlCompiler *compiler, gsk_sl_preprocessor_error_func, preproc, NULL); + preproc->tokens = g_array_new (FALSE, FALSE, sizeof (GskSlPpToken)); + g_array_set_clear_func (preproc->tokens, gsk_sl_preprocessor_clear_token); + preproc->defines = gsk_sl_compiler_copy_defines (compiler); return preproc; } @@ -86,35 +106,29 @@ gsk_sl_preprocessor_unref (GskSlPreprocessor *preproc) if (preproc->ref_count > 0) return; + g_hash_table_destroy (preproc->defines); gsk_sl_tokenizer_unref (preproc->tokenizer); - gsk_sl_token_clear (&preproc->token); g_object_unref (preproc->compiler); + g_array_free (preproc->tokens, TRUE); g_slice_free (GskSlPreprocessor, preproc); } static gboolean -gsk_sl_token_is_skipped (const GskSlToken *token) -{ - return gsk_sl_token_is (token, GSK_SL_TOKEN_ERROR) - || gsk_sl_token_is (token, GSK_SL_TOKEN_NEWLINE) - || gsk_sl_token_is (token, GSK_SL_TOKEN_WHITESPACE) - || gsk_sl_token_is (token, GSK_SL_TOKEN_COMMENT) - || gsk_sl_token_is (token, GSK_SL_TOKEN_SINGLE_LINE_COMMENT); -} - -static gboolean -gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc) +gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc, + GskSlPpToken *pp) { gboolean was_newline; + pp->token = (GskSlToken) { 0, }; + do { - preproc->location = *gsk_sl_tokenizer_get_location (preproc->tokenizer); - was_newline = gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_NEWLINE); - gsk_sl_tokenizer_read_token (preproc->tokenizer, &preproc->token); + pp->location = *gsk_sl_tokenizer_get_location (preproc->tokenizer); + was_newline = gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_NEWLINE); + gsk_sl_tokenizer_read_token (preproc->tokenizer, &pp->token); } - while (gsk_sl_token_is_skipped (&preproc->token)); + while (gsk_sl_token_is_skipped (&pp->token)); return was_newline; } @@ -122,17 +136,23 @@ gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc) static void gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc) { - gboolean was_newline = gsk_sl_preprocessor_next_token (preproc); + GskSlPpToken pp; + + gboolean was_newline = gsk_sl_preprocessor_next_token (preproc, &pp); /* empty # line */ if (was_newline) - return; - - if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_IDENTIFIER)) { - if (g_str_equal (preproc->token.str, "define")) + gsk_sl_preprocessor_clear_token (&pp); + return; + } + + if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER)) + { + if (g_str_equal (pp.token.str, "define")) { gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #define."); + gsk_sl_preprocessor_clear_token (&pp); } #if 0 else if (g_str_equal (preproc->token.str, "else")) @@ -165,49 +185,89 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc) else if (g_str_equal (preproc->token.str, "pragma")) { } + else if (g_str_equal (preproc->token.str, "undef")) + { + } else if (g_str_equal (preproc->token.str, "version")) { } #endif else { - gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #%s.", preproc->token.str); + gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #%s.", pp.token.str); + gsk_sl_preprocessor_clear_token (&pp); } } - else if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_ELSE)) - { - gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #else."); - } else { gsk_sl_preprocessor_error (preproc, "Missing identifier for preprocessor directive."); + gsk_sl_preprocessor_clear_token (&pp); + } + + while (!gsk_sl_preprocessor_next_token (preproc, &pp)) + gsk_sl_preprocessor_clear_token (&pp); +} + +static void +gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc, + GskSlPpToken *pp, + GSList *used_defines) +{ + if (gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_IDENTIFIER)) + { + GskSlDefine *define; + char *ident = pp->token.str; + + define = g_hash_table_lookup (preproc->defines, ident); + if (define && + !g_slist_find (used_defines, define)) + { + GSList new_defines = { define, used_defines }; + GskSlPpToken dpp; + guint i; + + for (i = 0; i < gsk_sl_define_get_n_tokens (define); i++) + { + gsk_sl_define_get_token (define, i, &dpp.location, &dpp.token); + gsk_sl_preprocessor_append_token (preproc, &dpp, &new_defines); + } + + gsk_sl_preprocessor_clear_token (pp); + return; + } + + gsk_sl_token_init_from_identifier (&pp->token, ident); + g_free (ident); } - while (!gsk_sl_preprocessor_next_token (preproc)); + g_array_append_val (preproc->tokens, *pp); } static void gsk_sl_preprocessor_ensure (GskSlPreprocessor *preproc) { + GskSlPpToken pp; gboolean was_newline = FALSE; - if (!gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_EOF)) + if (preproc->tokens->len > 0) return; - was_newline = gsk_sl_preprocessor_next_token (preproc); + was_newline = gsk_sl_preprocessor_next_token (preproc, &pp); while (TRUE) { - if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_HASH)) + if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_HASH)) { if (!was_newline && - preproc->location.bytes != 0) + pp.location.bytes != 0) { gsk_sl_preprocessor_error (preproc, "Unexpected \"#\" - preprocessor directives must be at start of line."); - was_newline = gsk_sl_preprocessor_next_token (preproc); + gsk_sl_preprocessor_clear_token (&pp); + was_newline = gsk_sl_preprocessor_next_token (preproc, &pp); } else { + gsk_sl_preprocessor_clear_token (&pp); gsk_sl_preprocessor_handle_preprocessor_directive (preproc); was_newline = TRUE; } @@ -218,12 +278,7 @@ gsk_sl_preprocessor_ensure (GskSlPreprocessor *preproc) } } - if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_IDENTIFIER)) - { - char *ident = preproc->token.str; - gsk_sl_token_init_from_identifier (&preproc->token, ident); - g_free (ident); - } + gsk_sl_preprocessor_append_token (preproc, &pp, NULL); } const GskSlToken * @@ -231,7 +286,7 @@ gsk_sl_preprocessor_get (GskSlPreprocessor *preproc) { gsk_sl_preprocessor_ensure (preproc); - return &preproc->token; + return &g_array_index (preproc->tokens, GskSlPpToken, 0).token; } const GskCodeLocation * @@ -239,7 +294,7 @@ gsk_sl_preprocessor_get_location (GskSlPreprocessor *preproc) { gsk_sl_preprocessor_ensure (preproc); - return &preproc->location; + return &g_array_index (preproc->tokens, GskSlPpToken, 0).location; } void @@ -248,7 +303,7 @@ gsk_sl_preprocessor_consume (GskSlPreprocessor *preproc, { gsk_sl_preprocessor_ensure (preproc); - gsk_sl_token_clear (&preproc->token); + g_array_remove_index (preproc->tokens, 0); } void @@ -269,8 +324,8 @@ gsk_sl_preprocessor_error (GskSlPreprocessor *preproc, gsk_sl_preprocessor_ensure (preproc); gsk_sl_preprocessor_error_func (preproc->tokenizer, TRUE, - &preproc->location, - &preproc->token, + gsk_sl_preprocessor_get_location (preproc), + gsk_sl_preprocessor_get (preproc), error, NULL); diff --git a/gsk/gsksltokenizer.c b/gsk/gsksltokenizer.c index f4cc8654ed..c304f014a1 100644 --- a/gsk/gsksltokenizer.c +++ b/gsk/gsksltokenizer.c @@ -314,6 +314,256 @@ gsk_sl_token_clear (GskSlToken *token) token->type = GSK_SL_TOKEN_EOF; } +void +gsk_sl_token_copy (GskSlToken *dest, + const GskSlToken *src) +{ + dest->type = src->type; + + switch (src->type) + { + case GSK_SL_TOKEN_IDENTIFIER: + dest->str = g_strdup (src->str); + break; + + case GSK_SL_TOKEN_BOOLCONSTANT: + dest->b = src->b; + break; + + case GSK_SL_TOKEN_FLOATCONSTANT: + dest->f = src->f; + break; + + case GSK_SL_TOKEN_DOUBLECONSTANT: + dest->d = src->d; + break; + + case GSK_SL_TOKEN_INTCONSTANT: + dest->i32 = src->i32; + break; + + case GSK_SL_TOKEN_UINTCONSTANT: + dest->u32 = src->u32; + break; + + case GSK_SL_TOKEN_EOF: + case GSK_SL_TOKEN_ERROR: + case GSK_SL_TOKEN_NEWLINE: + case GSK_SL_TOKEN_WHITESPACE: + case GSK_SL_TOKEN_COMMENT: + case GSK_SL_TOKEN_SINGLE_LINE_COMMENT: + case GSK_SL_TOKEN_CONST: + case GSK_SL_TOKEN_BREAK: + case GSK_SL_TOKEN_CONTINUE: + case GSK_SL_TOKEN_DO: + case GSK_SL_TOKEN_ELSE: + case GSK_SL_TOKEN_FOR: + case GSK_SL_TOKEN_IF: + case GSK_SL_TOKEN_DISCARD: + case GSK_SL_TOKEN_RETURN: + case GSK_SL_TOKEN_SWITCH: + case GSK_SL_TOKEN_CASE: + case GSK_SL_TOKEN_DEFAULT: + case GSK_SL_TOKEN_SUBROUTINE: + 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_MAT2: + case GSK_SL_TOKEN_MAT3: + case GSK_SL_TOKEN_MAT4: + case GSK_SL_TOKEN_CENTROID: + case GSK_SL_TOKEN_IN: + case GSK_SL_TOKEN_OUT: + case GSK_SL_TOKEN_INOUT: + case GSK_SL_TOKEN_UNIFORM: + case GSK_SL_TOKEN_PATCH: + case GSK_SL_TOKEN_SAMPLE: + case GSK_SL_TOKEN_BUFFER: + case GSK_SL_TOKEN_SHARED: + 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_DVEC2: + case GSK_SL_TOKEN_DVEC3: + case GSK_SL_TOKEN_DVEC4: + case GSK_SL_TOKEN_DMAT2: + case GSK_SL_TOKEN_DMAT3: + case GSK_SL_TOKEN_DMAT4: + case GSK_SL_TOKEN_NOPERSPECTIVE: + case GSK_SL_TOKEN_FLAT: + case GSK_SL_TOKEN_SMOOTH: + case GSK_SL_TOKEN_LAYOUT: + 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_ATOMIC_UINT: + case GSK_SL_TOKEN_SAMPLER1D: + case GSK_SL_TOKEN_SAMPLER2D: + case GSK_SL_TOKEN_SAMPLER3D: + case GSK_SL_TOKEN_SAMPLERCUBE: + case GSK_SL_TOKEN_SAMPLER1DSHADOW: + case GSK_SL_TOKEN_SAMPLER2DSHADOW: + case GSK_SL_TOKEN_SAMPLERCUBESHADOW: + case GSK_SL_TOKEN_SAMPLER1DARRAY: + case GSK_SL_TOKEN_SAMPLER2DARRAY: + case GSK_SL_TOKEN_SAMPLER1DARRAYSHADOW: + case GSK_SL_TOKEN_SAMPLER2DARRAYSHADOW: + case GSK_SL_TOKEN_ISAMPLER1D: + case GSK_SL_TOKEN_ISAMPLER2D: + case GSK_SL_TOKEN_ISAMPLER3D: + case GSK_SL_TOKEN_ISAMPLERCUBE: + case GSK_SL_TOKEN_ISAMPLER1DARRAY: + case GSK_SL_TOKEN_ISAMPLER2DARRAY: + case GSK_SL_TOKEN_USAMPLER1D: + case GSK_SL_TOKEN_USAMPLER2D: + case GSK_SL_TOKEN_USAMPLER3D: + case GSK_SL_TOKEN_USAMPLERCUBE: + case GSK_SL_TOKEN_USAMPLER1DARRAY: + case GSK_SL_TOKEN_USAMPLER2DARRAY: + case GSK_SL_TOKEN_SAMPLER2DRECT: + case GSK_SL_TOKEN_SAMPLER2DRECTSHADOW: + case GSK_SL_TOKEN_ISAMPLER2DRECT: + case GSK_SL_TOKEN_USAMPLER2DRECT: + case GSK_SL_TOKEN_SAMPLERBUFFER: + case GSK_SL_TOKEN_ISAMPLERBUFFER: + case GSK_SL_TOKEN_USAMPLERBUFFER: + case GSK_SL_TOKEN_SAMPLERCUBEARRAY: + case GSK_SL_TOKEN_SAMPLERCUBEARRAYSHADOW: + case GSK_SL_TOKEN_ISAMPLERCUBEARRAY: + case GSK_SL_TOKEN_USAMPLERCUBEARRAY: + case GSK_SL_TOKEN_SAMPLER2DMS: + case GSK_SL_TOKEN_ISAMPLER2DMS: + case GSK_SL_TOKEN_USAMPLER2DMS: + case GSK_SL_TOKEN_SAMPLER2DMSARRAY: + case GSK_SL_TOKEN_ISAMPLER2DMSARRAY: + case GSK_SL_TOKEN_USAMPLER2DMSARRAY: + case GSK_SL_TOKEN_IMAGE1D: + case GSK_SL_TOKEN_IIMAGE1D: + case GSK_SL_TOKEN_UIMAGE1D: + case GSK_SL_TOKEN_IMAGE2D: + case GSK_SL_TOKEN_IIMAGE2D: + case GSK_SL_TOKEN_UIMAGE2D: + case GSK_SL_TOKEN_IMAGE3D: + case GSK_SL_TOKEN_IIMAGE3D: + case GSK_SL_TOKEN_UIMAGE3D: + case GSK_SL_TOKEN_IMAGE2DRECT: + case GSK_SL_TOKEN_IIMAGE2DRECT: + case GSK_SL_TOKEN_UIMAGE2DRECT: + case GSK_SL_TOKEN_IMAGECUBE: + case GSK_SL_TOKEN_IIMAGECUBE: + case GSK_SL_TOKEN_UIMAGECUBE: + case GSK_SL_TOKEN_IMAGEBUFFER: + case GSK_SL_TOKEN_IIMAGEBUFFER: + case GSK_SL_TOKEN_UIMAGEBUFFER: + case GSK_SL_TOKEN_IMAGE1DARRAY: + case GSK_SL_TOKEN_IIMAGE1DARRAY: + case GSK_SL_TOKEN_UIMAGE1DARRAY: + case GSK_SL_TOKEN_IMAGE2DARRAY: + case GSK_SL_TOKEN_IIMAGE2DARRAY: + case GSK_SL_TOKEN_UIMAGE2DARRAY: + case GSK_SL_TOKEN_IMAGECUBEARRAY: + case GSK_SL_TOKEN_IIMAGECUBEARRAY: + case GSK_SL_TOKEN_UIMAGECUBEARRAY: + case GSK_SL_TOKEN_IMAGE2DMS: + case GSK_SL_TOKEN_IIMAGE2DMS: + case GSK_SL_TOKEN_UIMAGE2DMS: + case GSK_SL_TOKEN_IMAGE2DMSARRAY: + case GSK_SL_TOKEN_IIMAGE2DMSARRAY: + case GSK_SL_TOKEN_UIMAGE2DMSARRAY: + case GSK_SL_TOKEN_STRUCT: + case GSK_SL_TOKEN_VOID: + case GSK_SL_TOKEN_WHILE: + 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_LEFT_OP: + case GSK_SL_TOKEN_RIGHT_OP: + case GSK_SL_TOKEN_INC_OP: + case GSK_SL_TOKEN_DEC_OP: + case GSK_SL_TOKEN_LE_OP: + case GSK_SL_TOKEN_GE_OP: + case GSK_SL_TOKEN_EQ_OP: + case GSK_SL_TOKEN_NE_OP: + case GSK_SL_TOKEN_AND_OP: + case GSK_SL_TOKEN_OR_OP: + case GSK_SL_TOKEN_XOR_OP: + case GSK_SL_TOKEN_MUL_ASSIGN: + case GSK_SL_TOKEN_DIV_ASSIGN: + case GSK_SL_TOKEN_ADD_ASSIGN: + case GSK_SL_TOKEN_MOD_ASSIGN: + case GSK_SL_TOKEN_LEFT_ASSIGN: + case GSK_SL_TOKEN_RIGHT_ASSIGN: + case GSK_SL_TOKEN_AND_ASSIGN: + case GSK_SL_TOKEN_XOR_ASSIGN: + case GSK_SL_TOKEN_OR_ASSIGN: + case GSK_SL_TOKEN_SUB_ASSIGN: + case GSK_SL_TOKEN_LEFT_PAREN: + case GSK_SL_TOKEN_RIGHT_PAREN: + case GSK_SL_TOKEN_LEFT_BRACKET: + case GSK_SL_TOKEN_RIGHT_BRACKET: + case GSK_SL_TOKEN_LEFT_BRACE: + case GSK_SL_TOKEN_RIGHT_BRACE: + case GSK_SL_TOKEN_DOT: + case GSK_SL_TOKEN_COMMA: + case GSK_SL_TOKEN_COLON: + case GSK_SL_TOKEN_EQUAL: + case GSK_SL_TOKEN_SEMICOLON: + case GSK_SL_TOKEN_BANG: + case GSK_SL_TOKEN_DASH: + case GSK_SL_TOKEN_TILDE: + case GSK_SL_TOKEN_PLUS: + case GSK_SL_TOKEN_STAR: + case GSK_SL_TOKEN_SLASH: + case GSK_SL_TOKEN_PERCENT: + case GSK_SL_TOKEN_LEFT_ANGLE: + case GSK_SL_TOKEN_RIGHT_ANGLE: + case GSK_SL_TOKEN_VERTICAL_BAR: + case GSK_SL_TOKEN_CARET: + case GSK_SL_TOKEN_AMPERSAND: + case GSK_SL_TOKEN_QUESTION: + case GSK_SL_TOKEN_HASH: + case GSK_SL_TOKEN_INVARIANT: + case GSK_SL_TOKEN_PRECISE: + case GSK_SL_TOKEN_HIGH_PRECISION: + case GSK_SL_TOKEN_MEDIUM_PRECISION: + case GSK_SL_TOKEN_LOW_PRECISION: + case GSK_SL_TOKEN_PRECISION: + break; + + default: + g_assert_not_reached (); + break; + } +} + static const char *keywords[] = { [GSK_SL_TOKEN_CONST] = "const", [GSK_SL_TOKEN_BOOL] = "bool", @@ -1484,6 +1734,23 @@ gsk_sl_token_reader_read_identifier (GskSlTokenReader *reader, token->str = g_string_free (string, FALSE); } +gboolean +gsk_sl_string_is_valid_identifier (const char *ident) +{ + guint i; + + if (!is_identifier_start (ident[0])) + return FALSE; + + for (i = 1; ident[i]; i++) + { + if (!is_identifier (ident[i])) + return FALSE; + } + + return TRUE; +} + void gsk_sl_token_init_from_identifier (GskSlToken *token, const char *ident) @@ -1518,6 +1785,16 @@ gsk_sl_token_init_from_identifier (GskSlToken *token, token->str = g_strdup (ident); } +gboolean +gsk_sl_token_is_skipped (const GskSlToken *token) +{ + return gsk_sl_token_is (token, GSK_SL_TOKEN_ERROR) + || gsk_sl_token_is (token, GSK_SL_TOKEN_NEWLINE) + || gsk_sl_token_is (token, GSK_SL_TOKEN_WHITESPACE) + || gsk_sl_token_is (token, GSK_SL_TOKEN_COMMENT) + || gsk_sl_token_is (token, GSK_SL_TOKEN_SINGLE_LINE_COMMENT); +} + void gsk_sl_tokenizer_read_token (GskSlTokenizer *tokenizer, GskSlToken *token) diff --git a/gsk/gsksltokenizerprivate.h b/gsk/gsksltokenizerprivate.h index f39e64fda0..e968d310d1 100644 --- a/gsk/gsksltokenizerprivate.h +++ b/gsk/gsksltokenizerprivate.h @@ -265,11 +265,14 @@ struct _GskSlToken { }; void gsk_sl_token_clear (GskSlToken *token); +void gsk_sl_token_copy (GskSlToken *dest, + const GskSlToken *src); +gboolean gsk_sl_string_is_valid_identifier (const char *ident); void gsk_sl_token_init_from_identifier (GskSlToken *token, const char *ident); -gboolean gsk_sl_token_is_finite (const GskSlToken *token); +gboolean gsk_sl_token_is_skipped (const GskSlToken *token); #define gsk_sl_token_is(token, _type) ((token)->type == (_type)) gboolean gsk_sl_token_is_ident (const GskSlToken *token, const char *ident); diff --git a/gsk/meson.build b/gsk/meson.build index 17b82cc838..292b67f4a9 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -34,6 +34,7 @@ gsk_private_sources = files([ 'gskprivate.c', 'gskprofiler.c', 'gskshaderbuilder.c', + 'gsksldefine.c', 'gskslfunction.c', 'gskslnode.c', 'gskslpreprocessor.c', diff --git a/gtk/glsl.c b/gtk/glsl.c index 16be6201ac..04e8b0ff62 100644 --- a/gtk/glsl.c +++ b/gtk/glsl.c @@ -132,6 +132,41 @@ usage (GOptionContext *ctx) exit (EXIT_FAILURE); } +static gboolean +define (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + GskSlCompiler *compiler = data; + char **tokens; + gboolean result; + + tokens = g_strsplit (value, "=", 2); + + result = gsk_sl_compiler_add_define (compiler, + tokens[0], + tokens[1], + error); + + g_strfreev (tokens); + + return result; +} + +static gboolean +undefine (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + GskSlCompiler *compiler = data; + + gsk_sl_compiler_remove_define (compiler, value); + + return TRUE; +} + int main (int argc, char *argv[]) { @@ -139,13 +174,16 @@ main (int argc, char *argv[]) char **filenames = NULL; char *output_file = NULL; gboolean print = FALSE; - GskSlCompiler *compiler; const GOptionEntry entries[] = { + { "define", 'D', 0, G_OPTION_ARG_CALLBACK, define, "Add a preprocssor definition", "NAME[=VALUE]" }, + { "undef", 'U', 0, G_OPTION_ARG_CALLBACK, undefine, "Cancel previous preprocessor definition", "NAME" }, { "print", 'p', 0, G_OPTION_ARG_NONE, &print, "Print instead of compiling", NULL }, { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output_file, "Output filename", "FILE" }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, "List of input files", "FILE [FILE...]" }, { NULL, } }; + GskSlCompiler *compiler; + GOptionGroup *group; GError *error = NULL; GOutputStream *output; gboolean success = TRUE; @@ -157,7 +195,9 @@ main (int argc, char *argv[]) compiler = gsk_sl_compiler_new (); ctx = g_option_context_new (NULL); - g_option_context_add_main_entries (ctx, entries, NULL); + group = g_option_group_new (NULL, NULL, NULL, g_object_ref (compiler), g_object_unref); + g_option_group_add_entries (group, entries); + g_option_context_set_main_group (ctx, group); if (!g_option_context_parse (ctx, &argc, &argv, &error)) {