Commit 6df1d2f5 authored by Christian Hergert's avatar Christian Hergert

initial commit

parents
build
*.swp
__pycache__
project('gir2rst', 'c')
cc = meson.get_compiler('c')
gnome = import('gnome')
glib_dep = dependency('gio-2.0')
gir_dep = dependency('gobject-introspection-1.0')
xml_dep = dependency('libxml-2.0')
tmpl_dep = dependency('template-glib-1.0')
girst_resources = gnome.compile_resources(
'girst-resources',
'src/girst.gresource.xml',
c_name: 'girst',
source_dir: 'src',
)
girst_sources = [
'src/parser/girst-alias.c',
'src/parser/girst-alias.h',
'src/parser/girst-annotation.c',
'src/parser/girst-annotation.h',
'src/parser/girst-array.c',
'src/parser/girst-array.h',
'src/parser/girst-bitfield.c',
'src/parser/girst-bitfield.h',
'src/parser/girst-c-include.c',
'src/parser/girst-c-include.h',
'src/parser/girst-callback.c',
'src/parser/girst-callback.h',
'src/parser/girst-class.c',
'src/parser/girst-class.h',
'src/parser/girst-constant.c',
'src/parser/girst-constant.h',
'src/parser/girst-constructor.c',
'src/parser/girst-constructor.h',
'src/parser/girst-doc-deprecated.c',
'src/parser/girst-doc-deprecated.h',
'src/parser/girst-doc-stability.c',
'src/parser/girst-doc-stability.h',
'src/parser/girst-doc-version.c',
'src/parser/girst-doc-version.h',
'src/parser/girst-doc.c',
'src/parser/girst-doc.h',
'src/parser/girst-enumeration.c',
'src/parser/girst-enumeration.h',
'src/parser/girst-field.c',
'src/parser/girst-field.h',
'src/parser/girst-function.c',
'src/parser/girst-function.h',
'src/parser/girst-glib-boxed.c',
'src/parser/girst-glib-boxed.h',
'src/parser/girst-glib-signal.c',
'src/parser/girst-glib-signal.h',
'src/parser/girst-implements.c',
'src/parser/girst-implements.h',
'src/parser/girst-include.c',
'src/parser/girst-include.h',
'src/parser/girst-instance-parameter.c',
'src/parser/girst-instance-parameter.h',
'src/parser/girst-interface.c',
'src/parser/girst-interface.h',
'src/parser/girst-member.c',
'src/parser/girst-member.h',
'src/parser/girst-method.c',
'src/parser/girst-method.h',
'src/parser/girst-namespace.c',
'src/parser/girst-namespace.h',
'src/parser/girst-package.c',
'src/parser/girst-package.h',
'src/parser/girst-parameter.c',
'src/parser/girst-parameter.h',
'src/parser/girst-parameters.c',
'src/parser/girst-parameters.h',
'src/parser/girst-parser-object.c',
'src/parser/girst-parser-types.h',
'src/parser/girst-parser.c',
'src/parser/girst-parser.h',
'src/parser/girst-prerequisite.c',
'src/parser/girst-prerequisite.h',
'src/parser/girst-property.c',
'src/parser/girst-property.h',
'src/parser/girst-record.c',
'src/parser/girst-record.h',
'src/parser/girst-repository.c',
'src/parser/girst-repository.h',
'src/parser/girst-return-value.c',
'src/parser/girst-return-value.h',
'src/parser/girst-type.c',
'src/parser/girst-type.h',
'src/parser/girst-union.c',
'src/parser/girst-union.h',
'src/parser/girst-varargs.c',
'src/parser/girst-varargs.h',
'src/parser/girst-virtual-method.c',
'src/parser/girst-virtual-method.h',
'src/girst-cache.c',
'src/girst-cache.h',
'src/girst-generator.c',
'src/girst-generator.h',
'src/girst-util.c',
'src/girst-util.h',
'src/girst-main.c',
]
mapfile = 'src/girst.map'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
gir2rst = executable('gir2rst', girst_sources + [girst_resources[0]],
dependencies: [ glib_dep, gir_dep, tmpl_dep, xml_dep, cc.find_library('dl') ],
link_args: ['-Wl,--no-undefined', '-rdynamic', vflag],
link_depends: mapfile,
install: true,
)
girdir = join_paths(get_option('datadir'), 'gir-1.0')
typelibdir = join_paths(get_option('libdir'), 'girepository-1.0')
girst_gir = gnome.generate_gir(gir2rst,
sources: girst_sources,
nsversion: '1.0',
namespace: 'Girst',
symbol_prefix: 'girst',
identifier_prefix: 'Girst',
includes: [ 'Gio-2.0' ],
install: true,
install_dir_gir: girdir,
install_dir_typelib: typelibdir,
)
/* girst-cache.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define G_LOG_DOMAIN "girst-cache"
#include "parser/girst-alias.h"
#include "parser/girst-bitfield.h"
#include "parser/girst-class.h"
#include "parser/girst-callback.h"
#include "parser/girst-enumeration.h"
#include "parser/girst-interface.h"
#include "parser/girst-record.h"
#include "parser/girst-union.h"
#include "girst-cache.h"
#include "girst-util.h"
static GHashTable *cache;
void
girst_cache_set (const gchar *ns_name,
GirstRepository *repository)
{
g_return_if_fail (ns_name);
g_return_if_fail (GIRST_IS_REPOSITORY (repository));
if (cache == NULL)
cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
g_hash_table_insert (cache, g_strdup (ns_name), g_object_ref (repository));
}
/**
* girst_cache_get:
*
* Returns: (nullable) (transfer none): A #GirstRepository
*/
GirstRepository *
girst_cache_get (const gchar *name)
{
g_return_val_if_fail (name != NULL, NULL);
return cache ? g_hash_table_lookup (cache, name) : NULL;
}
/**
* girst_cache_resolve:
*
* Returns: (transfer none) (nullable): A #GirstParserObject or %NULL
*/
GirstParserObject *
girst_cache_resolve (const gchar *ns_name,
const gchar *type_name)
{
GirstRepository *repository;
GirstParserObject *ns;
GPtrArray *children;
if (cache == NULL)
return NULL;
if (!(repository = g_hash_table_lookup (cache, ns_name)) ||
!(ns = girst_parser_object_first_typed (GIRST_PARSER_OBJECT (repository), GIRST_TYPE_NAMESPACE)))
return NULL;
children = girst_parser_object_get_children (ns);
for (guint i = 0; i < children->len; i++)
{
GirstParserObject *obj = g_ptr_array_index (children, i);
#define CHECK_SIMPLE(T, t, func) \
else if (GIRST_IS_##T (obj) && \
girst_str_equal0 (type_name, \
girst_##t##_get_##func (GIRST_##T (obj)))) \
return obj;
if (0) {}
CHECK_SIMPLE (ALIAS, alias, name)
CHECK_SIMPLE (BITFIELD, bitfield, name)
CHECK_SIMPLE (CALLBACK, callback, name)
CHECK_SIMPLE (CLASS, class, name)
CHECK_SIMPLE (INTERFACE, interface, name)
CHECK_SIMPLE (ENUMERATION, enumeration, name)
CHECK_SIMPLE (RECORD, record, name)
CHECK_SIMPLE (UNION, union, name)
#undef CHECK_SIMPLE
}
return NULL;
}
/**
* girst_cache_foreach: (skip)
* @foreach_func: (scope call): A func to call
* @user_data: user data for @foreach_func
*
* Calls @foreach_func for each GirstRepository cached.
*/
void
girst_cache_foreach (GFunc foreach_func,
gpointer user_data)
{
GHashTableIter iter;
gpointer value;
if (cache == NULL)
return;
g_hash_table_iter_init (&iter, cache);
while (g_hash_table_iter_next (&iter, NULL, &value))
foreach_func (value, user_data);
}
/* girst-cache.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gio/gio.h>
#include "parser/girst-parser-types.h"
G_BEGIN_DECLS
void girst_cache_set (const gchar *ns_name,
GirstRepository *repository);
GirstRepository *girst_cache_get (const gchar *name);
GirstParserObject *girst_cache_resolve (const gchar *ns_name,
const gchar *type_name);
void girst_cache_foreach (GFunc foreach_func,
gpointer user_data);
G_END_DECLS
/* girst-generator.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define G_LOG_DOMAIN "girst-generator"
#include <errno.h>
#include <glib/gstdio.h>
#include <tmpl-glib.h>
#include "girst-generator.h"
#include "parser/girst-namespace.h"
struct _GirstGenerator
{
GObject parent_instance;
TmplTemplateLocator *locator;
GirstRepository *repository;
gchar *outdir;
GirstLanguage language;
};
G_DEFINE_TYPE (GirstGenerator, girst_generator, G_TYPE_OBJECT)
static void
girst_generator_finalize (GObject *object)
{
GirstGenerator *self = (GirstGenerator *)object;
g_clear_pointer (&self->outdir, g_free);
g_clear_object (&self->repository);
g_clear_object (&self->locator);
G_OBJECT_CLASS (girst_generator_parent_class)->finalize (object);
}
static void
girst_generator_class_init (GirstGeneratorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = girst_generator_finalize;
}
static void
girst_generator_init (GirstGenerator *self)
{
self->locator = tmpl_template_locator_new ();
tmpl_template_locator_prepend_search_path (self->locator, "resource:///templates/");
}
static TmplTemplate *
girst_generator_create_template (GirstGenerator *self,
const gchar *name,
GError **error)
{
g_autoptr(GInputStream) stream = NULL;
g_autoptr(TmplTemplate) template = NULL;
g_autofree gchar *path = NULL;
g_assert (GIRST_IS_GENERATOR (self));
template = tmpl_template_new (self->locator);
path = g_strdup_printf ("/templates/%s", name);
if (!tmpl_template_parse_resource (template, path, NULL, error))
return NULL;
return g_steal_pointer (&template);
}
G_GNUC_NULL_TERMINATED static GOutputStream *
girst_generator_create_stream (GirstGenerator *self,
const gchar *first_path,
...)
{
g_autoptr(GPtrArray) ar = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *dir = NULL;
g_autoptr(GFile) file = NULL;
const gchar *name;
va_list args;
g_assert (GIRST_IS_GENERATOR (self));
g_assert (first_path != NULL);
ar = g_ptr_array_new ();
va_start (args, first_path);
g_ptr_array_add (ar, (gchar *)self->outdir);
g_ptr_array_add (ar, (gchar *)first_path);
while (NULL != (name = va_arg (args, const gchar *)))
g_ptr_array_add (ar, (gchar *)name);
g_ptr_array_add (ar, NULL);
va_end (args);
path = g_build_filenamev ((gchar **)ar->pdata);
file = g_file_new_for_path (path);
dir = g_path_get_dirname (path);
g_mkdir_with_parents (dir, 0750);
return G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
G_FILE_CREATE_REPLACE_DESTINATION,
NULL, NULL));
}
GirstGenerator *
girst_generator_new (GirstRepository *repository,
const gchar *outdir,
GirstLanguage language)
{
GirstGenerator *self;
g_return_val_if_fail (GIRST_IS_REPOSITORY (repository), NULL);
g_return_val_if_fail (language != 0, NULL);
self = g_object_new (GIRST_TYPE_GENERATOR, NULL);
self->outdir = g_strdup (outdir ? outdir : "generated");
self->repository = g_object_ref (repository);
self->language = language;
return self;
}
static gboolean
resolver_cb (TmplScope *scope,
const gchar *name,
TmplSymbol **symbol,
gpointer user_data)
{
g_debug ("Missing symbol %s", name);
*symbol = tmpl_symbol_new ();
tmpl_symbol_assign_string (*symbol, NULL);
return TRUE;
}
static gboolean
girst_generator_generate_namespace (GirstGenerator *self,
GirstRepository *repository,
GirstNamespace *ns,
GError **error)
{
g_autofree gchar *dir = NULL;
struct {
const gchar *in_name;
const gchar *out_name;
const gchar *subdir;
const gchar *subrst;
const gchar *var;
GType check_type;
} info[] = {
{ "aliases.rst.tmpl", "aliases.rst", "aliases", NULL, NULL, GIRST_TYPE_ALIAS },
{ "bitfields.rst.tmpl", "bitfields.rst", "bitfields", "bitfield.rst.tmpl", "bitfield", GIRST_TYPE_BITFIELD },
{ "classes.rst.tmpl", "classes.rst", "classes", "class.rst.tmpl", "class", GIRST_TYPE_CLASS },
{ "constants.rst.tmpl", "constants.rst", NULL, NULL, NULL, GIRST_TYPE_CONSTANT },
{ "enumerations.rst.tmpl", "enumerations.rst", "enumerations", "enumeration.rst.tmpl", "enum", GIRST_TYPE_ENUMERATION },
{ "functions.rst.tmpl", "functions.rst", NULL, NULL, NULL, GIRST_TYPE_FUNCTION },
{ "namespace.rst.tmpl", "index.rst", NULL, NULL, NULL, G_TYPE_INVALID },
{ "interfaces.rst.tmpl", "interface.rst", "interfaces", "interface.rst.tmpl", "interface", GIRST_TYPE_INTERFACE },
{ "records.rst.tmpl", "records.rst", "records", "record.rst.tmpl", "record", GIRST_TYPE_RECORD },
};
g_assert (GIRST_IS_GENERATOR (self));
g_assert (GIRST_IS_REPOSITORY (repository));
g_assert (GIRST_IS_NAMESPACE (ns));
dir = g_strdup_printf ("%s-%s",
girst_namespace_get_name (ns),
girst_namespace_get_version (ns));
for (guint i = 0; i < G_N_ELEMENTS (info); i++)
{
const gchar *in_name = info[i].in_name;
const gchar *out_name = info[i].out_name;
const gchar *subdir = info[i].subdir;
const gchar *subrst = info[i].subrst;
const gchar *var = info[i].var;
GType type = info[i].check_type;
g_autoptr(GOutputStream) stream = NULL;
g_autoptr(TmplTemplate) template = NULL;
g_autoptr(TmplScope) scope = NULL;
g_autoptr(GListModel) typed_children = NULL;
guint len;
if (type && !girst_parser_object_has_child_typed (GIRST_PARSER_OBJECT (ns), type))
continue;
if (!(stream = girst_generator_create_stream (self, dir, out_name, NULL)))
{
g_set_error (error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Failed to create IO stream in %s", dir);
return FALSE;
}
if (!(template = girst_generator_create_template (self, in_name, error)))
return FALSE;
scope = tmpl_scope_new ();
tmpl_scope_set_object (scope, "repository", repository);
tmpl_scope_set_object (scope, "namespace", ns);
/* Member missing fallback */
tmpl_scope_set_resolver (scope, resolver_cb, NULL, NULL);
if (!tmpl_template_expand (template, stream, scope, NULL, error))
return FALSE;
if (!g_output_stream_close (stream, NULL, error))
return FALSE;
g_clear_object (&stream);
g_clear_object (&template);
if (!subdir || !var)
continue;
typed_children = girst_parser_object_get_children_typed (GIRST_PARSER_OBJECT (ns), type);
len = g_list_model_get_n_items (typed_children);
for (guint j = 0; j < len; j++)
{
g_autoptr(GirstParserObject) obj = g_list_model_get_item (typed_children, j);
g_autofree gchar *name = NULL;
g_autofree gchar *filename = NULL;
g_object_get (obj, "c-type", &name, NULL);
filename = g_strdup_printf ("%s.rst", name);
if (!(stream = girst_generator_create_stream (self, dir, subdir, filename, NULL)))
{
g_set_error (error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Failed to create IO stream in %s", dir);
return FALSE;
}
tmpl_scope_set_object (scope, var, obj);
if (!(template = girst_generator_create_template (self, subrst, error)))
return FALSE;
if (!tmpl_template_expand (template, stream, scope, NULL, error))
return FALSE;
if (!g_output_stream_close (stream, NULL, error))
return FALSE;
tmpl_scope_set_object (scope, var, NULL);
g_clear_object (&template);
g_clear_object (&stream);
}
}
return TRUE;
}
static gboolean
girst_generator_generate_repository (GirstGenerator *self,
GirstRepository *repository,
GError **error)
{
GPtrArray *children;
g_assert (GIRST_IS_GENERATOR (self));
g_assert (GIRST_IS_REPOSITORY (repository));
children = girst_parser_object_get_children (GIRST_PARSER_OBJECT (repository));
for (guint i = 0; i < children->len; i++)
{
GirstParserObject *child = g_ptr_array_index (children, i);
if (GIRST_IS_NAMESPACE (child))
return girst_generator_generate_namespace (self, repository, GIRST_NAMESPACE (child), error);
}
return TRUE;
}
gboolean
girst_generator_generate (GirstGenerator *self,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (GIRST_IS_GENERATOR (self), FALSE);
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
if (g_mkdir_with_parents (self->outdir, 0750) != 0)
{
g_set_error_literal (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
g_strerror (errno));
return FALSE;
}
if (!girst_generator_generate_repository (self, self->repository, error))
return FALSE;
return TRUE;
}
/* girst-generator.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "parser/girst-repository.h"
#include "girst-util.h"
G_BEGIN_DECLS
#define GIRST_TYPE_GENERATOR (girst_generator_get_type())
G_DECLARE_FINAL_TYPE (GirstGenerator, girst_generator, GIRST, GENERATOR, GObject)
GirstGenerator *girst_generator_new (GirstRepository *repository,
const gchar *outdir,
GirstLanguage language);
gboolean girst_generator_generate (GirstGenerator *self,
GCancellable *cancellable,
GError **error);
G_END_DECLS
/* girst-main.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gio/gio.h>
#include <girepository.h>
#include <glib/gi18n.h>
#include <string.h>
#include <stdlib.h>
#include "girst-cache.h"
#include "girst-generator.h"
#include "parser/girst-parser.h"
#include "parser/girst-repository.h"
static gchar *language;
static gchar *outdir;
static const GOptionEntry main_entries[] = {
{ "outdir", 'o', 0, G_OPTION_ARG_FILENAME, &outdir,
"Location to store generated files",
"DIR" },
{ "language", 'l', 0, G_OPTION_ARG_STRING, &language,
"Source code language to generate (C)",
"LANG" },
{ NULL }
};
static void
foreach_repository_cb (gpointer data,
gpointer user_data)
{
g_autoptr(GirstGenerator) generator = NULL;
GirstRepository *repository = data;
g_autoptr(GError) error = NULL;
gint *exit_code = user_data;