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



commit 5981565416e348a1fa139f5b8f7af08ac93d5028
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        |  309 ++++++++++++++++++++++++++++++++++++++++++++++-
 gsk/gsksltype.c        |  223 ++++++++++++++++++++++++-----------
 gsk/gsksltypeprivate.h |   15 +--
 3 files changed, 465 insertions(+), 82 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index e53dd6b..06a5e43 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
@@ -606,6 +713,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,
                                          GskSlPreprocessor *stream)
@@ -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 5edfbc6..ff0cf1f 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -25,30 +25,143 @@
 
 #include <string.h>
 
+#define N_SCALAR_TYPES 6
+
+typedef struct _GskSlTypeClass GskSlTypeClass;
+
 struct _GskSlType
 {
+  const GskSlTypeClass *class;
+
   int ref_count;
+};
 
-  GskSlBuiltinType builtin;
+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 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 }
+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 *
@@ -126,39 +231,23 @@ 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 5337e38..238db3e 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
 


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