gskslpreprocessor: Implement #include

This commit is contained in:
Benjamin Otte
2017-10-02 05:26:20 +02:00
parent 35476639c4
commit c5a1eaf1a1
4 changed files with 137 additions and 6 deletions

View File

@@ -146,6 +146,7 @@ gsk_code_source_load (GskCodeSource *source,
error))
return NULL;
return g_bytes_new_take (data, length);
source->bytes = g_bytes_new_take (data, length);
return g_bytes_ref (source->bytes);
}

View File

@@ -189,6 +189,47 @@ gsk_sl_compiler_copy_defines (GskSlCompiler *compiler)
return copy;
}
GskCodeSource *
gsk_sl_compiler_resolve_include (GskSlCompiler *compiler,
GskCodeSource *source,
gboolean local,
const char *name,
GError **error)
{
GskCodeSource *result;
GBytes *bytes;
if (local)
{
GFile *source_file = gsk_code_source_get_file (source);
if (source_file)
{
GFile *parent, *file;
parent = g_file_get_parent (source_file);
file = g_file_resolve_relative_path (parent, name);
result = gsk_code_source_new_for_file (file);
g_object_unref (parent);
g_object_unref (file);
bytes = gsk_code_source_load (result, error);
if (bytes)
{
g_bytes_unref (bytes);
return result;
}
g_object_unref (result);
}
}
else
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_EXIST,
"Could not resolve \"%s\" in search path.", name);
}
return NULL;
}
static GskSlProgram *
gsk_sl_compiler_compile (GskSlCompiler *compiler,
GskCodeSource *source)

View File

@@ -25,6 +25,12 @@ G_BEGIN_DECLS
GHashTable * gsk_sl_compiler_copy_defines (GskSlCompiler *compiler);
GskCodeSource * gsk_sl_compiler_resolve_include (GskSlCompiler *compiler,
GskCodeSource *source,
gboolean local,
const char *name,
GError **error);
G_END_DECLS
#endif /* __GSK_SL_COMPILER_PRIVATE_H__ */

View File

@@ -38,6 +38,7 @@ struct _GskSlPreprocessor
GskSlCompiler *compiler;
GskSlTokenizer *tokenizer;
GSList *pending_tokenizers;
GArray *tokens;
GHashTable *defines;
gboolean fatal_error;
@@ -117,6 +118,7 @@ gsk_sl_preprocessor_unref (GskSlPreprocessor *preproc)
g_slist_free (preproc->conditionals);
g_hash_table_destroy (preproc->defines);
g_slist_free_full (preproc->pending_tokenizers, (GDestroyNotify) gsk_sl_tokenizer_unref);
gsk_sl_tokenizer_unref (preproc->tokenizer);
g_object_unref (preproc->compiler);
g_array_free (preproc->tokens, TRUE);
@@ -167,6 +169,54 @@ gsk_sl_preprocessor_in_ignored_conditional (GskSlPreprocessor *preproc)
return FALSE;
}
static gboolean
gsk_sl_preprocessor_include (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
gboolean include_local)
{
GskCodeSource *source;
GError *error = NULL;
source = gsk_sl_compiler_resolve_include (preproc->compiler,
gsk_sl_tokenizer_get_location (preproc->tokenizer)->source,
include_local,
pp->token.str,
&error);
if (source == NULL)
{
gsk_sl_preprocessor_emit_error (preproc, TRUE, &pp->location, error);
gsk_sl_preprocessor_clear_token (pp);
g_error_free (error);
return FALSE;
}
if (g_slist_length (preproc->pending_tokenizers) > 20)
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp->location, "#include nested too deeply.");
gsk_sl_preprocessor_clear_token (pp);
return FALSE;
}
gsk_sl_preprocessor_clear_token (pp);
pp->location = *gsk_sl_tokenizer_get_location (preproc->tokenizer);
gsk_sl_tokenizer_read_token (preproc->tokenizer, &pp->token);
if (!gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_NEWLINE) &&
!gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_EOF))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp->location, "Extra content after #include directive");
gsk_sl_preprocessor_clear_token (pp);
return FALSE;
}
gsk_sl_preprocessor_clear_token (pp);
preproc->pending_tokenizers = g_slist_prepend (preproc->pending_tokenizers, preproc->tokenizer);
preproc->tokenizer = gsk_sl_tokenizer_new (source,
gsk_sl_preprocessor_error_func,
preproc,
NULL);
return TRUE;
}
static gboolean
gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
@@ -188,11 +238,29 @@ gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
return contained_newline || gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_EOF);
}
static void
gsk_sl_preprocessor_handle_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
gboolean was_newline);
static void
gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
GSList *used_defines)
{
if (gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_EOF) &&
preproc->pending_tokenizers)
{
gboolean was_newline;
gsk_sl_tokenizer_unref (preproc->tokenizer);
preproc->tokenizer = preproc->pending_tokenizers->data;
preproc->pending_tokenizers = g_slist_remove (preproc->pending_tokenizers, preproc->tokenizer);
gsk_sl_preprocessor_clear_token (pp);
gsk_sl_preprocessor_next_token (preproc, pp, &was_newline);
gsk_sl_preprocessor_handle_token (preproc, pp, TRUE);
return;
}
if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
{
gsk_sl_preprocessor_clear_token (pp);
@@ -235,11 +303,6 @@ gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
g_array_append_val (preproc->tokens, *pp);
}
static void
gsk_sl_preprocessor_handle_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
gboolean was_newline);
static void
gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
{
@@ -440,6 +503,26 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
return;
}
}
else if (g_str_equal (pp.token.str, "include"))
{
gsk_sl_preprocessor_clear_token (&pp);
if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No filename after #include.");
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
return;
}
if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_STRING))
{
if (gsk_sl_preprocessor_include (preproc, &pp, TRUE))
return;
}
else
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected filename after #include.");
gsk_sl_preprocessor_clear_token (&pp);
}
}
#if 0
else if (g_str_equal (pp.token.str, "line"))
{