summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2017-10-24 00:42:41 +0200
committerBenjamin Otte <otte@redhat.com>2017-10-30 02:58:03 +0100
commitab91b013d5ca2e0820b8692eca189b16e6283398 (patch)
treedcb0fc61988bbe345dd16462ec18ecbdd5b5bb8c
parent30c040a87c5b692c4a3a8a4be29b3805454d1caa (diff)
downloadgtk+-ab91b013d5ca2e0820b8692eca189b16e6283398.tar.gz
gskslexpression: Implement initializers
So now this works: float array[3] = { 1, 2, 3 };
-rw-r--r--gsk/gsksldeclaration.c2
-rw-r--r--gsk/gskslexpression.c311
-rw-r--r--gsk/gskslexpressionprivate.h5
-rw-r--r--gsk/gskslstatement.c2
-rw-r--r--testsuite/gsksl/errors/too-few-initializers-in-array.glsl5
-rw-r--r--testsuite/gsksl/errors/too-few-initializers-in-struct.glsl10
-rw-r--r--testsuite/gsksl/errors/too-many-initializers-in-array.glsl5
-rw-r--r--testsuite/gsksl/errors/too-many-initializers-in-struct.glsl10
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 };
+}