[gtk+/wip/otte/shader: 9/9] gskslnode: Add GskSlNodeOperation



commit 72e3d854c75adae0cb9479aabe76ac1c13ee5c84
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 34d3a0d..c37f63a 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_operation_get_return_type (operation->left);
+  rtype = gsk_sl_node_operation_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;
@@ -598,6 +709,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)
@@ -606,7 +905,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]