thesis-lisp/vm/main.c
2021-04-07 22:24:33 +03:00

136 lines
3.4 KiB
C

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "vmstate.h"
#include "unit.h"
#include "error.h"
#include "load.h"
#include "hash.h"
#include "list.h"
static int lookup_sym(struct vm_unit_info *info,
const char *name,
struct vm_export_entry **ent) {
for (size_t i = 0; i < info->exports.size; ++i) {
struct vm_export_entry *export = vector_ref(&info->exports, i);
if (!strcmp(export->name, name)) {
*ent = export;
return 0;
}
}
return -ERR_SYMBOL_UNDEFINED;
}
static int execute_file(const char *filename) {
FILE *fp;
int res;
struct hash unit_map;
struct hash_pair *pair;
struct list_head unresolved;
struct vm_export_entry *export;
struct vm_ref_entry *ref_entry;
struct vm_state vm;
struct vm_unit_info *info;
struct vm_unresolved_ref *ref;
if ((res = vm_state_init(&vm, 4096)) != 0) {
return res;
}
list_head_init(&unresolved);
if (shash_init(&unit_map, 16) != 0) {
return -ERR_OUT_OF_MEMORY;
}
if ((fp = fopen(filename, "rb")) == NULL) {
return -ERR_IMAGE_IO;
}
// Load main unit
if ((res = vm_load_unit_file(&vm, NULL, &unresolved, fp)) != 0) {
fclose(fp);
return res;
}
fclose(fp);
// Load any referenced units
list_for_each_entry(ref, &unresolved, link) {
struct vm_unit_info *info;
pair = hash_lookup(&unit_map, ref->unit_name);
if (!pair) {
info = malloc(sizeof(struct vm_unit_info));
if (!info) {
return -ERR_OUT_OF_MEMORY;
}
if ((res = vm_load_unit(&vm, info, &unresolved, ref->unit_name)) != 0) {
return res;
}
if (hash_insert(&unit_map, ref->unit_name, info) != 0) {
return -ERR_OUT_OF_MEMORY;
}
}
}
while (!list_empty(&unresolved)) {
ref = list_first_entry(&unresolved, struct vm_unresolved_ref, link);
pair = hash_lookup(&unit_map, ref->unit_name);
assert(pair);
info = pair->value;
// Lookup symbol in that unit
if ((res = lookup_sym(info, ref->sym_name, &export)) != 0) {
return -1;
}
// Resolve the reference
ref_entry = ref->entry;
ref_entry->unit_index = info->index;
if (export->is_native) {
ref_entry->flags = REF_NATIVE;
ref_entry->ref_native = export->ex_native;
} else {
ref_entry->flags = 0;
ref_entry->ref_index = export->ex_index;
}
list_del(&ref->link);
free(ref);
}
for (size_t i = 0; i < unit_map.bucket_count; ++i) {
list_for_each_entry(pair, &unit_map.buckets[i], link) {
info = pair->value;
vector_free(&info->exports);
free(info);
}
}
hash_free(&unit_map);
// Start execution
if ((res = vm_eval_unit(&vm, 0)) != 0) {
return res;
}
vm_state_free(&vm);
return 0;
}
int main(int argc, char **argv) {
int res;
if (argc != 2) {
fprintf(stderr, "Usage: %s INPUT", argv[0]);
return EXIT_FAILURE;
}
if ((res = execute_file(argv[1])) != 0) {
fprintf(stderr, "%s: %s\n", argv[1], vm_strerror(res));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}