summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2017-10-23 04:37:28 +0200
committerBenjamin Otte <otte@redhat.com>2017-10-30 02:58:03 +0100
commitc2773ef8039d0c83e85b15cdba22a68a476a0647 (patch)
tree5df3b6e6373aaca27718a221931aee0cb5fda823
parent9275cec20420c733972adc9649965bc4c57ef23e (diff)
downloadgtk+-c2773ef8039d0c83e85b15cdba22a68a476a0647.tar.gz
gskslexpression: Implement conditional expressions
Is_with_tests ? Commit_it : Commit_it_anyway
-rw-r--r--gsk/gskslexpression.c222
-rw-r--r--testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl7
-rw-r--r--testsuite/gsksl/errors/incompatible-types-in-conditional.glsl7
-rw-r--r--testsuite/gsksl/errors/missing-colon-in-conditional.glsl7
4 files changed, 240 insertions, 3 deletions
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index 1bdd61c1c0..08ca15f010 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -605,6 +605,149 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_LOGICAL_OR = {
gsk_sl_expression_default_get_spv_access_chain
};
+/* CONDITIONAL */
+
+typedef struct _GskSlExpressionConditional GskSlExpressionConditional;
+
+struct _GskSlExpressionConditional {
+ GskSlExpression parent;
+
+ GskSlExpression *condition;
+ GskSlType *type;
+ GskSlExpression *left;
+ GskSlExpression *right;
+};
+
+static void
+gsk_sl_expression_conditional_free (GskSlExpression *expression)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ gsk_sl_expression_unref (conditional->condition);
+ gsk_sl_type_unref (conditional->type);
+ gsk_sl_expression_unref (conditional->left);
+ gsk_sl_expression_unref (conditional->right);
+
+ g_slice_free (GskSlExpressionConditional, conditional);
+}
+
+static void
+gsk_sl_expression_conditional_print (const GskSlExpression *expression,
+ GskSlPrinter *printer)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ gsk_sl_expression_print (conditional->condition, printer);
+ gsk_sl_printer_append (printer, " ? ");
+ gsk_sl_expression_print (conditional->left, printer);
+ gsk_sl_printer_append (printer, " : ");
+ gsk_sl_expression_print (conditional->right, printer);
+}
+
+static GskSlType *
+gsk_sl_expression_conditional_get_return_type (const GskSlExpression *expression)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ return conditional->type;
+}
+
+static GskSlValue *
+gsk_sl_expression_conditional_get_constant (const GskSlExpression *expression)
+{
+ const GskSlExpressionConditional *conditional = (const GskSlExpressionConditional *) expression;
+ GskSlValue *cond, *lvalue, *rvalue;
+
+ cond = gsk_sl_expression_get_constant (conditional->condition);
+ if (cond == NULL)
+ return NULL;
+ lvalue = gsk_sl_expression_get_constant (conditional->left);
+ if (lvalue == NULL)
+ {
+ gsk_sl_value_free (cond);
+ return NULL;
+ }
+ rvalue = gsk_sl_expression_get_constant (conditional->right);
+ if (rvalue == NULL)
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (lvalue);
+ return NULL;
+ }
+
+ if (*(guint32 *) gsk_sl_value_get_data (cond))
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (rvalue);
+ return lvalue;
+ }
+ else
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (lvalue);
+ return rvalue;
+ }
+}
+
+static guint32
+gsk_sl_expression_conditional_write_spv (const GskSlExpression *expression,
+ GskSpvWriter *writer)
+{
+ const GskSlExpressionConditional *conditional = (const GskSlExpressionConditional *) expression;
+ guint32 true_id, false_id, after_id;
+ guint32 condition_id, left_id, right_id, result_id;
+
+ condition_id = gsk_sl_expression_write_spv (conditional->condition, writer);
+
+ true_id = gsk_spv_writer_make_id (writer);
+ false_id = gsk_spv_writer_make_id (writer);
+ after_id = gsk_spv_writer_make_id (writer);
+
+ gsk_spv_writer_selection_merge (writer, after_id, 0);
+ gsk_spv_writer_branch_conditional (writer, condition_id, true_id, false_id, NULL, 0);
+
+ gsk_spv_writer_start_code_block (writer, true_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, true_id);
+ left_id = gsk_sl_expression_write_spv (conditional->left, writer);
+ left_id = gsk_spv_writer_convert (writer,
+ left_id,
+ gsk_sl_expression_get_return_type (conditional->left),
+ conditional->type);
+ gsk_spv_writer_branch (writer, after_id);
+
+ gsk_spv_writer_start_code_block (writer, false_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, false_id);
+ right_id = gsk_sl_expression_write_spv (conditional->right, writer);
+ right_id = gsk_spv_writer_convert (writer,
+ right_id,
+ gsk_sl_expression_get_return_type (conditional->right),
+ conditional->type);
+ gsk_spv_writer_branch (writer, after_id);
+
+ gsk_spv_writer_start_code_block (writer, after_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, after_id);
+
+ result_id = gsk_spv_writer_phi (writer,
+ conditional->type,
+ (guint32 **) (guint32[4][2]) {
+ { left_id, true_id },
+ { right_id, false_id }
+ },
+ 2);
+
+ return result_id;
+}
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_CONDITIONAL = {
+ gsk_sl_expression_conditional_free,
+ gsk_sl_expression_conditional_print,
+ gsk_sl_expression_default_is_assignable,
+ gsk_sl_expression_conditional_get_return_type,
+ gsk_sl_expression_conditional_get_constant,
+ gsk_sl_expression_conditional_write_spv,
+ gsk_sl_expression_default_get_spv_access_chain
+};
+
/* REFERENCE */
typedef struct _GskSlExpressionReference GskSlExpressionReference;
@@ -3099,10 +3242,83 @@ gsk_sl_expression_parse_logical_or (GskSlScope *scope,
static GskSlExpression *
gsk_sl_expression_parse_conditional (GskSlScope *scope,
- GskSlPreprocessor *stream)
+ GskSlPreprocessor *preproc)
{
- /* XXX: support conditionals */
- return gsk_sl_expression_parse_logical_or (scope, stream);
+ GskSlExpressionConditional *conditional;
+ GskSlExpression *expr, *left, *right;
+ GskSlType *type, *expr_type, *left_type, *right_type;
+ const GskSlToken *token;
+ gboolean success = TRUE;
+
+ expr = gsk_sl_expression_parse_logical_or (scope, preproc);
+
+ token = gsk_sl_preprocessor_get (preproc);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_QUESTION))
+ return expr;
+ gsk_sl_preprocessor_consume (preproc, NULL);
+
+ expr_type = gsk_sl_expression_get_return_type (expr);
+ if (!gsk_sl_type_equal (expr_type, gsk_sl_type_get_scalar (GSK_SL_BOOL)))
+ {
+ gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+ "Condition in conditional expression returns %s, not bool",
+ gsk_sl_type_get_name (expr_type));
+ success = FALSE;
+ }
+ else
+ {
+ GskSlValue *value = gsk_sl_expression_get_constant (expr);
+
+ if (value)
+ {
+ gsk_sl_preprocessor_warn (preproc, CONSTANT,
+ "Conditional expression is always %s",
+ *(guint32 *) gsk_sl_value_get_data (value) ? "true" : "false");
+ gsk_sl_value_free (value);
+ }
+ }
+
+ left = gsk_sl_expression_parse (scope, preproc);
+
+ token = gsk_sl_preprocessor_get (preproc);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COLON))
+ {
+ gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \":\" while parsing conditional expression");
+ gsk_sl_expression_unref (expr);
+ return left;
+ }
+ gsk_sl_preprocessor_consume (preproc, NULL);
+
+ right = gsk_sl_expression_parse_assignment (scope, preproc);
+
+ left_type = gsk_sl_expression_get_return_type (left);
+ right_type = gsk_sl_expression_get_return_type (right);
+ if (gsk_sl_type_can_convert (left_type, right_type))
+ type = left_type;
+ else if (gsk_sl_type_can_convert (right_type, left_type))
+ type = right_type;
+ else
+ {
+ gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+ "Types %s and %s in conditional expression are not compatible.",
+ gsk_sl_type_get_name (left_type), gsk_sl_type_get_name (right_type));
+ success = FALSE;
+ }
+
+ if (!success)
+ {
+ gsk_sl_expression_unref (expr);
+ gsk_sl_expression_unref (right);
+ return left;
+ }
+
+ conditional = gsk_sl_expression_new (GskSlExpressionConditional, &GSK_SL_EXPRESSION_CONDITIONAL);
+ conditional->condition = expr;
+ conditional->type = gsk_sl_type_ref (type);
+ conditional->left = left;
+ conditional->right = right;
+
+ return (GskSlExpression *) conditional;
}
GskSlExpression *
diff --git a/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl b/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl
new file mode 100644
index 0000000000..cae267b16f
--- /dev/null
+++ b/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ int b;
+ int y = b ? 1 : 0;
+}
diff --git a/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl b/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl
new file mode 100644
index 0000000000..64403a142c
--- /dev/null
+++ b/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ bool b;
+ int y = b ? 1 : true;
+}
diff --git a/testsuite/gsksl/errors/missing-colon-in-conditional.glsl b/testsuite/gsksl/errors/missing-colon-in-conditional.glsl
new file mode 100644
index 0000000000..ed714b44aa
--- /dev/null
+++ b/testsuite/gsksl/errors/missing-colon-in-conditional.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ bool b;
+ int y = b ? 1;
+}