Files
gtk/gsk/gskslnode.c
Benjamin Otte fad4112d78 gsksl: Introduce gsk_sl_preprocessor_sync()
Instead of just returning after an error an continuing to parse
wherever, use gsk_sl_preprocessor_sync() to find the next point in the
token stream that looks like a useful way to continue parsing.
2017-10-30 02:58:02 +01:00

521 lines
15 KiB
C

/* GTK - The GIMP Toolkit
*
* Copyright © 2017 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gskslnodeprivate.h"
#include "gskslexpressionprivate.h"
#include "gskslfunctionprivate.h"
#include "gskslpointertypeprivate.h"
#include "gskslpreprocessorprivate.h"
#include "gskslscopeprivate.h"
#include "gsksltokenizerprivate.h"
#include "gsksltypeprivate.h"
#include "gskslvalueprivate.h"
#include "gskslvariableprivate.h"
#include "gskspvwriterprivate.h"
#include <string.h>
static GskSlNode *
gsk_sl_node_alloc (const GskSlNodeClass *klass,
gsize size)
{
GskSlNode *node;
node = g_slice_alloc0 (size);
node->class = klass;
node->ref_count = 1;
return node;
}
#define gsk_sl_node_new(_name, _klass) ((_name *) gsk_sl_node_alloc ((_klass), sizeof (_name)))
/* EMPTY */
/* FIXME: This exists only so we dont return NULL from empty statements (ie just a semicolon)
*/
typedef struct _GskSlNodeEmpty GskSlNodeEmpty;
struct _GskSlNodeEmpty {
GskSlNode parent;
};
static void
gsk_sl_node_empty_free (GskSlNode *node)
{
GskSlNodeEmpty *empty = (GskSlNodeEmpty *) node;
g_slice_free (GskSlNodeEmpty, empty);
}
static void
gsk_sl_node_empty_print (GskSlNode *node,
GString *string)
{
}
static guint32
gsk_sl_node_empty_write_spv (const GskSlNode *node,
GskSpvWriter *writer)
{
return 0;
}
static const GskSlNodeClass GSK_SL_NODE_EMPTY = {
gsk_sl_node_empty_free,
gsk_sl_node_empty_print,
gsk_sl_node_empty_write_spv
};
/* DECLARATION */
typedef struct _GskSlNodeDeclaration GskSlNodeDeclaration;
struct _GskSlNodeDeclaration {
GskSlNode parent;
GskSlVariable *variable;
GskSlExpression *initial;
};
static void
gsk_sl_node_declaration_free (GskSlNode *node)
{
GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
gsk_sl_variable_unref (declaration->variable);
if (declaration->initial)
gsk_sl_expression_unref (declaration->initial);
g_slice_free (GskSlNodeDeclaration, declaration);
}
static void
gsk_sl_node_declaration_print (GskSlNode *node,
GString *string)
{
GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
gsk_sl_variable_print (declaration->variable, string);
if (declaration->initial)
{
g_string_append (string, " = ");
gsk_sl_expression_print (declaration->initial, string);
}
}
static guint32
gsk_sl_node_declaration_write_spv (const GskSlNode *node,
GskSpvWriter *writer)
{
GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
guint32 variable_id;
variable_id = gsk_spv_writer_get_id_for_variable (writer, declaration->variable);
if (declaration->initial && ! gsk_sl_variable_get_initial_value (declaration->variable))
{
gsk_spv_writer_add (writer,
GSK_SPV_WRITER_SECTION_CODE,
3, GSK_SPV_OP_STORE,
(guint32[2]) { variable_id,
gsk_sl_expression_write_spv (declaration->initial, writer)});
}
return variable_id;
}
static const GskSlNodeClass GSK_SL_NODE_DECLARATION = {
gsk_sl_node_declaration_free,
gsk_sl_node_declaration_print,
gsk_sl_node_declaration_write_spv
};
/* RETURN */
typedef struct _GskSlNodeReturn GskSlNodeReturn;
struct _GskSlNodeReturn {
GskSlNode parent;
GskSlExpression *value;
};
static void
gsk_sl_node_return_free (GskSlNode *node)
{
GskSlNodeReturn *return_node = (GskSlNodeReturn *) node;
if (return_node->value)
gsk_sl_expression_unref (return_node->value);
g_slice_free (GskSlNodeReturn, return_node);
}
static void
gsk_sl_node_return_print (GskSlNode *node,
GString *string)
{
GskSlNodeReturn *return_node = (GskSlNodeReturn *) node;
g_string_append (string, "return");
if (return_node->value)
{
g_string_append (string, " ");
gsk_sl_expression_print (return_node->value, string);
}
}
static guint32
gsk_sl_node_return_write_spv (const GskSlNode *node,
GskSpvWriter *writer)
{
g_assert_not_reached ();
return 0;
}
static const GskSlNodeClass GSK_SL_NODE_RETURN = {
gsk_sl_node_return_free,
gsk_sl_node_return_print,
gsk_sl_node_return_write_spv
};
/* EXPRESSION */
typedef struct _GskSlNodeExpression GskSlNodeExpression;
struct _GskSlNodeExpression {
GskSlNode parent;
GskSlExpression *expression;
};
static void
gsk_sl_node_expression_free (GskSlNode *node)
{
GskSlNodeExpression *expression_node = (GskSlNodeExpression *) node;
gsk_sl_expression_unref (expression_node->expression);
g_slice_free (GskSlNodeExpression, expression_node);
}
static void
gsk_sl_node_expression_print (GskSlNode *node,
GString *string)
{
GskSlNodeExpression *expression_node = (GskSlNodeExpression *) node;
gsk_sl_expression_print (expression_node->expression, string);
}
static guint32
gsk_sl_node_expression_write_spv (const GskSlNode *node,
GskSpvWriter *writer)
{
GskSlNodeExpression *expression_node = (GskSlNodeExpression *) node;
return gsk_sl_expression_write_spv (expression_node->expression, writer);
}
static const GskSlNodeClass GSK_SL_NODE_EXPRESSION = {
gsk_sl_node_expression_free,
gsk_sl_node_expression_print,
gsk_sl_node_expression_write_spv
};
/* API */
static GskSlNode *
gsk_sl_node_parse_declaration (GskSlScope *scope,
GskSlPreprocessor *stream,
GskSlDecorations *decoration,
GskSlType *type)
{
GskSlNodeDeclaration *declaration;
GskSlPointerType *pointer_type;
GskSlValue *value = NULL;
const GskSlToken *token;
char *name;
declaration = gsk_sl_node_new (GskSlNodeDeclaration, &GSK_SL_NODE_DECLARATION);
token = gsk_sl_preprocessor_get (stream);
if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
{
name = g_strdup (token->str);
gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
token = gsk_sl_preprocessor_get (stream);
if (gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
{
GskSlValue *unconverted;
gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
declaration->initial = gsk_sl_expression_parse_assignment (scope, stream);
if (!gsk_sl_type_can_convert (type, gsk_sl_expression_get_return_type (declaration->initial)))
{
gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
"Cannot convert from initializer type %s to variable type %s",
gsk_sl_type_get_name (gsk_sl_expression_get_return_type (declaration->initial)),
gsk_sl_type_get_name (type));
gsk_sl_expression_unref (declaration->initial);
declaration->initial = NULL;
}
else
{
unconverted = gsk_sl_expression_get_constant (declaration->initial);
if (unconverted)
{
value = gsk_sl_value_new_convert (unconverted, type);
gsk_sl_value_free (unconverted);
}
}
}
}
else
{
name = NULL;
value = NULL;
}
pointer_type = gsk_sl_pointer_type_new (type, TRUE, decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
declaration->variable = gsk_sl_variable_new (pointer_type, name, value, decoration->values[GSK_SL_DECORATION_CONST].set);
gsk_sl_pointer_type_unref (pointer_type);
gsk_sl_scope_add_variable (scope, declaration->variable);
return (GskSlNode *) declaration;
}
GskSlNode *
gsk_sl_node_parse_statement (GskSlScope *scope,
GskSlPreprocessor *preproc)
{
const GskSlToken *token;
GskSlNode *node;
token = gsk_sl_preprocessor_get (preproc);
switch ((guint) token->type)
{
case GSK_SL_TOKEN_SEMICOLON:
node = (GskSlNode *) gsk_sl_node_new (GskSlNodeEmpty, &GSK_SL_NODE_EMPTY);
break;
case GSK_SL_TOKEN_EOF:
gsk_sl_preprocessor_error (preproc, SYNTAX, "Unexpected end of document");
return (GskSlNode *) gsk_sl_node_new (GskSlNodeEmpty, &GSK_SL_NODE_EMPTY);
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_STRUCT:
case GSK_SL_TOKEN_IDENTIFIER:
{
GskSlType *type;
GskSlDecorations decoration;
gsk_sl_decoration_list_parse (scope,
preproc,
&decoration);
type = gsk_sl_type_new_parse (scope, preproc);
token = gsk_sl_preprocessor_get (preproc);
if (token->type == GSK_SL_TOKEN_LEFT_PAREN)
{
GskSlNodeExpression *node_expression;
GskSlFunction *constructor;
constructor = gsk_sl_function_new_constructor (type);
node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
node_expression->expression = gsk_sl_expression_parse_function_call (scope, preproc, constructor);
node = (GskSlNode *) node_expression;
gsk_sl_function_unref (constructor);
}
else
{
node = gsk_sl_node_parse_declaration (scope, preproc, &decoration, type);
}
gsk_sl_type_unref (type);
}
break;
case GSK_SL_TOKEN_RETURN:
{
GskSlNodeReturn *return_node;
GskSlType *return_type;
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);
return_type = gsk_sl_scope_get_return_type (scope);
node = (GskSlNode *) return_node;
if (return_type == NULL)
{
gsk_sl_preprocessor_error (preproc, SCOPE, "Cannot return from here.");
}
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, TYPE_MISMATCH,"Functions expectes a return value of type %s", gsk_sl_type_get_name (return_type));
}
}
else
{
if (gsk_sl_type_equal (return_type, gsk_sl_type_get_scalar (GSK_SL_VOID)))
{
gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Cannot return a value from a void function.");
}
else if (!gsk_sl_type_can_convert (return_type, gsk_sl_expression_get_return_type (return_node->value)))
{
gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
"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));
break;
}
}
}
break;
default:
{
GskSlNodeExpression *node_expression;
node_expression = gsk_sl_node_new (GskSlNodeExpression, &GSK_SL_NODE_EXPRESSION);
node_expression->expression = gsk_sl_expression_parse (scope, preproc);
node = (GskSlNode *) node_expression;
}
break;
}
token = gsk_sl_preprocessor_get (preproc);
if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
{
gsk_sl_preprocessor_error (preproc, SYNTAX, "No semicolon at end of statement.");
gsk_sl_preprocessor_sync (preproc, GSK_SL_TOKEN_SEMICOLON);
}
gsk_sl_preprocessor_consume (preproc, (GskSlNode *) node);
return node;
}
GskSlNode *
gsk_sl_node_ref (GskSlNode *node)
{
g_return_val_if_fail (node != NULL, NULL);
node->ref_count += 1;
return node;
}
void
gsk_sl_node_unref (GskSlNode *node)
{
if (node == NULL)
return;
node->ref_count -= 1;
if (node->ref_count > 0)
return;
node->class->free (node);
}
void
gsk_sl_node_print (GskSlNode *node,
GString *string)
{
node->class->print (node, string);
}
guint32
gsk_sl_node_write_spv (const GskSlNode *node,
GskSpvWriter *writer)
{
return node->class->write_spv (node, writer);
}