diff options
author | Benjamin Otte <otte@redhat.com> | 2017-10-23 04:37:28 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2017-10-30 02:58:03 +0100 |
commit | c2773ef8039d0c83e85b15cdba22a68a476a0647 (patch) | |
tree | 5df3b6e6373aaca27718a221931aee0cb5fda823 | |
parent | 9275cec20420c733972adc9649965bc4c57ef23e (diff) | |
download | gtk+-c2773ef8039d0c83e85b15cdba22a68a476a0647.tar.gz |
gskslexpression: Implement conditional expressions
Is_with_tests ? Commit_it : Commit_it_anyway
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; +} |