aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/catalog.h
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
committerToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
commit5a40295c4cf0af5ea8da9ced04a4ce7d3621a080 (patch)
treecb21506e7b04d10b45d6066a0ee1655563d5d52b /src/compiler/catalog.h
Squashed 'flatcc/' content from commit 473da2a
git-subtree-dir: flatcc git-subtree-split: 473da2afa5ca435363f8c5e6569167aee6bc31c5
Diffstat (limited to 'src/compiler/catalog.h')
-rw-r--r--src/compiler/catalog.h217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/compiler/catalog.h b/src/compiler/catalog.h
new file mode 100644
index 0000000..de2947f
--- /dev/null
+++ b/src/compiler/catalog.h
@@ -0,0 +1,217 @@
+#ifndef CATALOG_H
+#define CATALOG_H
+
+#include <stdlib.h>
+#include "symbols.h"
+
+/* Helper to build more intuitive schema data with fully qualified names. */
+
+
+typedef struct entry entry_t;
+typedef entry_t object_entry_t;
+typedef entry_t enum_entry_t;
+typedef entry_t service_entry_t;
+typedef struct scope_entry scope_entry_t;
+
+struct entry {
+ fb_compound_type_t *ct;
+ char *name;
+};
+
+struct scope_entry {
+ fb_scope_t *scope;
+ char *name;
+};
+
+typedef struct catalog catalog_t;
+
+struct catalog {
+ int qualify_names;
+ int nobjects;
+ int nenums;
+ int nservices;
+ size_t name_table_size;
+ object_entry_t *objects;
+ enum_entry_t *enums;
+ service_entry_t *services;
+ char *name_table;
+ object_entry_t *next_object;
+ enum_entry_t *next_enum;
+ service_entry_t *next_service;
+ char *next_name;
+ fb_schema_t *schema;
+};
+
+#include <stdio.h>
+
+static void count_symbol(void *context, fb_symbol_t *sym)
+{
+ catalog_t *catalog = context;
+ fb_ref_t *scope_name;
+ size_t n = 0;
+ fb_compound_type_t *ct;
+
+ if (!(ct = get_compound_if_visible(catalog->schema, sym))) {
+ return;
+ }
+
+ /*
+ * Find out how much space the name requires. We must store each
+ * name in full for sorting because comparing a variable number of
+ * parent scope names is otherwise tricky.
+ */
+ if (catalog->qualify_names) {
+ scope_name = ct->scope->name;
+ while (scope_name) {
+ /* + 1 for '.'. */
+ n += (size_t)scope_name->ident->len + 1;
+ scope_name = scope_name->link;
+ }
+ }
+ /* + 1 for '\0'. */
+ n += (size_t)sym->ident->len + 1;
+ catalog->name_table_size += n;
+
+ switch (sym->kind) {
+ case fb_is_struct:
+ case fb_is_table:
+ ++catalog->nobjects;
+ break;
+ case fb_is_union:
+ case fb_is_enum:
+ ++catalog->nenums;
+ break;
+ case fb_is_rpc_service:
+ ++catalog->nservices;
+ break;
+ default: return;
+ }
+}
+
+static void install_symbol(void *context, fb_symbol_t *sym)
+{
+ catalog_t *catalog = context;
+ fb_ref_t *scope_name;
+ int n = 0;
+ char *s, *name;
+ fb_compound_type_t *ct;
+
+ if (!(ct = get_compound_if_visible(catalog->schema, sym))) {
+ return;
+ }
+
+ s = catalog->next_name;
+ name = s;
+ if (catalog->qualify_names) {
+ scope_name = ct->scope->name;
+ while (scope_name) {
+ n = (int)scope_name->ident->len;
+ memcpy(s, scope_name->ident->text, (size_t)n);
+ s += n;
+ *s++ = '.';
+ scope_name = scope_name->link;
+ }
+ }
+ n = (int)sym->ident->len;
+ memcpy(s, sym->ident->text, (size_t)n);
+ s += n;
+ *s++ = '\0';
+ catalog->next_name = s;
+
+ switch (sym->kind) {
+ case fb_is_struct:
+ case fb_is_table:
+ catalog->next_object->ct = (fb_compound_type_t *)sym;
+ catalog->next_object->name = name;
+ catalog->next_object++;
+ break;
+ case fb_is_union:
+ case fb_is_enum:
+ catalog->next_enum->ct = (fb_compound_type_t *)sym;
+ catalog->next_enum->name = name;
+ catalog->next_enum++;
+ break;
+ case fb_is_rpc_service:
+ catalog->next_service->ct = (fb_compound_type_t *)sym;
+ catalog->next_service->name = name;
+ catalog->next_service++;
+ break;
+ default: break;
+ }
+}
+
+static void count_symbols(void *context, fb_scope_t *scope)
+{
+ fb_symbol_table_visit(&scope->symbol_index, count_symbol, context);
+}
+
+static void install_symbols(void *context, fb_scope_t *scope)
+{
+ fb_symbol_table_visit(&scope->symbol_index, install_symbol, context);
+}
+
+static int compare_entries(const void *x, const void *y)
+{
+ return strcmp(((const entry_t *)x)->name, ((const entry_t *)y)->name);
+}
+
+static void sort_entries(entry_t *entries, int count)
+{
+ int i;
+
+ qsort(entries, (size_t)count, sizeof(entries[0]), compare_entries);
+
+ for (i = 0; i < count; ++i) {
+ entries[i].ct->export_index = (size_t)i;
+ }
+}
+
+static void clear_catalog(catalog_t *catalog)
+{
+ if (catalog->objects) {
+ free(catalog->objects);
+ }
+ if (catalog->enums) {
+ free(catalog->enums);
+ }
+ if (catalog->services) {
+ free(catalog->services);
+ }
+ if (catalog->name_table) {
+ free(catalog->name_table);
+ }
+ memset(catalog, 0, sizeof(*catalog));
+}
+
+static int build_catalog(catalog_t *catalog, fb_schema_t *schema, int qualify_names, fb_scope_table_t *index)
+{
+ memset(catalog, 0, sizeof(*catalog));
+ catalog->qualify_names = qualify_names;
+ catalog->schema = schema;
+
+ /* Build support datastructures before export. */
+ fb_scope_table_visit(index, count_symbols, catalog);
+ catalog->objects = calloc((size_t)catalog->nobjects, sizeof(catalog->objects[0]));
+ catalog->enums = calloc((size_t)catalog->nenums, sizeof(catalog->enums[0]));
+ catalog->services = calloc((size_t)catalog->nservices, sizeof(catalog->services[0]));
+ catalog->name_table = malloc(catalog->name_table_size);
+ catalog->next_object = catalog->objects;
+ catalog->next_enum = catalog->enums;
+ catalog->next_service = catalog->services;
+ catalog->next_name = catalog->name_table;
+ if ((!catalog->objects && catalog->nobjects > 0) ||
+ (!catalog->enums && catalog->nenums > 0) ||
+ (!catalog->services && catalog->nservices > 0) ||
+ (!catalog->name_table && catalog->name_table_size > 0)) {
+ clear_catalog(catalog);
+ return -1;
+ }
+ fb_scope_table_visit(index, install_symbols, catalog);
+ /* Presort objects and enums because the sorted index is required in Type tables. */
+ sort_entries(catalog->objects, catalog->nobjects);
+ sort_entries(catalog->enums, catalog->nenums);
+ sort_entries(catalog->services, catalog->nservices);
+ return 0;
+}
+
+#endif /* CATALOG_H */