[gtk+/wip/otte/shader: 2/12] gskslnode: Add GskSlNodeOperation
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/shader: 2/12] gskslnode: Add GskSlNodeOperation
- Date: Mon, 18 Sep 2017 17:43:52 +0000 (UTC)
commit d09b2e1dd1f43a2fc8095df955c43087518cfdef
Author: Benjamin Otte <otte redhat com>
Date: Sun Sep 17 06:00:49 2017 +0200
gskslnode: Add GskSlNodeOperation
This is for operations in expressions, like and, or, shift, addition or
multiplication.
These operations need to do sophisticated type checks that can't be done
yet, so only the logical operations are implemented so far.
gsk/gskslnode.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++-
gsk/gsksltype.c | 33 ++++++
gsk/gsksltypeprivate.h | 4 +
3 files changed, 337 insertions(+), 1 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 6712789..8d76292 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;
@@ -601,6 +712,194 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
}
static GskSlNode *
+gsk_sl_node_parse_or_expression (GskSlNodeProgram *program,
+ GskSlScope *scope,
+ GskSlTokenStream *stream)
+{
+ return gsk_sl_node_parse_primary_expression (program, scope, stream);
+}
+
+static GskSlNode *
+gsk_sl_node_parse_logical_and_expression (GskSlNodeProgram *program,
+ GskSlScope *scope,
+ GskSlTokenStream *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_token_stream_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_token_stream_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_builtin (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_token_stream_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_builtin (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_token_stream_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,
+ GskSlTokenStream *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_token_stream_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_token_stream_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_builtin (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_token_stream_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_builtin (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_token_stream_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,
+ GskSlTokenStream *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_token_stream_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_token_stream_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_builtin (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_token_stream_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_builtin (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_token_stream_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,
+ GskSlTokenStream *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,
GskSlTokenStream *stream)
@@ -609,7 +908,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 b978fe5..4ab562a 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -162,3 +162,36 @@ gsk_sl_type_print (const GskSlType *type,
break;
}
}
+
+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)
+{
+ if (target->builtin == source->builtin)
+ return TRUE;
+
+ switch (source->builtin)
+ {
+ case GSK_SL_INT:
+ return target->builtin == GSK_SL_UINT
+ || target->builtin == GSK_SL_FLOAT
+ || target->builtin == GSK_SL_DOUBLE;
+ case GSK_SL_UINT:
+ return target->builtin == GSK_SL_FLOAT
+ || target->builtin == GSK_SL_DOUBLE;
+ case GSK_SL_FLOAT:
+ return target->builtin == GSK_SL_DOUBLE;
+ default:
+ return FALSE;
+ }
+}
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index da4f0f3..45f4fd2 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -49,6 +49,10 @@ void gsk_sl_type_unref (GskSlType
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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]