diff options
author | Benjamin Otte <otte@redhat.com> | 2017-10-24 00:42:41 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2017-10-30 02:58:03 +0100 |
commit | ab91b013d5ca2e0820b8692eca189b16e6283398 (patch) | |
tree | dcb0fc61988bbe345dd16462ec18ecbdd5b5bb8c | |
parent | 30c040a87c5b692c4a3a8a4be29b3805454d1caa (diff) | |
download | gtk+-ab91b013d5ca2e0820b8692eca189b16e6283398.tar.gz |
gskslexpression: Implement initializers
So now this works:
float array[3] = { 1, 2, 3 };
-rw-r--r-- | gsk/gsksldeclaration.c | 2 | ||||
-rw-r--r-- | gsk/gskslexpression.c | 311 | ||||
-rw-r--r-- | gsk/gskslexpressionprivate.h | 5 | ||||
-rw-r--r-- | gsk/gskslstatement.c | 2 | ||||
-rw-r--r-- | testsuite/gsksl/errors/too-few-initializers-in-array.glsl | 5 | ||||
-rw-r--r-- | testsuite/gsksl/errors/too-few-initializers-in-struct.glsl | 10 | ||||
-rw-r--r-- | testsuite/gsksl/errors/too-many-initializers-in-array.glsl | 5 | ||||
-rw-r--r-- | testsuite/gsksl/errors/too-many-initializers-in-struct.glsl | 10 |
8 files changed, 345 insertions, 5 deletions
diff --git a/gsk/gsksldeclaration.c b/gsk/gsksldeclaration.c index 8c32be1868..0e80659ccb 100644 --- a/gsk/gsksldeclaration.c +++ b/gsk/gsksldeclaration.c @@ -239,7 +239,7 @@ gsk_sl_declaration_parse_variable (GskSlScope *scope, { gsk_sl_preprocessor_consume (preproc, NULL); - initial = gsk_sl_expression_parse_assignment (scope, preproc); + initial = gsk_sl_expression_parse_initializer (scope, preproc, type); if (!gsk_sl_type_can_convert (type, gsk_sl_expression_get_return_type (initial))) { diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c index 3af18614db..c0ffdecc14 100644 --- a/gsk/gskslexpression.c +++ b/gsk/gskslexpression.c @@ -1213,6 +1213,177 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_CONSTRUCTOR = { gsk_sl_expression_default_get_spv_access_chain }; +/* INITIALIZER */ + +typedef struct _GskSlExpressionInitializer GskSlExpressionInitializer; + +struct _GskSlExpressionInitializer { + GskSlExpression parent; + + GskSlType *type; + GskSlExpression **arguments; + guint n_arguments; +}; + +static void +gsk_sl_expression_initializer_free (GskSlExpression *expression) +{ + GskSlExpressionInitializer *initializer = (GskSlExpressionInitializer *) expression; + guint i; + + for (i = 0; i < initializer->n_arguments; i++) + { + gsk_sl_expression_unref (initializer->arguments[i]); + } + g_free (initializer->arguments); + + gsk_sl_type_unref (initializer->type); + + g_slice_free (GskSlExpressionInitializer, initializer); +} + +static void +gsk_sl_expression_initializer_print (const GskSlExpression *expression, + GskSlPrinter *printer) +{ + const GskSlExpressionInitializer *initializer = (const GskSlExpressionInitializer *) expression; + guint i; + + gsk_sl_printer_append (printer, "{"); + + for (i = 0; i < initializer->n_arguments; i++) + { + if (i > 0) + gsk_sl_printer_append (printer, ", "); + gsk_sl_expression_print (initializer->arguments[i], printer); + } + + gsk_sl_printer_append (printer, "}"); +} + +static GskSlType * +gsk_sl_expression_initializer_get_return_type (const GskSlExpression *expression) +{ + const GskSlExpressionInitializer *initializer = (const GskSlExpressionInitializer *) expression; + + return initializer->type; +} + +static GskSlValue * +gsk_sl_expression_initializer_get_constant (const GskSlExpression *expression) +{ + const GskSlExpressionInitializer *initializer = (const GskSlExpressionInitializer *) expression; + GskSlType *type = initializer->type; + GskSlValue *values[initializer->n_arguments]; + GskSlValue *result; + gsize i; + + for (i = 0; i < initializer->n_arguments; i++) + { + values[i] = gsk_sl_expression_get_constant (initializer->arguments[i]); + if (values[i] == NULL) + { + guint j; + for (j = 0; j < i; j++) + gsk_sl_value_free (values[j]); + return NULL; + } + } + + result = gsk_sl_value_new (type); + + if (gsk_sl_type_get_length (type)) + { + GskSlType *index_type = gsk_sl_type_get_index_type (type); + gsize stride = gsk_sl_type_get_index_stride (type); + gsize size = gsk_sl_type_get_size (index_type); + guchar *data = gsk_sl_value_get_data (result); + + for (i = 0; i < gsk_sl_type_get_length (type); i++) + { + if (!gsk_sl_type_equal (gsk_sl_value_get_type (values[i]), index_type)) + { + GskSlValue *tmp = gsk_sl_value_new_convert (values[i], index_type); + gsk_sl_value_free (values[i]); + values[i] = tmp; + } + memcpy (data + i * stride, gsk_sl_value_get_data (values[i]), size); + gsk_sl_value_free (values[i]); + } + } + else + { + guchar *data = gsk_sl_value_get_data (result); + + for (i = 0; i < gsk_sl_type_get_n_members (type); i++) + { + GskSlType *member_type = gsk_sl_type_get_member_type (type, i); + + if (!gsk_sl_type_equal (gsk_sl_value_get_type (values[i]), member_type)) + { + GskSlValue *tmp = gsk_sl_value_new_convert (values[i], member_type); + gsk_sl_value_free (values[i]); + values[i] = tmp; + } + memcpy (data + gsk_sl_type_get_member_offset (type, i), + gsk_sl_value_get_data (values[i]), + gsk_sl_type_get_size (member_type)); + gsk_sl_value_free (values[i]); + } + } + + return result; +} + +static guint32 +gsk_sl_expression_initializer_write_spv (const GskSlExpression *expression, + GskSpvWriter *writer) +{ + const GskSlExpressionInitializer *initializer = (const GskSlExpressionInitializer *) expression; + GskSlType *type = initializer->type; + guint32 ids[initializer->n_arguments]; + gsize i; + + if (gsk_sl_type_get_length (type)) + { + GskSlType *index_type = gsk_sl_type_get_index_type (type); + + for (i = 0; i < gsk_sl_type_get_length (type); i++) + { + ids[i] = gsk_sl_expression_write_spv (initializer->arguments[i], writer, index_type); + } + + return gsk_spv_writer_composite_construct (writer, + type, + ids, + gsk_sl_type_get_length (type)); + } + else + { + for (i = 0; i < gsk_sl_type_get_n_members (type); i++) + { + ids[i] = gsk_sl_expression_write_spv (initializer->arguments[i], + writer, + gsk_sl_type_get_member_type (type, i)); + } + + return gsk_spv_writer_composite_construct (writer, + type, + ids, + gsk_sl_type_get_n_members (type)); + } +} + +static const GskSlExpressionClass GSK_SL_EXPRESSION_INITIALIZER = { + gsk_sl_expression_initializer_free, + gsk_sl_expression_initializer_print, + gsk_sl_expression_default_is_assignable, + gsk_sl_expression_initializer_get_return_type, + gsk_sl_expression_initializer_get_constant, + gsk_sl_expression_initializer_write_spv, + gsk_sl_expression_default_get_spv_access_chain +}; + /* FUNCTION_CALL */ typedef struct _GskSlExpressionFunctionCall GskSlExpressionFunctionCall; @@ -2003,6 +2174,10 @@ gsk_sl_expression_error_new (void) return (GskSlExpression *) constant; } +static GskSlExpression * +gsk_sl_expression_parse_assignment (GskSlScope *scope, + GskSlPreprocessor *preproc); + GskSlExpression * gsk_sl_expression_parse_constructor (GskSlScope *scope, GskSlPreprocessor *stream, @@ -3382,7 +3557,7 @@ gsk_sl_expression_parse_integral_constant (GskSlScope *scope, } } -GskSlExpression * +static GskSlExpression * gsk_sl_expression_parse_assignment (GskSlScope *scope, GskSlPreprocessor *preproc) { @@ -3469,6 +3644,140 @@ gsk_sl_expression_parse_assignment (GskSlScope *scope, return (GskSlExpression *) assign; } +static GskSlExpression * +gsk_sl_expression_parse_initializer_array (GskSlScope *scope, + GskSlPreprocessor *preproc, + GskSlType *type) +{ + GskSlExpressionInitializer *initializer; + GskSlType *index_type = gsk_sl_type_get_index_type (type); + const GskSlToken *token; + gsize i; + + initializer = gsk_sl_expression_new (GskSlExpressionInitializer, &GSK_SL_EXPRESSION_INITIALIZER); + initializer->type = gsk_sl_type_ref (type); + initializer->n_arguments = gsk_sl_type_get_length (type); + initializer->arguments = g_new0 (GskSlExpression *, initializer->n_arguments); + + for (i = 0; i < initializer->n_arguments; i++) + { + if (i > 0) + { + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA)) + gsk_sl_preprocessor_consume (preproc, NULL); + else + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \",\" and next initializer"); + break; + } + } + + initializer->arguments[i] = gsk_sl_expression_parse_initializer (scope, preproc, index_type); + + if (!gsk_sl_type_can_convert (index_type, gsk_sl_expression_get_return_type (initializer->arguments[i]))) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Cannot convert from %s to %s.", + gsk_sl_type_get_name (gsk_sl_expression_get_return_type (initializer->arguments[i])), + gsk_sl_type_get_name (index_type)); + } + } + + return (GskSlExpression *) initializer; +} + +static GskSlExpression * +gsk_sl_expression_parse_initializer_members (GskSlScope *scope, + GskSlPreprocessor *preproc, + GskSlType *type) +{ + GskSlExpressionInitializer *initializer; + const GskSlToken *token; + gsize i; + + initializer = gsk_sl_expression_new (GskSlExpressionInitializer, &GSK_SL_EXPRESSION_INITIALIZER); + initializer->type = gsk_sl_type_ref (type); + initializer->n_arguments = gsk_sl_type_get_n_members (type); + initializer->arguments = g_new0 (GskSlExpression *, initializer->n_arguments); + + for (i = 0; i < initializer->n_arguments; i++) + { + GskSlType *member_type = gsk_sl_type_get_member_type (type, i); + + if (i > 0) + { + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA)) + gsk_sl_preprocessor_consume (preproc, NULL); + else + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \",\" and next initializer"); + break; + } + } + + initializer->arguments[i] = gsk_sl_expression_parse_initializer (scope, preproc, member_type); + + if (!gsk_sl_type_can_convert (member_type, gsk_sl_expression_get_return_type (initializer->arguments[i]))) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Cannot convert from %s to %s.", + gsk_sl_type_get_name (gsk_sl_expression_get_return_type (initializer->arguments[i])), + gsk_sl_type_get_name (member_type)); + } + } + + return (GskSlExpression *) initializer; +} + +GskSlExpression * +gsk_sl_expression_parse_initializer (GskSlScope *scope, + GskSlPreprocessor *preproc, + GskSlType *type) +{ + const GskSlToken *token; + + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE)) + { + GskSlExpression *expression; + + gsk_sl_preprocessor_consume (preproc, NULL); + + if (gsk_sl_type_get_length (type)) + { + expression = gsk_sl_expression_parse_initializer_array (scope, preproc, type); + } + else if (gsk_sl_type_get_n_members (type)) + { + expression = gsk_sl_expression_parse_initializer_members (scope, preproc, type); + } + else + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Cannot use initializer on %s", gsk_sl_type_get_name (type)); + gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_BRACE); + expression = gsk_sl_expression_error_new (); + } + + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA)) + { + gsk_sl_preprocessor_consume (preproc, NULL); + token = gsk_sl_preprocessor_get (preproc); + } + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE)) + { + gsk_sl_preprocessor_error (preproc, SYNTAX, "Too many elements in initializer for %s", gsk_sl_type_get_name (type)); + gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_RIGHT_BRACE); + } + gsk_sl_preprocessor_consume (preproc, NULL); + + return expression; + } + + return gsk_sl_expression_parse_assignment (scope, preproc); +} + GskSlExpression * gsk_sl_expression_parse (GskSlScope *scope, GskSlPreprocessor *stream) diff --git a/gsk/gskslexpressionprivate.h b/gsk/gskslexpressionprivate.h index ccc1ebd728..e0235bc9c2 100644 --- a/gsk/gskslexpressionprivate.h +++ b/gsk/gskslexpressionprivate.h @@ -25,8 +25,9 @@ G_BEGIN_DECLS GskSlExpression * gsk_sl_expression_parse (GskSlScope *scope, GskSlPreprocessor *stream); -GskSlExpression * gsk_sl_expression_parse_assignment (GskSlScope *scope, - GskSlPreprocessor *stream); +GskSlExpression * gsk_sl_expression_parse_initializer (GskSlScope *scope, + GskSlPreprocessor *preproc, + GskSlType *type); GskSlExpression * gsk_sl_expression_parse_constant (GskSlScope *scope, GskSlPreprocessor *stream); gint32 gsk_sl_expression_parse_integral_constant (GskSlScope *scope, diff --git a/gsk/gskslstatement.c b/gsk/gskslstatement.c index 488ceeb8eb..cdb1b5db59 100644 --- a/gsk/gskslstatement.c +++ b/gsk/gskslstatement.c @@ -705,7 +705,7 @@ gsk_sl_statement_parse_declaration (GskSlScope *scope, GskSlValue *unconverted; gsk_sl_preprocessor_consume (stream, (GskSlStatement *) declaration); - declaration->initial = gsk_sl_expression_parse_assignment (scope, stream); + declaration->initial = gsk_sl_expression_parse_initializer (scope, stream, type); if (!gsk_sl_type_can_convert (type, gsk_sl_expression_get_return_type (declaration->initial))) { gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, diff --git a/testsuite/gsksl/errors/too-few-initializers-in-array.glsl b/testsuite/gsksl/errors/too-few-initializers-in-array.glsl new file mode 100644 index 0000000000..7b54c62994 --- /dev/null +++ b/testsuite/gsksl/errors/too-few-initializers-in-array.glsl @@ -0,0 +1,5 @@ +void +main () +{ + vec4 v = { 1, 2, 3, }; +} diff --git a/testsuite/gsksl/errors/too-few-initializers-in-struct.glsl b/testsuite/gsksl/errors/too-few-initializers-in-struct.glsl new file mode 100644 index 0000000000..b76f6761bd --- /dev/null +++ b/testsuite/gsksl/errors/too-few-initializers-in-struct.glsl @@ -0,0 +1,10 @@ +struct S { + vec2 v; + float f; +}; + +void +main () +{ + S s = { { 1, 2 } }; +} diff --git a/testsuite/gsksl/errors/too-many-initializers-in-array.glsl b/testsuite/gsksl/errors/too-many-initializers-in-array.glsl new file mode 100644 index 0000000000..af5d289230 --- /dev/null +++ b/testsuite/gsksl/errors/too-many-initializers-in-array.glsl @@ -0,0 +1,5 @@ +void +main () +{ + vec2 v = { 1, 2, 3 }; +} diff --git a/testsuite/gsksl/errors/too-many-initializers-in-struct.glsl b/testsuite/gsksl/errors/too-many-initializers-in-struct.glsl new file mode 100644 index 0000000000..91a7019588 --- /dev/null +++ b/testsuite/gsksl/errors/too-many-initializers-in-struct.glsl @@ -0,0 +1,10 @@ +struct S { + vec2 v; + float f; +}; + +void +main () +{ + S s = { { 1, 2 }, 3, 4 }; +} |