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.
This commit is contained in:
Benjamin Otte
2017-09-17 06:00:49 +02:00
parent ad4b45639b
commit 0362778524
3 changed files with 467 additions and 84 deletions

View File

@@ -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
@@ -605,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_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,
@@ -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;

View File

@@ -25,30 +25,143 @@
#include <string.h>
#define N_SCALAR_TYPES 6
typedef struct _GskSlTypeClass GskSlTypeClass;
struct _GskSlType
{
int ref_count;
const GskSlTypeClass *class;
GskSlBuiltinType builtin;
int ref_count;
};
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 }
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 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 *
@@ -119,46 +224,30 @@ gsk_sl_type_unref (GskSlType *type)
if (type->ref_count > 0)
return;
g_assert_not_reached ();
type->class->free (type);
}
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);
}

View File

@@ -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