diff --git a/gsk/gskslfunction.c b/gsk/gskslfunction.c index bbff985944..c9e2ac5dae 100644 --- a/gsk/gskslfunction.c +++ b/gsk/gskslfunction.c @@ -20,7 +20,12 @@ #include "gskslfunctionprivate.h" +#include "gskslnodeprivate.h" +#include "gskslpreprocessorprivate.h" +#include "gskslscopeprivate.h" +#include "gsksltokenizerprivate.h" #include "gsksltypeprivate.h" +#include "gskspvwriterprivate.h" static GskSlFunction * gsk_sl_function_alloc (const GskSlFunctionClass *klass, @@ -58,22 +63,27 @@ gsk_sl_function_constructor_free (GskSlFunction *function) } static GskSlType * -gsk_sl_function_constructor_get_return_type (GskSlFunction *function) +gsk_sl_function_constructor_get_return_type (const GskSlFunction *function) { - GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function; + const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function; return constructor->type; } static void -gsk_sl_function_constructor_print_name (GskSlFunction *function, - GString *string) +gsk_sl_function_constructor_print_name (const GskSlFunction *function, + GString *string) { - GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function; + const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function; g_string_append (string, gsk_sl_type_get_name (constructor->type)); } +static void +gsk_sl_function_constructor_print (const GskSlFunction *function, + GString *string) +{ +} static guint gsk_sl_function_builtin_get_args_by_type (const GskSlType *type) @@ -89,12 +99,12 @@ gsk_sl_function_builtin_get_args_by_type (const GskSlType *type) } static gboolean -gsk_sl_function_constructor_matches (GskSlFunction *function, - GskSlType **arguments, - gsize n_arguments, - GError **error) +gsk_sl_function_constructor_matches (const GskSlFunction *function, + GskSlType **arguments, + gsize n_arguments, + GError **error) { - GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function; + const GskSlFunctionConstructor *constructor = (const GskSlFunctionConstructor *) function; guint needed, provided; gsize i; @@ -127,11 +137,161 @@ gsk_sl_function_constructor_matches (GskSlFunction *function, return TRUE; } +static guint32 +gsk_sl_function_constructor_write_spv (const GskSlFunction *function, + GskSpvWriter *writer) +{ + return 0; +} + static const GskSlFunctionClass GSK_SL_FUNCTION_CONSTRUCTOR = { gsk_sl_function_constructor_free, gsk_sl_function_constructor_get_return_type, gsk_sl_function_constructor_print_name, + gsk_sl_function_constructor_print, gsk_sl_function_constructor_matches, + gsk_sl_function_constructor_write_spv, +}; + +/* DECLARED */ + +typedef struct _GskSlFunctionDeclared GskSlFunctionDeclared; + +struct _GskSlFunctionDeclared { + GskSlFunction parent; + + GskSlScope *scope; + GskSlType *return_type; + char *name; + GSList *statements; +}; + +static void +gsk_sl_function_declared_free (GskSlFunction *function) +{ + GskSlFunctionDeclared *declared = (GskSlFunctionDeclared *) function; + + if (declared->scope) + gsk_sl_scope_unref (declared->scope); + if (declared->return_type) + gsk_sl_type_unref (declared->return_type); + g_free (declared->name); + g_slist_free_full (declared->statements, (GDestroyNotify) gsk_sl_node_unref); + + g_slice_free (GskSlFunctionDeclared, declared); +} + +static GskSlType * +gsk_sl_function_declared_get_return_type (const GskSlFunction *function) +{ + const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function; + + return declared->return_type; +} + +static void +gsk_sl_function_declared_print_name (const GskSlFunction *function, + GString *string) +{ + const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function; + + g_string_append (string, declared->name); +} + +static void +gsk_sl_function_declared_print (const GskSlFunction *function, + GString *string) +{ + const GskSlFunctionDeclared *declared = (const GskSlFunctionDeclared *) function; + GSList *l; + + g_string_append (string, gsk_sl_type_get_name (declared->return_type)); + g_string_append (string, "\n"); + + g_string_append (string, declared->name); + g_string_append (string, " ("); + g_string_append (string, ")\n"); + + g_string_append (string, "{\n"); + for (l = declared->statements; l; l = l->next) + { + g_string_append (string, " "); + gsk_sl_node_print (l->data, string); + g_string_append (string, ";\n"); + } + g_string_append (string, "}\n"); +} + +static gboolean +gsk_sl_function_declared_matches (const GskSlFunction *function, + GskSlType **arguments, + gsize n_arguments, + GError **error) +{ + if (n_arguments > 0) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Function only takes %u arguments.", 0); + return FALSE; + } + + return TRUE; +} + +static guint32 +gsk_sl_function_declared_write_spv (const GskSlFunction *function, + GskSpvWriter *writer) +{ + GskSlFunctionDeclared *declared = (GskSlFunctionDeclared *) function; + guint32 return_type_id, function_type_id, function_id, label_id; + GSList *l; + + /* declare type of function */ + return_type_id = gsk_spv_writer_get_id_for_type (writer, declared->return_type); + function_type_id = gsk_spv_writer_next_id (writer); + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_DECLARE, + 3, GSK_SPV_OP_TYPE_FUNCTION, + (guint32[2]) { function_type_id, + return_type_id }); + + /* add debug info */ + /* FIXME */ + + /* add function body */ + function_id = gsk_spv_writer_next_id (writer); + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 5, GSK_SPV_OP_FUNCTION, + (guint32[4]) { return_type_id, + function_id, + 0, + function_type_id }); + label_id = gsk_spv_writer_next_id (writer); + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 2, GSK_SPV_OP_LABEL, + (guint32[1]) { label_id }); + + for (l = declared->statements; l; l = l->next) + { + gsk_sl_node_write_spv (l->data, writer); + } + + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 1, GSK_SPV_OP_FUNCTION_END, + NULL); + + return function_id; +} + +static const GskSlFunctionClass GSK_SL_FUNCTION_DECLARED = { + gsk_sl_function_declared_free, + gsk_sl_function_declared_get_return_type, + gsk_sl_function_declared_print_name, + gsk_sl_function_declared_print, + gsk_sl_function_declared_matches, + gsk_sl_function_declared_write_spv, }; /* API */ @@ -148,6 +308,85 @@ gsk_sl_function_new_constructor (GskSlType *type) return &constructor->parent; } +GskSlFunction * +gsk_sl_function_new_parse (GskSlScope *scope, + GskSlPreprocessor *preproc, + GskSlType *return_type, + const char *name) +{ + GskSlFunctionDeclared *function; + const GskSlToken *token; + gboolean success = TRUE; + + function = gsk_sl_function_new (GskSlFunctionDeclared, &GSK_SL_FUNCTION_DECLARED); + function->return_type = gsk_sl_type_ref (return_type); + function->name = g_strdup (name); + + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN)) + { + gsk_sl_preprocessor_error (preproc, "Expected an openening \"(\""); + gsk_sl_function_unref ((GskSlFunction *) function); + return NULL; + } + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function); + + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN)) + { + gsk_sl_preprocessor_error (preproc, "Expected a closing \")\""); + gsk_sl_function_unref ((GskSlFunction *) function); + return NULL; + } + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function); + + token = gsk_sl_preprocessor_get (preproc); + if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) + { + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function); + return (GskSlFunction *) function; + } + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE)) + { + gsk_sl_preprocessor_error (preproc, "Expected an opening \"{\""); + gsk_sl_function_unref ((GskSlFunction *) function); + return NULL; + } + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function); + + function->scope = gsk_sl_scope_new (scope, function->return_type); + + for (token = gsk_sl_preprocessor_get (preproc); + !gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE) && !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF); + token = gsk_sl_preprocessor_get (preproc)) + { + GskSlNode *statement; + + statement = gsk_sl_node_parse_statement (function->scope, preproc); + if (statement) + function->statements = g_slist_append (function->statements, statement); + else + success = FALSE; + } + + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE)) + { + gsk_sl_preprocessor_error (preproc, "Missing closing \"}\" at end."); + gsk_sl_function_unref ((GskSlFunction *) function); + return NULL; + } + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) function); + + if (!success) + { + gsk_sl_function_unref ((GskSlFunction *) function); + return NULL; + } + + return (GskSlFunction *) function; +} + GskSlFunction * gsk_sl_function_ref (GskSlFunction *function) { @@ -172,24 +411,38 @@ gsk_sl_function_unref (GskSlFunction *function) } GskSlType * -gsk_sl_function_get_return_type (GskSlFunction *function) +gsk_sl_function_get_return_type (const GskSlFunction *function) { return function->class->get_return_type (function); } void -gsk_sl_function_print_name (GskSlFunction *function, - GString *string) +gsk_sl_function_print_name (const GskSlFunction *function, + GString *string) { function->class->print_name (function, string); } +void +gsk_sl_function_print (const GskSlFunction *function, + GString *string) +{ + function->class->print (function, string); +} + gboolean -gsk_sl_function_matches (GskSlFunction *function, - GskSlType **arguments, - gsize n_arguments, - GError **error) +gsk_sl_function_matches (const GskSlFunction *function, + GskSlType **arguments, + gsize n_arguments, + GError **error) { return function->class->matches (function, arguments, n_arguments, error); } +guint32 +gsk_sl_function_write_spv (const GskSlFunction *function, + GskSpvWriter *writer) +{ + return function->class->write_spv (function, writer); +} + diff --git a/gsk/gskslfunctionprivate.h b/gsk/gskslfunctionprivate.h index 7005fd9c45..99967cb793 100644 --- a/gsk/gskslfunctionprivate.h +++ b/gsk/gskslfunctionprivate.h @@ -37,27 +37,40 @@ struct _GskSlFunction struct _GskSlFunctionClass { void (* free) (GskSlFunction *function); - GskSlType * (* get_return_type) (GskSlFunction *function); - void (* print_name) (GskSlFunction *function, - GString *string); - gboolean (* matches) (GskSlFunction *function, - GskSlType **arguments, - gsize n_arguments, - GError **error); + GskSlType * (* get_return_type) (const GskSlFunction *function); + void (* print_name) (const GskSlFunction *function, + GString *string); + void (* print) (const GskSlFunction *function, + GString *string); + gboolean (* matches) (const GskSlFunction *function, + GskSlType **arguments, + gsize n_arguments, + GError **error); + guint32 (* write_spv) (const GskSlFunction *function, + GskSpvWriter *writer); }; -GskSlFunction * gsk_sl_function_new_constructor (GskSlType *type); +GskSlFunction * gsk_sl_function_new_constructor (GskSlType *type); +GskSlFunction * gsk_sl_function_new_parse (GskSlScope *scope, + GskSlPreprocessor *stream, + GskSlType *return_type, + const char *name); -GskSlFunction * gsk_sl_function_ref (GskSlFunction *function); -void gsk_sl_function_unref (GskSlFunction *function); +GskSlFunction * gsk_sl_function_ref (GskSlFunction *function); +void gsk_sl_function_unref (GskSlFunction *function); -void gsk_sl_function_print_name (GskSlFunction *function, - GString *string); -GskSlType * gsk_sl_function_get_return_type (GskSlFunction *function); -gboolean gsk_sl_function_matches (GskSlFunction *function, - GskSlType **arguments, - gsize n_arguments, - GError **error); +void gsk_sl_function_print (const GskSlFunction *function, + GString *string); + +void gsk_sl_function_print_name (const GskSlFunction *function, + GString *string); +GskSlType * gsk_sl_function_get_return_type (const GskSlFunction *function); +gboolean gsk_sl_function_matches (const GskSlFunction *function, + GskSlType **arguments, + gsize n_arguments, + GError **error); +guint32 gsk_sl_function_write_spv (const GskSlFunction *function, + GskSpvWriter *writer); G_END_DECLS diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c index 6e5fa82cbb..62afbbbcc2 100644 --- a/gsk/gskslnode.c +++ b/gsk/gskslnode.c @@ -47,109 +47,42 @@ gsk_sl_node_alloc (const GskSlNodeClass *klass, } #define gsk_sl_node_new(_name, _klass) ((_name *) gsk_sl_node_alloc ((_klass), sizeof (_name))) -/* FUNCTION */ +/* EMPTY */ -typedef struct _GskSlNodeFunction GskSlNodeFunction; +/* FIXME: This exists only so we dont return NULL from empty statements (ie just a semicolon) + */ -struct _GskSlNodeFunction { +typedef struct _GskSlNodeEmpty GskSlNodeEmpty; + +struct _GskSlNodeEmpty { GskSlNode parent; - - GskSlScope *scope; - GskSlType *return_type; - char *name; - GSList *statements; }; static void -gsk_sl_node_function_free (GskSlNode *node) +gsk_sl_node_empty_free (GskSlNode *node) { - GskSlNodeFunction *function = (GskSlNodeFunction *) node; + GskSlNodeEmpty *empty = (GskSlNodeEmpty *) node; - if (function->scope) - gsk_sl_scope_unref (function->scope); - if (function->return_type) - gsk_sl_type_unref (function->return_type); - g_free (function->name); - g_slist_free_full (function->statements, (GDestroyNotify) gsk_sl_node_unref); - - g_slice_free (GskSlNodeFunction, function); + g_slice_free (GskSlNodeEmpty, empty); } static void -gsk_sl_node_function_print (GskSlNode *node, - GString *string) +gsk_sl_node_empty_print (GskSlNode *node, + GString *string) { - GskSlNodeFunction *function = (GskSlNodeFunction *) node; - GSList *l; - - g_string_append (string, gsk_sl_type_get_name (function->return_type)); - g_string_append (string, "\n"); - - g_string_append (string, function->name); - g_string_append (string, " ("); - g_string_append (string, ")\n"); - - g_string_append (string, "{\n"); - for (l = function->statements; l; l = l->next) - { - g_string_append (string, " "); - gsk_sl_node_print (l->data, string); - g_string_append (string, ";\n"); - } - g_string_append (string, "}\n"); } static guint32 -gsk_sl_node_function_write_spv (const GskSlNode *node, - GskSpvWriter *writer) +gsk_sl_node_empty_write_spv (const GskSlNode *node, + GskSpvWriter *writer) { - GskSlNodeFunction *function = (GskSlNodeFunction *) node; - guint32 return_type_id, function_type_id, function_id, label_id; - GSList *l; - - /* declare type of function */ - return_type_id = gsk_spv_writer_get_id_for_type (writer, function->return_type); - function_type_id = gsk_spv_writer_next_id (writer); - gsk_spv_writer_add (writer, - GSK_SPV_WRITER_SECTION_DECLARE, - 3, GSK_SPV_OP_TYPE_FUNCTION, - (guint32[2]) { function_type_id, - return_type_id }); - - /* add debug info */ - /* FIXME */ - - /* add function body */ - function_id = gsk_spv_writer_next_id (writer); - gsk_spv_writer_add (writer, - GSK_SPV_WRITER_SECTION_CODE, - 5, GSK_SPV_OP_FUNCTION, - (guint32[4]) { return_type_id, - function_id, - 0, - function_type_id }); - label_id = gsk_spv_writer_next_id (writer); - gsk_spv_writer_add (writer, - GSK_SPV_WRITER_SECTION_CODE, - 2, GSK_SPV_OP_LABEL, - (guint32[4]) { label_id }); - - for (l = function->statements; l; l = l->next) - { - gsk_sl_node_write_spv (l->data, writer); - } - - gsk_spv_writer_add (writer, - GSK_SPV_WRITER_SECTION_CODE, - 1, GSK_SPV_OP_FUNCTION_END, - NULL); - return function_id; + return 0; } -static const GskSlNodeClass GSK_SL_NODE_FUNCTION = { - gsk_sl_node_function_free, - gsk_sl_node_function_print, - gsk_sl_node_function_write_spv +static const GskSlNodeClass GSK_SL_NODE_EMPTY = { + gsk_sl_node_empty_free, + gsk_sl_node_empty_print, + gsk_sl_node_empty_write_spv }; /* DECLARATION */ @@ -312,52 +245,6 @@ static const GskSlNodeClass GSK_SL_NODE_EXPRESSION = { /* API */ -static GskSlNodeFunction * -gsk_sl_node_parse_function_prototype (GskSlScope *scope, - GskSlPreprocessor *stream) -{ - GskSlType *type; - GskSlNodeFunction *function; - const GskSlToken *token; - - type = gsk_sl_type_new_parse (stream); - if (type == NULL) - return NULL; - - token = gsk_sl_preprocessor_get (stream); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) - { - gsk_sl_preprocessor_error (stream, "Expected a function name"); - gsk_sl_type_unref (type); - return NULL; - } - - function = gsk_sl_node_new (GskSlNodeFunction, &GSK_SL_NODE_FUNCTION); - function->return_type = type; - function->name = g_strdup (token->str); - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); - - token = gsk_sl_preprocessor_get (stream); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN)) - { - gsk_sl_preprocessor_error (stream, "Expected an openening \"(\""); - gsk_sl_node_unref ((GskSlNode *) function); - return NULL; - } - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); - - token = gsk_sl_preprocessor_get (stream); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN)) - { - gsk_sl_preprocessor_error (stream, "Expected a closing \")\""); - gsk_sl_node_unref ((GskSlNode *) function); - return NULL; - } - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); - - return function; -} - static GskSlNode * gsk_sl_node_parse_declaration (GskSlScope *scope, GskSlPreprocessor *stream, @@ -391,239 +278,228 @@ gsk_sl_node_parse_declaration (GskSlScope *scope, } GskSlNode * -gsk_sl_node_parse_function_definition (GskSlScope *scope, - GskSlPreprocessor *stream) +gsk_sl_node_parse_statement (GskSlScope *scope, + GskSlPreprocessor *preproc) { - GskSlNodeFunction *function; const GskSlToken *token; - gboolean result = TRUE; + GskSlNode *node; - function = gsk_sl_node_parse_function_prototype (scope, stream); - if (function == NULL) - return FALSE; + token = gsk_sl_preprocessor_get (preproc); - token = gsk_sl_preprocessor_get (stream); - if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) - { - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); - return (GskSlNode *) function; - } + switch ((guint) token->type) + { + case GSK_SL_TOKEN_SEMICOLON: + node = (GskSlNode *) gsk_sl_node_new (GskSlNodeEmpty, &GSK_SL_NODE_EMPTY); + break; - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE)) - { - gsk_sl_preprocessor_error (stream, "Expected an opening \"{\""); - gsk_sl_node_unref ((GskSlNode *) function); - return FALSE; - } - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); + case GSK_SL_TOKEN_EOF: + gsk_sl_preprocessor_error (preproc, "Unexpected end of document"); + return NULL; - function->scope = gsk_sl_scope_new (scope); - - while (TRUE) - { - token = gsk_sl_preprocessor_get (stream); - switch ((guint) token->type) + case GSK_SL_TOKEN_CONST: + case GSK_SL_TOKEN_IN: + case GSK_SL_TOKEN_OUT: + case GSK_SL_TOKEN_INOUT: + case GSK_SL_TOKEN_INVARIANT: + case GSK_SL_TOKEN_COHERENT: + case GSK_SL_TOKEN_VOLATILE: + case GSK_SL_TOKEN_RESTRICT: + case GSK_SL_TOKEN_READONLY: + case GSK_SL_TOKEN_WRITEONLY: + case GSK_SL_TOKEN_VOID: + case GSK_SL_TOKEN_FLOAT: + case GSK_SL_TOKEN_DOUBLE: + case GSK_SL_TOKEN_INT: + case GSK_SL_TOKEN_UINT: + case GSK_SL_TOKEN_BOOL: + case GSK_SL_TOKEN_BVEC2: + case GSK_SL_TOKEN_BVEC3: + case GSK_SL_TOKEN_BVEC4: + case GSK_SL_TOKEN_IVEC2: + case GSK_SL_TOKEN_IVEC3: + case GSK_SL_TOKEN_IVEC4: + case GSK_SL_TOKEN_UVEC2: + case GSK_SL_TOKEN_UVEC3: + case GSK_SL_TOKEN_UVEC4: + case GSK_SL_TOKEN_VEC2: + case GSK_SL_TOKEN_VEC3: + case GSK_SL_TOKEN_VEC4: + case GSK_SL_TOKEN_DVEC2: + case GSK_SL_TOKEN_DVEC3: + case GSK_SL_TOKEN_DVEC4: + case GSK_SL_TOKEN_MAT2: + case GSK_SL_TOKEN_MAT3: + case GSK_SL_TOKEN_MAT4: + case GSK_SL_TOKEN_DMAT2: + case GSK_SL_TOKEN_DMAT3: + case GSK_SL_TOKEN_DMAT4: + case GSK_SL_TOKEN_MAT2X2: + case GSK_SL_TOKEN_MAT2X3: + case GSK_SL_TOKEN_MAT2X4: + case GSK_SL_TOKEN_MAT3X2: + case GSK_SL_TOKEN_MAT3X3: + case GSK_SL_TOKEN_MAT3X4: + case GSK_SL_TOKEN_MAT4X2: + case GSK_SL_TOKEN_MAT4X3: + case GSK_SL_TOKEN_MAT4X4: + case GSK_SL_TOKEN_DMAT2X2: + case GSK_SL_TOKEN_DMAT2X3: + case GSK_SL_TOKEN_DMAT2X4: + case GSK_SL_TOKEN_DMAT3X2: + case GSK_SL_TOKEN_DMAT3X3: + case GSK_SL_TOKEN_DMAT3X4: + case GSK_SL_TOKEN_DMAT4X2: + case GSK_SL_TOKEN_DMAT4X3: + case GSK_SL_TOKEN_DMAT4X4: { - case GSK_SL_TOKEN_SEMICOLON: - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); - break; + GskSlType *type; + GskSlPointerTypeFlags flags; + gboolean success; - case GSK_SL_TOKEN_EOF: - gsk_sl_preprocessor_error (stream, "Unexpected end of function, expected \"}\""); - goto out; + success = gsk_sl_type_qualifier_parse (preproc, + GSK_SL_POINTER_TYPE_PARAMETER_QUALIFIER + | GSK_SL_POINTER_TYPE_MEMORY_QUALIFIER, + &flags); - case GSK_SL_TOKEN_RIGHT_BRACE: - goto out; - - case GSK_SL_TOKEN_CONST: - case GSK_SL_TOKEN_IN: - case GSK_SL_TOKEN_OUT: - case GSK_SL_TOKEN_INOUT: - case GSK_SL_TOKEN_INVARIANT: - case GSK_SL_TOKEN_COHERENT: - case GSK_SL_TOKEN_VOLATILE: - case GSK_SL_TOKEN_RESTRICT: - case GSK_SL_TOKEN_READONLY: - case GSK_SL_TOKEN_WRITEONLY: - case GSK_SL_TOKEN_VOID: - case GSK_SL_TOKEN_FLOAT: - case GSK_SL_TOKEN_DOUBLE: - case GSK_SL_TOKEN_INT: - case GSK_SL_TOKEN_UINT: - case GSK_SL_TOKEN_BOOL: - case GSK_SL_TOKEN_BVEC2: - case GSK_SL_TOKEN_BVEC3: - case GSK_SL_TOKEN_BVEC4: - case GSK_SL_TOKEN_IVEC2: - case GSK_SL_TOKEN_IVEC3: - case GSK_SL_TOKEN_IVEC4: - case GSK_SL_TOKEN_UVEC2: - case GSK_SL_TOKEN_UVEC3: - case GSK_SL_TOKEN_UVEC4: - case GSK_SL_TOKEN_VEC2: - case GSK_SL_TOKEN_VEC3: - case GSK_SL_TOKEN_VEC4: - case GSK_SL_TOKEN_DVEC2: - case GSK_SL_TOKEN_DVEC3: - case GSK_SL_TOKEN_DVEC4: - case GSK_SL_TOKEN_MAT2: - case GSK_SL_TOKEN_MAT3: - case GSK_SL_TOKEN_MAT4: - case GSK_SL_TOKEN_DMAT2: - case GSK_SL_TOKEN_DMAT3: - case GSK_SL_TOKEN_DMAT4: - case GSK_SL_TOKEN_MAT2X2: - case GSK_SL_TOKEN_MAT2X3: - case GSK_SL_TOKEN_MAT2X4: - case GSK_SL_TOKEN_MAT3X2: - case GSK_SL_TOKEN_MAT3X3: - case GSK_SL_TOKEN_MAT3X4: - case GSK_SL_TOKEN_MAT4X2: - case GSK_SL_TOKEN_MAT4X3: - case GSK_SL_TOKEN_MAT4X4: - case GSK_SL_TOKEN_DMAT2X2: - case GSK_SL_TOKEN_DMAT2X3: - case GSK_SL_TOKEN_DMAT2X4: - case GSK_SL_TOKEN_DMAT3X2: - case GSK_SL_TOKEN_DMAT3X3: - case GSK_SL_TOKEN_DMAT3X4: - case GSK_SL_TOKEN_DMAT4X2: - case GSK_SL_TOKEN_DMAT4X3: - case GSK_SL_TOKEN_DMAT4X4: - { - GskSlType *type; - GskSlPointerTypeFlags flags; - gboolean success; - GskSlNode *node = NULL; - - success = gsk_sl_type_qualifier_parse (stream, - GSK_SL_POINTER_TYPE_PARAMETER_QUALIFIER - | GSK_SL_POINTER_TYPE_MEMORY_QUALIFIER, - &flags); - - type = gsk_sl_type_new_parse (stream); - if (type == NULL) + type = gsk_sl_type_new_parse (preproc); + if (type == NULL) + { + node = NULL; break; + } - token = gsk_sl_preprocessor_get (stream); + token = gsk_sl_preprocessor_get (preproc); - if (token->type == GSK_SL_TOKEN_LEFT_BRACE) - { - GskSlExpression *expression = gsk_sl_expression_parse_constructor_call (function->scope, stream, type); + if (token->type == GSK_SL_TOKEN_LEFT_PAREN) + { + GskSlExpression *expression = gsk_sl_expression_parse_constructor_call (scope, preproc, type); - if (expression) - { - GskSlNodeExpression *node; - - node = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION); - node->expression = expression; - - function->statements = g_slist_append (function->statements, node); - } - else - { - node = NULL; - } - } - else - { - GskSlPointerType *pointer_type; - - pointer_type = gsk_sl_pointer_type_new (type, flags | GSK_SL_POINTER_TYPE_LOCAL); - node = gsk_sl_node_parse_declaration (function->scope, stream, pointer_type); - gsk_sl_pointer_type_unref (pointer_type); - } - - gsk_sl_type_unref (type); - - if (!success) - { - gsk_sl_node_unref (node); - } - else if (node) - { - function->statements = g_slist_append (function->statements, node); - } - } - break; - - case GSK_SL_TOKEN_RETURN: - { - GskSlNodeReturn *return_node; - - return_node = gsk_sl_node_new (GskSlNodeReturn, &GSK_SL_NODE_RETURN); - gsk_sl_preprocessor_consume (stream, (GskSlNode *) return_node); - token = gsk_sl_preprocessor_get (stream); - if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) - { - return_node->value = gsk_sl_expression_parse (function->scope, stream); - if (return_node->value == NULL) - { - gsk_sl_node_unref ((GskSlNode *) return_node); - break; - } - if (function->return_type == NULL) - { - gsk_sl_preprocessor_error (stream, "Cannot return a value from a void function."); - gsk_sl_node_unref ((GskSlNode *) return_node); - break; - } - else if (!gsk_sl_type_can_convert (function->return_type, gsk_sl_expression_get_return_type (return_node->value))) - { - gsk_sl_preprocessor_error (stream, "Cannot convert return type %s to function type %s.", - gsk_sl_type_get_name (gsk_sl_expression_get_return_type (return_node->value)), - gsk_sl_type_get_name (function->return_type)); - gsk_sl_node_unref ((GskSlNode *) return_node); - break; - } + if (expression) + { + GskSlNodeExpression *node_expression; + + node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION); + node_expression->expression = expression; + node = (GskSlNode *) node_expression; } else { - if (function->return_type != NULL) - { - gsk_sl_preprocessor_error (stream, "Return statement does not return a value."); - gsk_sl_node_unref ((GskSlNode *) return_node); - break; - } + node = NULL; } - function->statements = g_slist_append (function->statements, return_node); } - break; + else + { + GskSlPointerType *pointer_type; + + pointer_type = gsk_sl_pointer_type_new (type, flags | GSK_SL_POINTER_TYPE_LOCAL); + node = gsk_sl_node_parse_declaration (scope, preproc, pointer_type); + gsk_sl_pointer_type_unref (pointer_type); + } - default: - { - GskSlExpression * expression = gsk_sl_expression_parse (function->scope, stream); + gsk_sl_type_unref (type); + + if (!success) + { + gsk_sl_node_unref (node); + node = NULL; + } + } + break; - if (expression) - { - GskSlNodeExpression *node; - - node = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION); - node->expression = expression; + case GSK_SL_TOKEN_RETURN: + { + GskSlNodeReturn *return_node; + GskSlType *return_type; - function->statements = g_slist_append (function->statements, node); - } - else - { - result = FALSE; + return_node = gsk_sl_node_new (GskSlNodeReturn, &GSK_SL_NODE_RETURN); + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) return_node); + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) + { + return_node->value = gsk_sl_expression_parse (scope, preproc); + + if (return_node->value == NULL) + { + gsk_sl_node_unref ((GskSlNode *) return_node); + node = NULL; + break; + } + } + + return_type = gsk_sl_scope_get_return_type (scope); + node = (GskSlNode *) return_node; + + if (return_type == NULL) + { + gsk_sl_preprocessor_error (preproc, "Cannot return from here."); + gsk_sl_node_unref (node); + node = NULL; + } + else if (return_node->value == NULL) + { + if (!gsk_sl_type_equal (return_type, gsk_sl_type_get_scalar (GSK_SL_VOID))) + { + gsk_sl_preprocessor_error (preproc, "Functions expectes a return value of type %s", gsk_sl_type_get_name (return_type)); + gsk_sl_node_unref (node); + node = NULL; + } + } + else + { + if (gsk_sl_type_equal (return_type, gsk_sl_type_get_scalar (GSK_SL_VOID))) + { + gsk_sl_preprocessor_error (preproc, "Cannot return a value from a void function."); + gsk_sl_node_unref (node); + node = NULL; + } + else if (!gsk_sl_type_can_convert (return_type, gsk_sl_expression_get_return_type (return_node->value))) + { + gsk_sl_preprocessor_error (preproc, + "Cannot convert type %s to return type %s.", + gsk_sl_type_get_name (gsk_sl_expression_get_return_type (return_node->value)), + gsk_sl_type_get_name (return_type)); + gsk_sl_node_unref (node); + node = NULL; + break; + } } } - break; + break; + + default: + { + GskSlExpression * expression = gsk_sl_expression_parse (scope, preproc); + + if (expression) + { + GskSlNodeExpression *node_expression; + + node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION); + node_expression->expression = expression; + + node = (GskSlNode *) node_expression; + } + else + { + return NULL; + } } - } + break; + } -out: - gsk_sl_preprocessor_consume (stream, (GskSlNode *) function); + if (node == NULL) + return NULL; - if (result) + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON)) { - return (GskSlNode *) function; - } - else - { - gsk_sl_node_unref ((GskSlNode *) function); + gsk_sl_preprocessor_error (preproc, "No semicolon at end of statement."); + gsk_sl_node_unref (node); return NULL; } + gsk_sl_preprocessor_consume (preproc, (GskSlNode *) node); + + return node; } GskSlNode * diff --git a/gsk/gskslnodeprivate.h b/gsk/gskslnodeprivate.h index ead228055a..5cb00c4439 100644 --- a/gsk/gskslnodeprivate.h +++ b/gsk/gskslnodeprivate.h @@ -41,7 +41,7 @@ struct _GskSlNodeClass { GskSpvWriter *writer); }; -GskSlNode * gsk_sl_node_parse_function_definition (GskSlScope *scope, +GskSlNode * gsk_sl_node_parse_statement (GskSlScope *scope, GskSlPreprocessor *preproc); GskSlNode * gsk_sl_node_ref (GskSlNode *node); diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c index dcb0f99cd3..8a1d6de6c5 100644 --- a/gsk/gskslprogram.c +++ b/gsk/gskslprogram.c @@ -20,10 +20,12 @@ #include "gskslprogramprivate.h" +#include "gskslfunctionprivate.h" #include "gskslnodeprivate.h" #include "gskslpreprocessorprivate.h" #include "gskslscopeprivate.h" #include "gsksltokenizerprivate.h" +#include "gsksltypeprivate.h" #include "gskspvwriterprivate.h" struct _GskSlProgram { @@ -59,7 +61,48 @@ gsk_sl_program_class_init (GskSlProgramClass *klass) static void gsk_sl_program_init (GskSlProgram *program) { - program->scope = gsk_sl_scope_new (NULL); + program->scope = gsk_sl_scope_new (NULL, NULL); +} + +static gboolean +gsk_sl_program_parse_declaration (GskSlProgram *program, + GskSlScope *scope, + GskSlPreprocessor *preproc) +{ + GskSlType *type; + GskSlFunction *function; + const GskSlToken *token; + char *name; + + type = gsk_sl_type_new_parse (preproc); + if (type == NULL) + { + gsk_sl_preprocessor_consume (preproc, program); + return FALSE; + } + + token = gsk_sl_preprocessor_get (preproc); + if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER)) + { + gsk_sl_preprocessor_error (preproc, "Expected a function name"); + gsk_sl_type_unref (type); + return FALSE; + } + + name = g_strdup (token->str); + gsk_sl_preprocessor_consume (preproc, program); + + function = gsk_sl_function_new_parse (scope, + preproc, + type, + name); + if (function) + program->functions = g_slist_append (program->functions, function); + + gsk_sl_type_unref (type); + g_free (name); + + return function != NULL; } gboolean @@ -67,26 +110,16 @@ gsk_sl_program_parse (GskSlProgram *program, GskSlPreprocessor *preproc) { const GskSlToken *token; - gboolean result = TRUE; + gboolean success = TRUE; for (token = gsk_sl_preprocessor_get (preproc); !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF); token = gsk_sl_preprocessor_get (preproc)) { - GskSlNode *node = gsk_sl_node_parse_function_definition (program->scope, preproc); - - if (node) - { - program->functions = g_slist_append (program->functions, node); - } - else - { - gsk_sl_preprocessor_consume (preproc, (GskSlNode *) program); - result = FALSE; - } + success &= gsk_sl_program_parse_declaration (program, program->scope, preproc); } - return result; + return success; } void @@ -105,7 +138,7 @@ gsk_sl_program_print (GskSlProgram *program, { if (l != program->functions || program->declarations != NULL) g_string_append (string, "\n"); - gsk_sl_node_print (l->data, string); + gsk_sl_function_print (l->data, string); } } diff --git a/gsk/gskslscope.c b/gsk/gskslscope.c index 27a3c3195e..e1b3ca0bed 100644 --- a/gsk/gskslscope.c +++ b/gsk/gskslscope.c @@ -20,6 +20,7 @@ #include "gskslscopeprivate.h" +#include "gsksltypeprivate.h" #include "gskslvariableprivate.h" #include @@ -30,12 +31,14 @@ struct _GskSlScope GskSlScope *parent; GSList *children; + GskSlType *return_type; GHashTable *variables; }; GskSlScope * -gsk_sl_scope_new (GskSlScope *parent) +gsk_sl_scope_new (GskSlScope *parent, + GskSlType *return_type) { GskSlScope *scope; @@ -47,6 +50,8 @@ gsk_sl_scope_new (GskSlScope *parent) scope->parent = parent; parent->children = g_slist_prepend (parent->children, scope); } + if (return_type) + scope->return_type = gsk_sl_type_ref (return_type); scope->variables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gsk_sl_variable_unref); return scope; @@ -81,10 +86,18 @@ gsk_sl_scope_unref (GskSlScope *scope) for (l = scope->children; l; l = l->next) ((GskSlScope *) l->data)->parent = NULL; g_slist_free (scope->children); + if (scope->return_type) + gsk_sl_type_unref (scope->return_type); g_slice_free (GskSlScope, scope); } +GskSlType * +gsk_sl_scope_get_return_type (const GskSlScope *scope) +{ + return scope->return_type; +} + void gsk_sl_scope_add_variable (GskSlScope *scope, GskSlVariable *variable) diff --git a/gsk/gskslscopeprivate.h b/gsk/gskslscopeprivate.h index 11060753f5..9a41bef969 100644 --- a/gsk/gskslscopeprivate.h +++ b/gsk/gskslscopeprivate.h @@ -25,11 +25,14 @@ G_BEGIN_DECLS -GskSlScope * gsk_sl_scope_new (GskSlScope *parent); +GskSlScope * gsk_sl_scope_new (GskSlScope *parent, + GskSlType *return_type); GskSlScope * gsk_sl_scope_ref (GskSlScope *scope); void gsk_sl_scope_unref (GskSlScope *scope); +GskSlType * gsk_sl_scope_get_return_type (const GskSlScope *scope); + void gsk_sl_scope_add_variable (GskSlScope *scope, GskSlVariable *variable); GskSlVariable * gsk_sl_scope_lookup_variable (GskSlScope *scope,