diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c index 11fa6436d2..14bda0fccd 100644 --- a/gsk/gskslexpression.c +++ b/gsk/gskslexpression.c @@ -171,10 +171,524 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_ASSIGNMENT = { gsk_sl_expression_assignment_write_spv }; -/* BINARY */ +/* MULTIPLICATION */ + +typedef struct _GskSlExpressionMultiplication GskSlExpressionMultiplication; + +struct _GskSlExpressionMultiplication { + GskSlExpression parent; + + GskSlType *type; + GskSlExpression *left; + GskSlExpression *right; +}; + +static void +gsk_sl_expression_multiplication_free (GskSlExpression *expression) +{ + GskSlExpressionMultiplication *multiplication = (GskSlExpressionMultiplication *) expression; + + gsk_sl_expression_unref (multiplication->left); + gsk_sl_expression_unref (multiplication->right); + gsk_sl_type_unref (multiplication->type); + + g_slice_free (GskSlExpressionMultiplication, multiplication); +} + +static void +gsk_sl_expression_multiplication_print (const GskSlExpression *expression, + GskSlPrinter *printer) +{ + GskSlExpressionMultiplication *multiplication = (GskSlExpressionMultiplication *) expression; + + gsk_sl_expression_print (multiplication->left, printer); + gsk_sl_printer_append (printer, " * "); + gsk_sl_expression_print (multiplication->right, printer); +} + +static GskSlType * +gsk_sl_expression_multiplication_get_result_type (GskSlPreprocessor *preproc, + GskSlType *ltype, + GskSlType *rtype) +{ + GskSlScalarType scalar; + + if (gsk_sl_scalar_type_can_convert (gsk_sl_type_get_scalar_type (ltype), + gsk_sl_type_get_scalar_type (rtype))) + scalar = gsk_sl_type_get_scalar_type (ltype); + else if (gsk_sl_scalar_type_can_convert (gsk_sl_type_get_scalar_type (rtype), + gsk_sl_type_get_scalar_type (ltype))) + scalar = gsk_sl_type_get_scalar_type (rtype); + else + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Operand types %s and %s do not share compatible scalar types.", + gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); + return NULL; + } + if (scalar == GSK_SL_BOOL) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Cannot multiply booleans."); + return NULL; + } + + if (gsk_sl_type_is_matrix (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Incompatible dimensions when multiplying %s * %s.", + gsk_sl_type_get_name (ltype), + gsk_sl_type_get_name (rtype)); + return NULL; + } + return gsk_sl_type_get_matrix (scalar, + gsk_sl_type_get_length (rtype), + gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype))); + } + else if (gsk_sl_type_is_vector (rtype)) + { + if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype)) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Matrix column count doesn't match vector length."); + return NULL; + } + return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype))); + } + else if (gsk_sl_type_is_scalar (rtype)) + { + return gsk_sl_type_get_matrix (scalar, + gsk_sl_type_get_length (ltype), + gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype))); + } + else + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Right operand is incompatible type for multiplication."); + return NULL; + } + } + else if (gsk_sl_type_is_vector (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Vector length for %s doesn't match row count for %s", + gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); + return NULL; + } + return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (rtype)); + } + else if (gsk_sl_type_is_vector (rtype)) + { + if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype)) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Vector operands %s and %s to arithmetic multiplication have different length.", + gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); + return NULL; + } + return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (ltype)); + } + else if (gsk_sl_type_is_scalar (rtype)) + { + return gsk_sl_type_get_vector (scalar, + gsk_sl_type_get_length (ltype)); + } + else + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Right operand is incompatible type for multiplication."); + return NULL; + } + } + else if (gsk_sl_type_is_scalar (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + return gsk_sl_type_get_matrix (scalar, + gsk_sl_type_get_length (rtype), + gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))); + } + else if (gsk_sl_type_is_vector (rtype)) + { + return gsk_sl_type_get_vector (scalar, + gsk_sl_type_get_length (rtype)); + } + else if (gsk_sl_type_is_scalar (rtype)) + { + return gsk_sl_type_get_scalar (scalar); + } + else + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Right operand is incompatible type for multiplication."); + return NULL; + } + } + else + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Left operand is incompatible type for multiplication."); + return NULL; + } +} + +static GskSlType * +gsk_sl_expression_multiplication_get_return_type (const GskSlExpression *expression) +{ + GskSlExpressionMultiplication *multiplication = (GskSlExpressionMultiplication *) expression; + + return multiplication->type; +} + +#define GSK_SL_OPERATION_FUNC_SCALAR(func,type,...) \ +static void \ +func (gpointer value, gpointer scalar) \ +{ \ + type x = *(type *) value; \ + type y = *(type *) scalar; \ + __VA_ARGS__ \ + *(type *) value = x; \ +} +GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_multiplication_int, gint32, x *= y;) +GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_multiplication_uint, guint32, x *= y;) +GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_multiplication_float, float, x *= y;) +GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_multiplication_double, double, x *= y;) +static void (* mult_funcs[]) (gpointer, gpointer) = { + [GSK_SL_INT] = gsk_sl_expression_multiplication_int, + [GSK_SL_UINT] = gsk_sl_expression_multiplication_uint, + [GSK_SL_FLOAT] = gsk_sl_expression_multiplication_float, + [GSK_SL_DOUBLE] = gsk_sl_expression_multiplication_double, +}; + +static GskSlValue * +gsk_sl_expression_multiplication_get_constant (const GskSlExpression *expression) +{ + const GskSlExpressionMultiplication *multiplication = (const GskSlExpressionMultiplication *) expression; + GskSlValue *result, *lvalue, *rvalue; + GskSlType *ltype, *rtype; + GskSlScalarType scalar; + + scalar = gsk_sl_type_get_scalar_type (multiplication->type); + lvalue = gsk_sl_expression_get_constant (multiplication->left); + if (lvalue == NULL) + return NULL; + rvalue = gsk_sl_expression_get_constant (multiplication->right); + if (rvalue == NULL) + { + gsk_sl_value_free (lvalue); + return NULL; + } + lvalue = gsk_sl_value_convert_components (lvalue, scalar); + rvalue = gsk_sl_value_convert_components (rvalue, scalar); + ltype = gsk_sl_value_get_type (lvalue); + rtype = gsk_sl_value_get_type (rvalue); + + if ((gsk_sl_type_is_matrix (rtype) && gsk_sl_type_is_matrix (ltype)) || + (gsk_sl_type_is_vector (rtype) && gsk_sl_type_is_matrix (ltype)) || + (gsk_sl_type_is_matrix (rtype) && gsk_sl_type_is_vector (ltype))) + { + gsize c, cols; + gsize r, rows; + gsize i, n; + gpointer data, ldata, rdata; + + result = gsk_sl_value_new (multiplication->type); + data = gsk_sl_value_get_data (result); + ldata = gsk_sl_value_get_data (lvalue); + rdata = gsk_sl_value_get_data (rvalue); + + if (gsk_sl_type_is_vector (rtype)) + { + cols = 1; + rows = gsk_sl_type_get_length (gsk_sl_value_get_type (result)); + n = gsk_sl_type_get_length (rtype); + } + else if (gsk_sl_type_is_vector (ltype)) + { + cols = gsk_sl_type_get_length (gsk_sl_value_get_type (result)); + rows = 1; + n = gsk_sl_type_get_length (ltype); + } + else + { + cols = gsk_sl_type_get_length (gsk_sl_value_get_type (result)); + rows = gsk_sl_type_get_length (gsk_sl_type_get_index_type (gsk_sl_value_get_type (result))); + n = gsk_sl_type_get_length (ltype); + } +#define MATRIXMULT(TYPE) G_STMT_START{\ + for (c = 0; c < cols; c++) \ + { \ + for (r = 0; r < rows; r++) \ + { \ + TYPE result = 0; \ + for (i = 0; i < n; i++) \ + { \ + result += *((TYPE *) rdata + c * n + i) * \ + *((TYPE *) ldata + i * rows + r); \ + } \ + *((TYPE *) data + c * rows + r) = result; \ + } \ + } \ + }G_STMT_END + if (gsk_sl_type_get_scalar_type (multiplication->type) == GSK_SL_DOUBLE) + MATRIXMULT(double); + else + MATRIXMULT(float); + gsk_sl_value_free (lvalue); + gsk_sl_value_free (rvalue); + return result; + } + else + { + /* we can multiply componentwise */ + gsize ln, rn; + + ln = gsk_sl_type_get_n_components (ltype); + rn = gsk_sl_type_get_n_components (rtype); + if (ln == 1) + { + gsk_sl_value_componentwise (rvalue, mult_funcs[scalar], gsk_sl_value_get_data (lvalue)); + gsk_sl_value_free (lvalue); + result = rvalue; + } + else if (rn == 1) + { + gsk_sl_value_componentwise (lvalue, mult_funcs[scalar], gsk_sl_value_get_data (rvalue)); + gsk_sl_value_free (rvalue); + result = lvalue; + } + else + { + guchar *ldata, *rdata; + gsize i, stride; + + stride = gsk_sl_scalar_type_get_size (scalar); + ldata = gsk_sl_value_get_data (lvalue); + rdata = gsk_sl_value_get_data (rvalue); + for (i = 0; i < ln; i++) + { + mult_funcs[scalar] (ldata + i * stride, rdata + i * stride); + } + gsk_sl_value_free (rvalue); + result = lvalue; + } + } + + return result; +} + +static guint32 +gsk_sl_expression_multiplication_write_spv (const GskSlExpression *expression, + GskSpvWriter *writer) +{ + const GskSlExpressionMultiplication *multiplication = (const GskSlExpressionMultiplication *) expression; + GskSlType *ltype, *rtype; + guint32 left_id, right_id, result_id, result_type_id; + + ltype = gsk_sl_expression_get_return_type (multiplication->left); + rtype = gsk_sl_expression_get_return_type (multiplication->right); + + left_id = gsk_sl_expression_write_spv (multiplication->left, writer); + if (gsk_sl_type_get_scalar_type (ltype) != gsk_sl_type_get_scalar_type (multiplication->type)) + { + GskSlType *new_type = gsk_sl_type_get_matrix (gsk_sl_type_get_scalar_type (multiplication->type), + gsk_sl_type_get_length (ltype), + gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype))); + left_id = gsk_spv_writer_add_conversion (writer, left_id, ltype, new_type); + } + right_id = gsk_sl_expression_write_spv (multiplication->right, writer); + if (gsk_sl_type_get_scalar_type (rtype) != gsk_sl_type_get_scalar_type (multiplication->type)) + { + GskSlType *new_type = gsk_sl_type_get_matrix (gsk_sl_type_get_scalar_type (multiplication->type), + gsk_sl_type_get_length (rtype), + gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))); + right_id = gsk_spv_writer_add_conversion (writer, right_id, rtype, new_type); + } + + result_type_id = gsk_spv_writer_get_id_for_type (writer, multiplication->type); + result_id = gsk_spv_writer_next_id (writer); + + if (gsk_sl_type_is_matrix (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_MATRIX_TIMES_MATRIX, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + + return result_id; + } + else if (gsk_sl_type_is_vector (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_VECTOR_TIMES_MATRIX, + (guint32[4]) { result_type_id, + result_id, + right_id, + left_id }); + + return result_id; + } + else if (gsk_sl_type_is_scalar (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_MATRIX_TIMES_SCALAR, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + + return result_id; + } + } + else if (gsk_sl_type_is_vector (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_MATRIX_TIMES_VECTOR, + (guint32[4]) { result_type_id, + result_id, + right_id, + left_id }); + + return result_id; + } + else if (gsk_sl_type_is_vector (rtype)) + { + switch (gsk_sl_type_get_scalar_type (multiplication->type)) + { + case GSK_SL_FLOAT: + case GSK_SL_DOUBLE: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_F_MUL, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + break; + case GSK_SL_INT: + case GSK_SL_UINT: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_I_MUL, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + break; + case GSK_SL_VOID: + case GSK_SL_BOOL: + default: + g_assert_not_reached (); + break; + } + + return result_id; + } + else if (gsk_sl_type_is_scalar (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_VECTOR_TIMES_SCALAR, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + + return result_id; + } + } + else if (gsk_sl_type_is_scalar (ltype)) + { + if (gsk_sl_type_is_matrix (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_MATRIX_TIMES_SCALAR, + (guint32[4]) { result_type_id, + result_id, + right_id, + left_id }); + + return result_id; + } + else if (gsk_sl_type_is_vector (rtype)) + { + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_VECTOR_TIMES_SCALAR, + (guint32[4]) { result_type_id, + result_id, + right_id, + left_id }); + + return result_id; + } + else if (gsk_sl_type_is_scalar (rtype)) + { + switch (gsk_sl_type_get_scalar_type (multiplication->type)) + { + case GSK_SL_FLOAT: + case GSK_SL_DOUBLE: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_F_MUL, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + break; + case GSK_SL_INT: + case GSK_SL_UINT: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_I_MUL, + (guint32[4]) { result_type_id, + result_id, + left_id, + right_id }); + break; + case GSK_SL_VOID: + case GSK_SL_BOOL: + default: + g_assert_not_reached (); + break; + } + + return result_id; + } + } + + g_assert_not_reached (); + + return 0; +} + +static const GskSlExpressionClass GSK_SL_EXPRESSION_MULTIPLICATION = { + gsk_sl_expression_multiplication_free, + gsk_sl_expression_multiplication_print, + gsk_sl_expression_multiplication_get_return_type, + gsk_sl_expression_multiplication_get_constant, + gsk_sl_expression_multiplication_write_spv +}; + +/* OPERATION */ typedef enum { - GSK_SL_OPERATION_MUL, GSK_SL_OPERATION_DIV, GSK_SL_OPERATION_MOD, GSK_SL_OPERATION_ADD, @@ -222,7 +736,6 @@ gsk_sl_expression_operation_print (const GskSlExpression *expression, GskSlPrinter *printer) { const char *op_str[] = { - [GSK_SL_OPERATION_MUL] = " * ", [GSK_SL_OPERATION_DIV] = " / ", [GSK_SL_OPERATION_MOD] = " % ", [GSK_SL_OPERATION_ADD] = " + ", @@ -253,7 +766,6 @@ gsk_sl_expression_operation_print (const GskSlExpression *expression, static GskSlType * gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream, - gboolean multiply, GskSlType *ltype, GskSlType *rtype) { @@ -280,60 +792,30 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream, { if (gsk_sl_type_is_matrix (rtype)) { - if (multiply) + if (gsk_sl_type_can_convert (ltype, rtype)) { - if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))) - { - if (stream) - gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, - "Matrices to multiplication have incompatible dimensions."); - return NULL; - } - return gsk_sl_type_get_matrix (scalar, - gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype)), - gsk_sl_type_get_length (rtype)); + return ltype; } - else + else if (gsk_sl_type_can_convert (rtype, ltype)) { - if (gsk_sl_type_can_convert (ltype, rtype)) - { - return ltype; - } - else if (gsk_sl_type_can_convert (rtype, ltype)) - { - return rtype; - } - else - { - if (stream) - gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, - "Matrix types %s and %s have different size.", - gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); - return NULL; - } - } - } - else if (gsk_sl_type_is_vector (rtype)) - { - if (multiply) - { - if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype)) - { - if (stream) - gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, - "Matrix column count doesn't match vector length."); - return NULL; - } - return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype))); + return rtype; } else { if (stream) gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, - "Cannot perform arithmetic operation between matrix and vector."); + "Matrix types %s and %s have different size.", + gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); return NULL; } } + else if (gsk_sl_type_is_vector (rtype)) + { + if (stream) + gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, + "Cannot perform arithmetic operation between matrix and vector."); + return NULL; + } else if (gsk_sl_type_is_scalar (rtype)) { return gsk_sl_type_get_matrix (scalar, @@ -352,24 +834,9 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream, { if (gsk_sl_type_is_matrix (rtype)) { - if (multiply) - { - if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (gsk_sl_type_get_index_type (rtype))) - { - if (stream) - gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, - "Vector length for %s doesn't match row count for %s", - gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype)); - return NULL; - } - return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (rtype)); - } - else - { - if (stream) - gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, "Cannot perform arithmetic operation between vector and matrix."); - return NULL; - } + if (stream) + gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, "Cannot perform arithmetic operation between vector and matrix."); + return NULL; } else if (gsk_sl_type_is_vector (rtype)) { @@ -568,16 +1035,10 @@ gsk_sl_expression_operation_get_return_type (const GskSlExpression *expression) switch (operation->op) { - case GSK_SL_OPERATION_MUL: - return gsk_sl_expression_arithmetic_type_check (NULL, - TRUE, - gsk_sl_expression_get_return_type (operation->left), - gsk_sl_expression_get_return_type (operation->right)); case GSK_SL_OPERATION_DIV: case GSK_SL_OPERATION_ADD: case GSK_SL_OPERATION_SUB: return gsk_sl_expression_arithmetic_type_check (NULL, - FALSE, gsk_sl_expression_get_return_type (operation->left), gsk_sl_expression_get_return_type (operation->right)); case GSK_SL_OPERATION_LSHIFT: @@ -2321,9 +2782,8 @@ gsk_sl_expression_parse_multiplicative (GskSlScope *scope, GskSlPreprocessor *stream) { const GskSlToken *token; - GskSlExpression *expression; - GskSlExpressionOperation *operation; - GskSlOperation op; + GskSlExpression *expression, *right; + enum { MUL, DIV, MOD } op; expression = gsk_sl_expression_parse_unary (scope, stream); @@ -2331,35 +2791,72 @@ gsk_sl_expression_parse_multiplicative (GskSlScope *scope, { token = gsk_sl_preprocessor_get (stream); if (gsk_sl_token_is (token, GSK_SL_TOKEN_STAR)) - op = GSK_SL_OPERATION_MUL; + op = MUL; else if (gsk_sl_token_is (token, GSK_SL_TOKEN_SLASH)) - op = GSK_SL_OPERATION_DIV; + op = DIV; else if (gsk_sl_token_is (token, GSK_SL_TOKEN_PERCENT)) - op = GSK_SL_OPERATION_MOD; + op = MOD; else return expression; - operation = gsk_sl_expression_new (GskSlExpressionOperation, &GSK_SL_EXPRESSION_OPERATION); - operation->left = expression; - operation->op = op; - gsk_sl_preprocessor_consume (stream, (GskSlExpression *) operation); - operation->right = gsk_sl_expression_parse_unary (scope, stream); - if ((op == GSK_SL_OPERATION_MOD && - !gsk_sl_expression_bitwise_type_check (stream, - gsk_sl_expression_get_return_type (operation->left), - gsk_sl_expression_get_return_type (operation->right))) || - (op != GSK_SL_OPERATION_MOD && - !gsk_sl_expression_arithmetic_type_check (stream, - FALSE, - gsk_sl_expression_get_return_type (operation->left), - gsk_sl_expression_get_return_type (operation->right)))) + gsk_sl_preprocessor_consume (stream, NULL); + right = gsk_sl_expression_parse_unary (scope, stream); + if (op == MUL) { - gsk_sl_expression_ref (expression); - gsk_sl_expression_unref ((GskSlExpression *) operation); + GskSlType *result_type; + + result_type = gsk_sl_expression_multiplication_get_result_type (stream, + gsk_sl_expression_get_return_type (expression), + gsk_sl_expression_get_return_type (right)); + if (result_type) + { + GskSlExpressionMultiplication *multiplication; + multiplication = gsk_sl_expression_new (GskSlExpressionMultiplication, &GSK_SL_EXPRESSION_MULTIPLICATION); + multiplication->type = gsk_sl_type_ref (result_type); + multiplication->left = expression; + multiplication->right = right; + expression = (GskSlExpression *) multiplication; + } + else + { + gsk_sl_expression_unref ((GskSlExpression *) right); + } + } + else if (op == DIV) + { + if (gsk_sl_expression_arithmetic_type_check (stream, + gsk_sl_expression_get_return_type (expression), + gsk_sl_expression_get_return_type (right))) + { + GskSlExpressionOperation *operation; + operation = gsk_sl_expression_new (GskSlExpressionOperation, &GSK_SL_EXPRESSION_OPERATION); + operation->op = GSK_SL_OPERATION_DIV; + operation->left = expression; + operation->right = right; + expression = (GskSlExpression *) operation; + } + else + { + gsk_sl_expression_unref ((GskSlExpression *) right); + } } else { - expression = (GskSlExpression *) operation; + if (gsk_sl_expression_bitwise_type_check (stream, + gsk_sl_expression_get_return_type (expression), + gsk_sl_expression_get_return_type (right))) + { + GskSlExpressionOperation *operation; + operation = gsk_sl_expression_new (GskSlExpressionOperation, &GSK_SL_EXPRESSION_OPERATION); + operation->op = GSK_SL_OPERATION_MOD; + operation->left = expression; + operation->right = right; + expression = (GskSlExpression *) operation; + } + else + { + gsk_sl_expression_unref ((GskSlExpression *) right); + } } } @@ -2395,7 +2892,6 @@ gsk_sl_expression_parse_additive (GskSlScope *scope, gsk_sl_preprocessor_consume (stream, (GskSlExpression *) operation); operation->right = gsk_sl_expression_parse_additive (scope, stream); if (!gsk_sl_expression_arithmetic_type_check (stream, - FALSE, gsk_sl_expression_get_return_type (operation->left), gsk_sl_expression_get_return_type (operation->right))) {