diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c index e53dd6b921..06a5e433d2 100644 --- a/gsk/gskslnode.c +++ b/gsk/gskslnode.c @@ -269,6 +269,117 @@ static const GskSlNodeClass GSK_SL_NODE_ASSIGNMENT = { gsk_sl_node_assignment_is_constant }; +/* BINARY */ + +typedef enum { + GSK_SL_OPERATION_MUL, + GSK_SL_OPERATION_DIV, + GSK_SL_OPERATION_MOD, + GSK_SL_OPERATION_ADD, + GSK_SL_OPERATION_SUB, + GSK_SL_OPERATION_LSHIFT, + GSK_SL_OPERATION_RSHIFT, + GSK_SL_OPERATION_LESS, + GSK_SL_OPERATION_GREATER, + GSK_SL_OPERATION_LESS_EQUAL, + GSK_SL_OPERATION_GREATER_EQUAL, + GSK_SL_OPERATION_EQUAL, + GSK_SL_OPERATION_NOT_EQUAL, + GSK_SL_OPERATION_AND, + GSK_SL_OPERATION_XOR, + GSK_SL_OPERATION_OR, + GSK_SL_OPERATION_LOGICAL_AND, + GSK_SL_OPERATION_LOGICAL_XOR, + GSK_SL_OPERATION_LOGICAL_OR +} GskSlOperation; + +typedef struct _GskSlNodeOperation GskSlNodeOperation; + +struct _GskSlNodeOperation { + GskSlNode parent; + + GskSlOperation op; + GskSlNode *left; + GskSlNode *right; +}; + +static void +gsk_sl_node_operation_free (GskSlNode *node) +{ + GskSlNodeOperation *operation = (GskSlNodeOperation *) node; + + gsk_sl_node_unref (operation->left); + if (operation->right) + gsk_sl_node_unref (operation->right); + + g_slice_free (GskSlNodeOperation, operation); +} + +static void +gsk_sl_node_operation_print (GskSlNode *node, + GString *string) +{ + const char *op_str[] = { + [GSK_SL_OPERATION_MUL] = " * ", + [GSK_SL_OPERATION_DIV] = " / ", + [GSK_SL_OPERATION_MOD] = " % ", + [GSK_SL_OPERATION_ADD] = " + ", + [GSK_SL_OPERATION_SUB] = " - ", + [GSK_SL_OPERATION_LSHIFT] = " << ", + [GSK_SL_OPERATION_RSHIFT] = " >> ", + [GSK_SL_OPERATION_LESS] = " < ", + [GSK_SL_OPERATION_GREATER] = " > ", + [GSK_SL_OPERATION_LESS_EQUAL] = " <= ", + [GSK_SL_OPERATION_GREATER_EQUAL] = " >= ", + [GSK_SL_OPERATION_EQUAL] = " == ", + [GSK_SL_OPERATION_NOT_EQUAL] = " != ", + [GSK_SL_OPERATION_AND] = " & ", + [GSK_SL_OPERATION_XOR] = " ^ ", + [GSK_SL_OPERATION_OR] = " | ", + [GSK_SL_OPERATION_LOGICAL_AND] = " && ", + [GSK_SL_OPERATION_LOGICAL_XOR] = " ^^ ", + [GSK_SL_OPERATION_LOGICAL_OR] = " || " + }; + GskSlNodeOperation *operation = (GskSlNodeOperation *) node; + + /* XXX: figure out the need for bracketing here */ + + gsk_sl_node_print (operation->left, string); + g_string_append (string, op_str[operation->op]); + gsk_sl_node_print (operation->right, string); +} + +static GskSlType * +gsk_sl_node_operation_get_return_type (GskSlNode *node) +{ + GskSlNodeOperation *operation = (GskSlNodeOperation *) node; + GskSlType *ltype, *rtype; + + ltype = gsk_sl_node_get_return_type (operation->left); + rtype = gsk_sl_node_get_return_type (operation->right); + + if (gsk_sl_type_can_convert (ltype, rtype)) + return ltype; + else + return rtype; +} + +static gboolean +gsk_sl_node_operation_is_constant (GskSlNode *node) +{ + GskSlNodeOperation *operation = (GskSlNodeOperation *) node; + + return gsk_sl_node_is_constant (operation->left) + && gsk_sl_node_is_constant (operation->right); +} + +static const GskSlNodeClass GSK_SL_NODE_OPERATION = { + gsk_sl_node_operation_free, + gsk_sl_node_operation_print, + gsk_sl_node_operation_get_return_type, + gsk_sl_node_operation_is_constant +}; + /* DECLARATION */ typedef struct _GskSlNodeDeclaration GskSlNodeDeclaration; @@ -398,7 +509,7 @@ typedef struct _GskSlNodeConstant GskSlNodeConstant; struct _GskSlNodeConstant { GskSlNode parent; - GskSlBuiltinType type; + GskSlScalarType type; union { gint32 i32; guint32 u32; @@ -453,10 +564,6 @@ gsk_sl_node_constant_print (GskSlNode *node, break; case GSK_SL_VOID: - case GSK_SL_VEC2: - case GSK_SL_VEC3: - case GSK_SL_VEC4: - case GSK_SL_N_BUILTIN_TYPES: default: g_assert_not_reached (); break; @@ -468,7 +575,7 @@ gsk_sl_node_constant_get_return_type (GskSlNode *node) { GskSlNodeConstant *constant = (GskSlNodeConstant *) node; - return gsk_sl_type_get_builtin (constant->type); + return gsk_sl_type_get_scalar (constant->type); } static gboolean @@ -605,6 +712,194 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program, } } +static GskSlNode * +gsk_sl_node_parse_or_expression (GskSlNodeProgram *program, + GskSlScope *scope, + GskSlPreprocessor *stream) +{ + return gsk_sl_node_parse_primary_expression (program, scope, stream); +} + +static GskSlNode * +gsk_sl_node_parse_logical_and_expression (GskSlNodeProgram *program, + GskSlScope *scope, + GskSlPreprocessor *stream) +{ + const GskSlToken *token; + GskSlNode *node; + GskSlNodeOperation *operation; + + node = gsk_sl_node_parse_or_expression (program, scope, stream); + if (node == NULL) + return NULL; + + while (TRUE) + { + token = gsk_sl_preprocessor_get (stream); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_AND_OP)) + return node; + + operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION); + operation->left = node; + operation->op = GSK_SL_OPERATION_LOGICAL_AND; + gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation); + operation->right = gsk_sl_node_parse_or_expression (program, scope, stream); + if (operation->right == NULL) + { + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (operation->right))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (operation->right)); + gsk_sl_preprocessor_error (stream, "Right operand of && expression is not bool but %s", type_name); + g_free (type_name); + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (node))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (node)); + gsk_sl_preprocessor_error (stream, "Left operand of && expression is not bool but %s", type_name); + g_free (type_name); + node = operation->right; + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else + { + node = (GskSlNode *) operation; + } + } + + return node; +} + +static GskSlNode * +gsk_sl_node_parse_logical_xor_expression (GskSlNodeProgram *program, + GskSlScope *scope, + GskSlPreprocessor *stream) +{ + const GskSlToken *token; + GskSlNode *node; + GskSlNodeOperation *operation; + + node = gsk_sl_node_parse_logical_and_expression (program, scope, stream); + if (node == NULL) + return NULL; + + while (TRUE) + { + token = gsk_sl_preprocessor_get (stream); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_XOR_OP)) + return node; + + operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION); + operation->left = node; + operation->op = GSK_SL_OPERATION_LOGICAL_XOR; + gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation); + operation->right = gsk_sl_node_parse_logical_and_expression (program, scope, stream); + if (operation->right == NULL) + { + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (operation->right))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (operation->right)); + gsk_sl_preprocessor_error (stream, "Right operand of || expression is not bool but %s", type_name); + g_free (type_name); + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (node))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (node)); + gsk_sl_preprocessor_error (stream, "Left operand of || expression is not bool but %s", type_name); + g_free (type_name); + node = operation->right; + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else + { + node = (GskSlNode *) operation; + } + } + + return node; +} + +static GskSlNode * +gsk_sl_node_parse_logical_or_expression (GskSlNodeProgram *program, + GskSlScope *scope, + GskSlPreprocessor *stream) +{ + const GskSlToken *token; + GskSlNode *node; + GskSlNodeOperation *operation; + + node = gsk_sl_node_parse_logical_xor_expression (program, scope, stream); + if (node == NULL) + return NULL; + + while (TRUE) + { + token = gsk_sl_preprocessor_get (stream); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_OR_OP)) + return node; + + operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION); + operation->left = node; + operation->op = GSK_SL_OPERATION_LOGICAL_OR; + gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation); + operation->right = gsk_sl_node_parse_logical_xor_expression (program, scope, stream); + if (operation->right == NULL) + { + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (operation->right))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (operation->right)); + gsk_sl_preprocessor_error (stream, "Right operand of ^^ expression is not bool but %s", type_name); + g_free (type_name); + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else if (!gsk_sl_type_can_convert (gsk_sl_type_get_scalar (GSK_SL_BOOL), + gsk_sl_node_get_return_type (node))) + { + char *type_name = gsk_sl_type_to_string (gsk_sl_node_get_return_type (node)); + gsk_sl_preprocessor_error (stream, "Left operand of ^^ expression is not bool but %s", type_name); + g_free (type_name); + node = operation->right; + gsk_sl_node_ref (node); + gsk_sl_node_unref ((GskSlNode *) operation); + } + else + { + node = (GskSlNode *) operation; + } + } + + return node; +} + +static GskSlNode * +gsk_sl_node_parse_conditional_expression (GskSlNodeProgram *program, + GskSlScope *scope, + GskSlPreprocessor *stream) +{ + /* XXX: support conditionals */ + return gsk_sl_node_parse_logical_or_expression (program, scope, stream); +} + static GskSlNode * gsk_sl_node_parse_assignment_expression (GskSlNodeProgram *program, GskSlScope *scope, @@ -614,7 +909,7 @@ gsk_sl_node_parse_assignment_expression (GskSlNodeProgram *program, GskSlNode *lvalue; GskSlNodeAssignment *assign; - lvalue = gsk_sl_node_parse_primary_expression (program, scope, stream); + lvalue = gsk_sl_node_parse_conditional_expression (program, scope, stream); if (lvalue == NULL) return NULL; diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c index 5edfbc694a..dcd55bcc55 100644 --- a/gsk/gsksltype.c +++ b/gsk/gsksltype.c @@ -25,30 +25,143 @@ #include +#define N_SCALAR_TYPES 6 + +typedef struct _GskSlTypeClass GskSlTypeClass; + struct _GskSlType { - int ref_count; + const GskSlTypeClass *class; - GskSlBuiltinType builtin; + int ref_count; }; -static GskSlType -builtin_types[GSK_SL_N_BUILTIN_TYPES] = { - [GSK_SL_VOID] = { 1, GSK_SL_VOID }, - [GSK_SL_FLOAT] = { 1, GSK_SL_FLOAT }, - [GSK_SL_DOUBLE] = { 1, GSK_SL_DOUBLE }, - [GSK_SL_INT] = { 1, GSK_SL_INT }, - [GSK_SL_UINT] = { 1, GSK_SL_UINT }, - [GSK_SL_BOOL] = { 1, GSK_SL_BOOL }, - [GSK_SL_VEC2] = { 1, GSK_SL_VEC2 }, - [GSK_SL_VEC3] = { 1, GSK_SL_VEC3 }, - [GSK_SL_VEC4] = { 1, GSK_SL_VEC4 } +struct _GskSlTypeClass { + void (* free) (GskSlType *type); + + void (* print) (const GskSlType *type, + GString *string); + GskSlScalarType (* get_scalar_type) (const GskSlType *type); + gboolean (* can_convert) (const GskSlType *target, + const GskSlType *source); +}; + +static gboolean +gsk_sl_scalar_type_can_convert (GskSlScalarType target, + GskSlScalarType source) +{ + if (target == source) + return TRUE; + + switch (source) + { + case GSK_SL_INT: + return target == GSK_SL_UINT + || target == GSK_SL_FLOAT + || target == GSK_SL_DOUBLE; + case GSK_SL_UINT: + return target == GSK_SL_FLOAT + || target == GSK_SL_DOUBLE; + case GSK_SL_FLOAT: + return target == GSK_SL_DOUBLE; + case GSK_SL_DOUBLE: + case GSK_SL_BOOL: + case GSK_SL_VOID: + default: + return FALSE; + } +} + +/* SCALAR */ + +typedef struct _GskSlTypeScalar GskSlTypeScalar; + +struct _GskSlTypeScalar { + GskSlType parent; + + GskSlScalarType scalar; +}; + +static void +gsk_sl_type_scalar_free (GskSlType *type) +{ + g_assert_not_reached (); +} + +static void +gsk_sl_type_scalar_print (const GskSlType *type, + GString *string) +{ + GskSlTypeScalar *scalar = (GskSlTypeScalar *) type; + + switch (scalar->scalar) + { + case GSK_SL_VOID: + g_string_append (string, "void"); + break; + case GSK_SL_FLOAT: + g_string_append (string, "float"); + break; + case GSK_SL_DOUBLE: + g_string_append (string, "double"); + break; + case GSK_SL_INT: + g_string_append (string, "int"); + break; + case GSK_SL_UINT: + g_string_append (string, "uint"); + break; + case GSK_SL_BOOL: + g_string_append (string, "bool"); + break; + default: + g_assert_not_reached (); + break; + } +} + +static GskSlScalarType +gsk_sl_type_scalar_get_scalar_type (const GskSlType *type) +{ + GskSlTypeScalar *scalar = (GskSlTypeScalar *) type; + + return scalar->scalar; +} + +static gboolean +gsk_sl_type_scalar_can_convert (const GskSlType *target, + const GskSlType *source) +{ + const GskSlTypeScalar *target_scalar = (const GskSlTypeScalar *) target; + const GskSlTypeScalar *source_scalar = (const GskSlTypeScalar *) source; + + if (target->class != source->class) + return FALSE; + + return gsk_sl_scalar_type_can_convert (target_scalar->scalar, source_scalar->scalar); +} + +static const GskSlTypeClass GSK_SL_TYPE_SCALAR = { + gsk_sl_type_scalar_free, + gsk_sl_type_scalar_print, + gsk_sl_type_scalar_get_scalar_type, + gsk_sl_type_scalar_can_convert +}; + +static GskSlTypeScalar +builtin_types[N_SCALAR_TYPES] = { + [GSK_SL_VOID] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_VOID }, + [GSK_SL_FLOAT] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_FLOAT }, + [GSK_SL_DOUBLE] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_DOUBLE }, + [GSK_SL_INT] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_INT }, + [GSK_SL_UINT] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_UINT }, + [GSK_SL_BOOL] = { { &GSK_SL_TYPE_SCALAR, 1 }, GSK_SL_BOOL }, }; GskSlType * gsk_sl_type_new_parse (GskSlPreprocessor *stream) { - GskSlBuiltinType builtin; + GskSlType *type; const GskSlToken *token; token = gsk_sl_preprocessor_get (stream); @@ -56,31 +169,22 @@ gsk_sl_type_new_parse (GskSlPreprocessor *stream) switch ((guint) token->type) { case GSK_SL_TOKEN_VOID: - builtin = GSK_SL_VOID; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_VOID)); break; case GSK_SL_TOKEN_FLOAT: - builtin = GSK_SL_FLOAT; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT)); break; case GSK_SL_TOKEN_DOUBLE: - builtin = GSK_SL_DOUBLE; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_DOUBLE)); break; case GSK_SL_TOKEN_INT: - builtin = GSK_SL_INT; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_INT)); break; case GSK_SL_TOKEN_UINT: - builtin = GSK_SL_UINT; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_UINT)); break; case GSK_SL_TOKEN_BOOL: - builtin = GSK_SL_BOOL; - break; - case GSK_SL_TOKEN_VEC2: - builtin = GSK_SL_VEC2; - break; - case GSK_SL_TOKEN_VEC3: - builtin = GSK_SL_VEC3; - break; - case GSK_SL_TOKEN_VEC4: - builtin = GSK_SL_VEC4; + type = gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_BOOL)); break; default: gsk_sl_preprocessor_error (stream, "Expected type specifier"); @@ -88,15 +192,16 @@ gsk_sl_type_new_parse (GskSlPreprocessor *stream) } gsk_sl_preprocessor_consume (stream, NULL); - return gsk_sl_type_ref (gsk_sl_type_get_builtin (builtin)); + + return type; } GskSlType * -gsk_sl_type_get_builtin (GskSlBuiltinType builtin) +gsk_sl_type_get_scalar (GskSlScalarType scalar) { - g_assert (builtin < GSK_SL_N_BUILTIN_TYPES); + g_assert (scalar < N_SCALAR_TYPES); - return &builtin_types[builtin]; + return &builtin_types[scalar].parent; } GskSlType * @@ -119,46 +224,30 @@ gsk_sl_type_unref (GskSlType *type) if (type->ref_count > 0) return; - g_assert_not_reached (); + type->class->free (type); } void gsk_sl_type_print (const GskSlType *type, GString *string) { - switch (type->builtin) - { - case GSK_SL_VOID: - g_string_append (string, "void"); - break; - case GSK_SL_FLOAT: - g_string_append (string, "float"); - break; - case GSK_SL_DOUBLE: - g_string_append (string, "double"); - break; - case GSK_SL_INT: - g_string_append (string, "int"); - break; - case GSK_SL_UINT: - g_string_append (string, "uint"); - break; - case GSK_SL_BOOL: - g_string_append (string, "bool"); - break; - case GSK_SL_VEC2: - g_string_append (string, "vec2"); - break; - case GSK_SL_VEC3: - g_string_append (string, "vec3"); - break; - case GSK_SL_VEC4: - g_string_append (string, "vec4"); - break; - /* add more above */ - case GSK_SL_N_BUILTIN_TYPES: - default: - g_assert_not_reached (); - break; - } + return type->class->print (type, string); } + +char * +gsk_sl_type_to_string (const GskSlType *type) +{ + GString *string; + + string = g_string_new (NULL); + gsk_sl_type_print (type, string); + return g_string_free (string, FALSE); +} + +gboolean +gsk_sl_type_can_convert (const GskSlType *target, + const GskSlType *source) +{ + return target->class->can_convert (target, source); +} + diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h index 5337e38aa3..238db3e0f5 100644 --- a/gsk/gsksltypeprivate.h +++ b/gsk/gsksltypeprivate.h @@ -31,22 +31,21 @@ typedef enum { GSK_SL_DOUBLE, GSK_SL_INT, GSK_SL_UINT, - GSK_SL_BOOL, - GSK_SL_VEC2, - GSK_SL_VEC3, - GSK_SL_VEC4, - /* add more above */ - GSK_SL_N_BUILTIN_TYPES -} GskSlBuiltinType; + GSK_SL_BOOL +} GskSlScalarType; GskSlType * gsk_sl_type_new_parse (GskSlPreprocessor *stream); -GskSlType * gsk_sl_type_get_builtin (GskSlBuiltinType builtin); +GskSlType * gsk_sl_type_get_scalar (GskSlScalarType scalar); GskSlType * gsk_sl_type_ref (GskSlType *type); void gsk_sl_type_unref (GskSlType *type); void gsk_sl_type_print (const GskSlType *type, GString *string); +char * gsk_sl_type_to_string (const GskSlType *type); + +gboolean gsk_sl_type_can_convert (const GskSlType *target, + const GskSlType *source); G_END_DECLS