lang: Create modules and dependencies on request
This commit is contained in:
parent
bd2cac8074
commit
0fd1f67923
3 changed files with 89 additions and 15 deletions
|
@ -62,6 +62,7 @@ int lang_main(void) {
|
|||
VmState state = vm_create();
|
||||
test_rational(state);
|
||||
test_module(state);
|
||||
modules_free(state);
|
||||
vm_destroy(&state);
|
||||
printf("All done!\n");
|
||||
return 0;
|
||||
|
|
|
@ -23,6 +23,30 @@ static ModuleInfo *modules_list[] = {
|
|||
};
|
||||
#undef X
|
||||
|
||||
// Size of a stack in elemenets
|
||||
#define STACK_SIZE 64
|
||||
|
||||
// A stack of ModuleInfo pointers
|
||||
struct module_stack {
|
||||
const ModuleInfo *elems[STACK_SIZE];
|
||||
int next;
|
||||
};
|
||||
|
||||
// A stack of Objects
|
||||
struct object_stack {
|
||||
Object elems[STACK_SIZE];
|
||||
int next;
|
||||
};
|
||||
|
||||
// A mapping mapping between ModuleInfo and Object
|
||||
// Each stack element should have a corresponding element
|
||||
// in the other stack at the same index
|
||||
struct module_mapping {
|
||||
struct module_stack infos;
|
||||
struct object_stack objects;
|
||||
};
|
||||
|
||||
// Finds a ModuleInfo by name
|
||||
static const ModuleInfo *info_by_name(const char *name) {
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(modules_list); ++i) {
|
||||
ModuleInfo *info = modules_list[i];
|
||||
|
@ -32,12 +56,7 @@ static const ModuleInfo *info_by_name(const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct module_stack {
|
||||
ModuleInfo *elems[64];
|
||||
int next;
|
||||
};
|
||||
|
||||
// Checks if an info is in a stack
|
||||
// Checks if a ModuleInfo is in a module_stack
|
||||
static int in_stack(const ModuleInfo *info, struct module_stack *stack) {
|
||||
for (int i = 0; i < stack->next; ++i) {
|
||||
ModuleInfo *elem = stack->elems[i];
|
||||
|
@ -48,8 +67,8 @@ static int in_stack(const ModuleInfo *info, struct module_stack *stack) {
|
|||
}
|
||||
|
||||
// Traverses a module use dependency tree, checking for circular dependencies
|
||||
// This uses a depth-first search with a stack for traversing
|
||||
// The resulting visited list is the reverse load order
|
||||
// The result is the visited stack containing modules in load order
|
||||
// This function works using a depth-first search
|
||||
static void traverse_module_uses(
|
||||
const ModuleInfo *start, struct module_stack *visited) {
|
||||
static struct module_stack traversing = {0};
|
||||
|
@ -57,37 +76,86 @@ static void traverse_module_uses(
|
|||
abort_print("Modules too big to traverse");
|
||||
if (in_stack(start, visited))
|
||||
return;
|
||||
// Push the start module to the top of the traversal stack
|
||||
traversing.next = 0;
|
||||
traversing.elems[traversing.next++] = start;
|
||||
do {
|
||||
// Use the top of traversal stack as our current module
|
||||
ModuleInfo *cur = traversing.elems[traversing.next - 1];
|
||||
// Iterate through module uses
|
||||
const char **use = cur->uses;
|
||||
while (*use) {
|
||||
// Find the info associated with the use
|
||||
const ModuleInfo *info = info_by_name(*use);
|
||||
if (info == NULL)
|
||||
abort_print("Couldn't find module");
|
||||
// If we are already traversing this use then
|
||||
// we have a cyclic dependency. Bail
|
||||
if (in_stack(info, &traversing))
|
||||
abort_print("Cyclic dependency found");
|
||||
// If this use is unvisited, push it to the stack
|
||||
// and traverse it
|
||||
if (!in_stack(info, visited)) {
|
||||
traversing.elems[traversing.next++] = info;
|
||||
break;
|
||||
}
|
||||
use++;
|
||||
}
|
||||
// No unvisited uses? Mark this module as visited and
|
||||
// retry the module we were traversing before
|
||||
if (*use == NULL) {
|
||||
traversing.elems[traversing.next--] = NULL;
|
||||
visited->elems[visited->next++] = cur;
|
||||
}
|
||||
} while (traversing.next != -1);
|
||||
} while (traversing.next != 0);
|
||||
|
||||
// The traversal stack is now empty, all done!
|
||||
}
|
||||
|
||||
// Finds a module object by its info using a module_mapping
|
||||
Object get_module_by_info(
|
||||
struct module_mapping *mapping, const ModuleInfo *info) {
|
||||
struct module_stack *infos = &mapping->infos;
|
||||
for (int i = 0; i < infos->next; ++i) {
|
||||
ModuleInfo *elem = infos->elems[i];
|
||||
if (elem == info)
|
||||
return mapping->objects.elems[i];
|
||||
}
|
||||
abort_print("Couldn't find module by info");
|
||||
}
|
||||
|
||||
// Creates modules and stores them in a mapping
|
||||
void create_modules(VmState state, struct module_mapping *mapping) {
|
||||
struct module_stack *infos = &mapping->infos;
|
||||
struct object_stack *objs = &mapping->objects;
|
||||
for (int i = objs->next; i < infos->next; ++i) {
|
||||
ModuleInfo *info = infos->elems[i];
|
||||
Object module = info->create(state);
|
||||
objs->elems[objs->next++] = module;
|
||||
}
|
||||
}
|
||||
|
||||
// Global mapping used for finding and freeing modules
|
||||
static struct module_mapping mapping = {0};
|
||||
|
||||
Object module_find(VmState state, const char *name) {
|
||||
const ModuleInfo *info = info_by_name(name);
|
||||
vm_abort_if(state, !info, "Unable to find module!");
|
||||
static struct module_stack visited = {0};
|
||||
if (sizeof(modules_list) > sizeof(visited.elems))
|
||||
if (sizeof(modules_list) > sizeof(mapping.infos.elems))
|
||||
abort_print("Modules too big to track");
|
||||
traverse_module_uses(info, &visited); // TODO: Does nothing
|
||||
traverse_module_uses(info, &visited); // TODO: Does nothing
|
||||
return info->create(state);
|
||||
if (sizeof(modules_list) > sizeof(mapping.objects.elems))
|
||||
abort_print("Modules too big to load");
|
||||
traverse_module_uses(info, &mapping.infos);
|
||||
create_modules(state, &mapping);
|
||||
Object module = get_module_by_info(&mapping, info);
|
||||
// Create a new reference for the caller
|
||||
object_hold(state, module);
|
||||
return module;
|
||||
}
|
||||
|
||||
void modules_free(VmState state) {
|
||||
struct object_stack *objs = &mapping.objects;
|
||||
for (int i = 0; i < objs->next; ++i)
|
||||
object_drop(state, &objs->elems[i]);
|
||||
memset(&mapping, 0, sizeof(mapping));
|
||||
}
|
||||
|
|
|
@ -7,11 +7,16 @@
|
|||
#include "types.h"
|
||||
|
||||
// Finds a module by its name
|
||||
// This internally loads the module and dependencies
|
||||
// A new reference is created for the caller
|
||||
Object module_find(VmState state, const char *name);
|
||||
|
||||
// Frees all modules loaded internally
|
||||
// You must call this at the end of your program
|
||||
void modules_free(VmState state);
|
||||
|
||||
// The following section is an internal API for use only with
|
||||
// the compiler's C code generator. Do not use for regular C code.
|
||||
|
||||
#ifdef MODULE_INTERNAL_API
|
||||
|
||||
// Data structure for creating a module
|
||||
|
|
Loading…
Add table
Reference in a new issue