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



commit c1c166541984083e7fe80a92125bda1cc6ad49f0
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 ddaf2b6..a5a06e8 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,
+                                 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_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_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_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_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_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_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_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_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_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_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_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_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,
                                          GskSlPreprocessor *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 eb9da5c..10303d0 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 5337e38..6acae51 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -47,6 +47,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]