[gtk+/wip/otte/shader: 11/150] gskslnode: Add comparison and shift operators



commit 4e7e5f52c1c2e37ece8ae3d68be12ab2d109b4fd
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 17 17:45:34 2017 +0200

    gskslnode: Add comparison and shift operators

 gsk/gskslnode.c        |  535 +++++++++++++++++++++++++++++++++++++++++++++++-
 gsk/gsksltype.c        |   84 ++++++---
 gsk/gsksltypeprivate.h |    3 +
 3 files changed, 586 insertions(+), 36 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 27461ef..7eb8384 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -350,6 +350,174 @@ gsk_sl_node_operation_print (GskSlNode *node,
 }
 
 static GskSlType *
+gsk_sl_node_arithmetic_type_check (GskSlPreprocessor *stream,
+                                   gboolean           multiply,
+                                   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
+    {
+      if (stream)
+        {
+          char *lstr = gsk_sl_type_to_string (ltype);
+          char *rstr = gsk_sl_type_to_string (rtype);
+          gsk_sl_preprocessor_error (stream, "Operand types %s and %s do not share compatible scalar 
types.", lstr, rstr);
+          g_free (lstr);
+          g_free (rstr);
+        }
+      return NULL;
+    }
+
+  if (gsk_sl_type_is_matrix (ltype))
+    {
+      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, "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));
+            }
+          else
+            {
+              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, "Matrices to arithmetic operation have different 
size.");
+                  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, "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 (stream)
+                gsk_sl_preprocessor_error (stream, "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,
+                                         gsk_sl_type_get_length (ltype),
+                                         gsk_sl_type_get_length (gsk_sl_type_get_index_type (ltype)));
+        }
+      else
+        {
+          if (stream)
+            gsk_sl_preprocessor_error (stream, "Right operand is incompatible type for arithemtic 
operation.");
+          return NULL;
+        }
+    }
+  else if (gsk_sl_type_is_vector (ltype))
+    {
+      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, "Vector length doesn't match matrix row count.");
+                  return NULL;
+                }
+              return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (rtype));
+            }
+          else
+            {
+              if (stream)
+                gsk_sl_preprocessor_error (stream, "Cannot perform arithmetic operation between vector and 
matrix.");
+              return NULL;
+            }
+        }
+      else if (gsk_sl_type_is_vector (rtype))
+        {
+          if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype))
+            {
+              if (stream)
+                gsk_sl_preprocessor_error (stream, "Vector operands to arithmetic operation have different 
length.");
+              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
+        {
+          if (stream)
+            gsk_sl_preprocessor_error (stream, "Right operand is incompatible type for arithemtic 
operation.");
+          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
+        {
+          if (stream)
+            gsk_sl_preprocessor_error (stream, "Right operand is incompatible type for arithemtic 
operation.");
+          return NULL;
+        }
+    }
+  else
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Left operand is incompatible type for arithemtic operation.");
+      return NULL;
+    }
+}
+
+static GskSlType *
 gsk_sl_node_bitwise_type_check (GskSlPreprocessor *stream,
                                 GskSlType         *ltype,
                                 GskSlType         *rtype)
@@ -397,6 +565,90 @@ gsk_sl_node_bitwise_type_check (GskSlPreprocessor *stream,
     return gsk_sl_type_get_vector (rscalar, gsk_sl_type_get_length (ltype));
 }
 
+static gboolean
+gsk_sl_node_shift_type_check (GskSlPreprocessor *stream,
+                              GskSlType         *ltype,
+                              GskSlType         *rtype)
+{
+  GskSlScalarType lscalar, rscalar;
+
+  lscalar = gsk_sl_type_get_scalar_type (ltype);
+  if (lscalar != GSK_SL_INT && lscalar != GSK_SL_UINT)
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Left operand is not an integer type.");
+      return FALSE;
+    }
+  rscalar = gsk_sl_type_get_scalar_type (ltype);
+  if (rscalar != GSK_SL_INT && rscalar != GSK_SL_UINT)
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Right operand is not an integer type.");
+      return FALSE;
+    }
+  if (!gsk_sl_type_is_scalar (ltype) && !gsk_sl_type_is_vector (ltype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Left operand is neither a scalar nor a vector.");
+      return FALSE;
+    }
+  if (!gsk_sl_type_is_scalar (rtype) && !gsk_sl_type_is_vector (rtype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Right operand is neither a scalar nor a vector.");
+      return FALSE;
+    }
+  if (gsk_sl_type_is_scalar (ltype) && gsk_sl_type_is_vector (rtype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Right operand to shift cannot be a vector if left operand is a 
scalar.");
+      return FALSE;
+    }
+  if (gsk_sl_type_is_vector (ltype) && gsk_sl_type_is_vector (rtype) &&
+      gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Vector operands do not have the same length.");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+gsk_sl_node_relational_type_check (GskSlPreprocessor *stream,
+                                   GskSlType        *ltype,
+                                   GskSlType        *rtype)
+{
+  if (!gsk_sl_type_is_scalar (ltype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Left operand to relational operator is not a scalar.");
+      return FALSE;
+    }
+  if (gsk_sl_type_get_scalar_type (ltype) == GSK_SL_BOOL)
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Left operand to relational operator must not be bool.");
+      return FALSE;
+    }
+  if (!gsk_sl_type_is_scalar (rtype))
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Right operand to relational operator is not a scalar.");
+      return FALSE;
+    }
+  if (gsk_sl_type_get_scalar_type (rtype) == GSK_SL_BOOL)
+    {
+      if (stream)
+        gsk_sl_preprocessor_error (stream, "Right operand to relational operator must not be bool.");
+      return FALSE;
+    }
+
+
+  return TRUE;
+}
+
 static GskSlType *
 gsk_sl_node_operation_get_return_type (GskSlNode *node)
 {
@@ -405,26 +657,33 @@ gsk_sl_node_operation_get_return_type (GskSlNode *node)
   switch (operation->op)
   {
     case GSK_SL_OPERATION_MUL:
+      return gsk_sl_node_arithmetic_type_check (NULL,
+                                                TRUE,
+                                                gsk_sl_node_get_return_type (operation->left),
+                                                gsk_sl_node_get_return_type (operation->right));
     case GSK_SL_OPERATION_DIV:
-    case GSK_SL_OPERATION_MOD:
     case GSK_SL_OPERATION_ADD:
     case GSK_SL_OPERATION_SUB:
+      return gsk_sl_node_arithmetic_type_check (NULL,
+                                                FALSE,
+                                                gsk_sl_node_get_return_type (operation->left),
+                                                gsk_sl_node_get_return_type (operation->right));
     case GSK_SL_OPERATION_LSHIFT:
     case GSK_SL_OPERATION_RSHIFT:
-    case GSK_SL_OPERATION_LESS:
-    case GSK_SL_OPERATION_GREATER:
-    case GSK_SL_OPERATION_LESS_EQUAL:
-    case GSK_SL_OPERATION_GREATER_EQUAL:
-    case GSK_SL_OPERATION_EQUAL:
-    case GSK_SL_OPERATION_NOT_EQUAL:
-      g_assert_not_reached ();
-      return NULL;
+      return gsk_sl_node_get_return_type (operation->left);
+    case GSK_SL_OPERATION_MOD:
     case GSK_SL_OPERATION_AND:
     case GSK_SL_OPERATION_XOR:
     case GSK_SL_OPERATION_OR:
       return gsk_sl_node_bitwise_type_check (NULL,
                                              gsk_sl_node_get_return_type (operation->left),
                                              gsk_sl_node_get_return_type (operation->right));
+    case GSK_SL_OPERATION_LESS:
+    case GSK_SL_OPERATION_GREATER:
+    case GSK_SL_OPERATION_LESS_EQUAL:
+    case GSK_SL_OPERATION_GREATER_EQUAL:
+    case GSK_SL_OPERATION_EQUAL:
+    case GSK_SL_OPERATION_NOT_EQUAL:
     case GSK_SL_OPERATION_LOGICAL_AND:
     case GSK_SL_OPERATION_LOGICAL_XOR:
     case GSK_SL_OPERATION_LOGICAL_OR:
@@ -784,11 +1043,267 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram  *program,
 }
 
 static GskSlNode *
+gsk_sl_node_parse_unary_expression (GskSlNodeProgram  *program,
+                                    GskSlScope        *scope,
+                                    GskSlPreprocessor *stream)
+{
+  return gsk_sl_node_parse_primary_expression (program, scope, stream);
+}
+
+static GskSlNode *
+gsk_sl_node_parse_multiplicative_expression (GskSlNodeProgram  *program,
+                                             GskSlScope        *scope,
+                                             GskSlPreprocessor *stream)
+{
+  const GskSlToken *token;
+  GskSlNode *node;
+  GskSlNodeOperation *operation;
+  GskSlOperation op;
+
+  node = gsk_sl_node_parse_unary_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_STAR))
+        op = GSK_SL_OPERATION_MUL;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_SLASH))
+        op = GSK_SL_OPERATION_DIV;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_PERCENT))
+        op = GSK_SL_OPERATION_MOD;
+      else
+        return node;
+
+      operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION);
+      operation->left = node;
+      operation->op = op;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation);
+      operation->right = gsk_sl_node_parse_unary_expression (program, scope, stream);
+      if (operation->right == NULL)
+        {
+          gsk_sl_node_ref (node);
+          gsk_sl_node_unref ((GskSlNode *) operation);
+        }
+      else if ((op == GSK_SL_OPERATION_MOD &&
+                !gsk_sl_node_bitwise_type_check (stream,
+                                                 gsk_sl_node_get_return_type (operation->left),
+                                                 gsk_sl_node_get_return_type (operation->right))) ||
+               (op != GSK_SL_OPERATION_MOD &&
+                !gsk_sl_node_arithmetic_type_check (stream,
+                                                    FALSE,
+                                                    gsk_sl_node_get_return_type (operation->left),
+                                                    gsk_sl_node_get_return_type (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_additive_expression (GskSlNodeProgram  *program,
+                                       GskSlScope        *scope,
+                                       GskSlPreprocessor *stream)
+{
+  const GskSlToken *token;
+  GskSlNode *node;
+  GskSlNodeOperation *operation;
+  GskSlOperation op;
+
+  node = gsk_sl_node_parse_multiplicative_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_PLUS))
+        op = GSK_SL_OPERATION_ADD;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_DASH))
+        op = GSK_SL_OPERATION_SUB;
+      else
+        return node;
+
+      operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION);
+      operation->left = node;
+      operation->op = op;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation);
+      operation->right = gsk_sl_node_parse_additive_expression (program, scope, stream);
+      if (operation->right == NULL)
+        {
+          gsk_sl_node_ref (node);
+          gsk_sl_node_unref ((GskSlNode *) operation);
+        }
+      else if (!gsk_sl_node_arithmetic_type_check (stream,
+                                                   FALSE,
+                                                   gsk_sl_node_get_return_type (operation->left),
+                                                   gsk_sl_node_get_return_type (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_shift_expression (GskSlNodeProgram  *program,
+                                    GskSlScope        *scope,
+                                    GskSlPreprocessor *stream)
+{
+  const GskSlToken *token;
+  GskSlNode *node;
+  GskSlNodeOperation *operation;
+  GskSlOperation op;
+
+  node = gsk_sl_node_parse_additive_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_LEFT_OP))
+        op = GSK_SL_OPERATION_LSHIFT;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_OP))
+        op = GSK_SL_OPERATION_RSHIFT;
+      else
+        return node;
+
+      operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION);
+      operation->left = node;
+      operation->op = op;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation);
+      operation->right = gsk_sl_node_parse_additive_expression (program, scope, stream);
+      if (operation->right == NULL)
+        {
+          gsk_sl_node_ref (node);
+          gsk_sl_node_unref ((GskSlNode *) operation);
+        }
+      else if (!gsk_sl_node_shift_type_check (stream,
+                                              gsk_sl_node_get_return_type (operation->left),
+                                              gsk_sl_node_get_return_type (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_relational_expression (GskSlNodeProgram  *program,
+                                         GskSlScope        *scope,
+                                         GskSlPreprocessor *stream)
+{
+  const GskSlToken *token;
+  GskSlNode *node;
+  GskSlNodeOperation *operation;
+  GskSlOperation op;
+
+  node = gsk_sl_node_parse_shift_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_LEFT_ANGLE))
+        op = GSK_SL_OPERATION_LESS;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_ANGLE))
+        op = GSK_SL_OPERATION_GREATER;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_LE_OP))
+        op = GSK_SL_OPERATION_LESS_EQUAL;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_GE_OP))
+        op = GSK_SL_OPERATION_GREATER_EQUAL;
+      else
+        return node;
+
+      operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION);
+      operation->left = node;
+      operation->op = op;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation);
+      operation->right = gsk_sl_node_parse_shift_expression (program, scope, stream);
+      if (operation->right == NULL)
+        {
+          gsk_sl_node_ref (node);
+          gsk_sl_node_unref ((GskSlNode *) operation);
+        }
+      else if (!gsk_sl_node_relational_type_check (stream,
+                                                   gsk_sl_node_get_return_type (operation->left),
+                                                   gsk_sl_node_get_return_type (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_equality_expression (GskSlNodeProgram  *program,
                                        GskSlScope        *scope,
                                        GskSlPreprocessor *stream)
 {
-  return gsk_sl_node_parse_primary_expression (program, scope, stream);
+  const GskSlToken *token;
+  GskSlNode *node;
+  GskSlNodeOperation *operation;
+  GskSlOperation op;
+
+  node = gsk_sl_node_parse_relational_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_EQ_OP))
+        op = GSK_SL_OPERATION_EQUAL;
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_NE_OP))
+        op = GSK_SL_OPERATION_NOT_EQUAL;
+      else
+        return node;
+
+      operation = gsk_sl_node_new (GskSlNodeOperation, &GSK_SL_NODE_OPERATION);
+      operation->left = node;
+      operation->op = op;
+      gsk_sl_preprocessor_consume (stream, (GskSlNode *) operation);
+      operation->right = gsk_sl_node_parse_relational_expression (program, scope, stream);
+      if (operation->right == NULL)
+        {
+          gsk_sl_node_ref (node);
+          gsk_sl_node_unref ((GskSlNode *) operation);
+        }
+      else
+        {
+          node = (GskSlNode *) operation;
+        }
+    }
+
+  return node;
 }
 
 static GskSlNode *
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index 2d720d2..ffa1511 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -42,37 +42,12 @@ struct _GskSlTypeClass {
   void                  (* print)                               (const GskSlType     *type,
                                                                  GString             *string);
   GskSlScalarType       (* get_scalar_type)                     (const GskSlType     *type);
+  GskSlType *           (* get_index_type)                      (const GskSlType     *type);
   guint                 (* get_length)                          (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;
@@ -129,6 +104,12 @@ gsk_sl_type_scalar_get_scalar_type (const GskSlType *type)
   return scalar->scalar;
 }
 
+static GskSlType *
+gsk_sl_type_scalar_get_index_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static guint
 gsk_sl_type_scalar_get_length (const GskSlType *type)
 {
@@ -152,6 +133,7 @@ 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_get_index_type,
   gsk_sl_type_scalar_get_length,
   gsk_sl_type_scalar_can_convert
 };
@@ -213,6 +195,14 @@ gsk_sl_type_vector_get_scalar_type (const GskSlType *type)
   return vector->scalar;
 }
 
+static GskSlType *
+gsk_sl_type_vector_get_index_type (const GskSlType *type)
+{
+  const GskSlTypeVector *vector = (const GskSlTypeVector *) type;
+
+  return gsk_sl_type_get_scalar (vector->scalar);
+}
+
 static guint
 gsk_sl_type_vector_get_length (const GskSlType *type)
 {
@@ -241,6 +231,7 @@ static const GskSlTypeClass GSK_SL_TYPE_VECTOR = {
   gsk_sl_type_vector_free,
   gsk_sl_type_vector_print,
   gsk_sl_type_vector_get_scalar_type,
+  gsk_sl_type_vector_get_index_type,
   gsk_sl_type_vector_get_length,
   gsk_sl_type_vector_can_convert
 };
@@ -285,6 +276,14 @@ gsk_sl_type_matrix_get_scalar_type (const GskSlType *type)
   return matrix->scalar;
 }
 
+static GskSlType *
+gsk_sl_type_matrix_get_index_type (const GskSlType *type)
+{
+  const GskSlTypeMatrix *matrix = (const GskSlTypeMatrix *) type;
+
+  return gsk_sl_type_get_vector (matrix->scalar, matrix->rows);
+}
+
 static guint
 gsk_sl_type_matrix_get_length (const GskSlType *type)
 {
@@ -314,6 +313,7 @@ static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
   gsk_sl_type_matrix_free,
   gsk_sl_type_matrix_print,
   gsk_sl_type_matrix_get_scalar_type,
+  gsk_sl_type_matrix_get_index_type,
   gsk_sl_type_matrix_get_length,
   gsk_sl_type_matrix_can_convert
 };
@@ -637,6 +637,12 @@ gsk_sl_type_get_scalar_type (const GskSlType *type)
   return type->class->get_scalar_type (type);
 }
 
+GskSlType *
+gsk_sl_type_get_index_type (const GskSlType *type)
+{
+  return type->class->get_index_type (type);
+}
+
 GskSlScalarType
 gsk_sl_type_get_length (const GskSlType *type)
 {
@@ -644,6 +650,32 @@ gsk_sl_type_get_length (const GskSlType *type)
 }
 
 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;
+  }
+}
+
+gboolean
 gsk_sl_type_can_convert (const GskSlType *target,
                          const GskSlType *source)
 {
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index b7166ac..d522e1b 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -53,7 +53,10 @@ gboolean                gsk_sl_type_is_scalar                   (const GskSlType
 gboolean                gsk_sl_type_is_vector                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_matrix                   (const GskSlType     *type);
 GskSlScalarType         gsk_sl_type_get_scalar_type             (const GskSlType     *type);
+GskSlType *             gsk_sl_type_get_index_type              (const GskSlType     *type);
 guint                   gsk_sl_type_get_length                  (const GskSlType     *type);
+gboolean                gsk_sl_scalar_type_can_convert          (GskSlScalarType      target,
+                                                                 GskSlScalarType      source);
 gboolean                gsk_sl_type_can_convert                 (const GskSlType     *target,
                                                                  const GskSlType     *source);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]