Mark Poliakov 91961bcec5 Lots of changes with long commit message again
1. (list ...)
2. string-* functions
3. (native str) to resolve native functions at runtime
4. Memory fuckups in compiler core unit loading
5. Now can call non-identifiers in compiler
2021-04-09 00:18:48 +03:00

156 lines
5.1 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "compile.h"
#include "binary.h"
#include "parse.h"
#include "hash.h"
#include "unit.h"
#include "node.h"
static void write_unit(FILE *fp, struct unit *u) {
struct bin_header hdr;
size_t offset = sizeof(struct bin_header);
// Step 1 generate offsets
hdr.magic = 0xCEBAB123;
hdr.version = 1;
hdr.global_pool_size = u->global.var_counter;
hdr.unit_table_offset = offset;
hdr.unit_table_size = u->ext_units.size;
for (size_t i = 0; i < u->ext_units.size; ++i) {
struct ext_unit *unit = vector_ref(&u->ext_units, i);
offset += sizeof(struct bin_unit_entry) + strlen(unit->name) + 1;
}
hdr.ref_table_offset = offset;
hdr.ref_table_size = u->ext_refs.size;
for (size_t i = 0; i < u->ext_refs.size; ++i) {
struct ext_ref *ref = vector_ref(&u->ext_refs, i);
offset += sizeof(struct bin_ref_entry) + strlen(ref->name) + 1;
}
hdr.export_table_offset = offset;
hdr.export_table_size = u->exports.size;
for (size_t i = 0; i < u->exports.size; ++i) {
struct export *export = vector_ref(&u->exports, i);
offset += sizeof(struct bin_export_entry) + strlen(export->name) + 1;
}
hdr.func_table_offset = offset;
hdr.func_table_size = u->functions.size;
for (size_t i = 0; i < u->functions.size; ++i) {
struct function *fn = vector_ref(&u->functions, i);
offset += sizeof(struct bin_func_entry) + fn->bytecode.size * sizeof(uint32_t);
}
hdr.string_table_offset = offset;
hdr.string_table_size = u->strtab.size;
fwrite(&hdr, 1, sizeof(struct bin_header), fp);
for (size_t i = 0; i < u->ext_units.size; ++i) {
struct ext_unit *unit = vector_ref(&u->ext_units, i);
struct bin_unit_entry bin_unit;
bin_unit.name_len = strlen(unit->name);
fwrite(&bin_unit, 1, sizeof(struct bin_unit_entry), fp);
fwrite(unit->name, 1, bin_unit.name_len + 1, fp);
}
for (size_t i = 0; i < u->ext_refs.size; ++i) {
struct ext_ref *ref = vector_ref(&u->ext_refs, i);
struct bin_ref_entry bin_ref;
bin_ref.unit_index = ref->unit_index;
bin_ref.name_len = strlen(ref->name);
fwrite(&bin_ref, 1, sizeof(struct bin_ref_entry), fp);
fwrite(ref->name, 1, bin_ref.name_len + 1, fp);
}
for (size_t i = 0; i < u->exports.size; ++i) {
struct export *export = vector_ref(&u->exports, i);
struct bin_export_entry bin_export;
bin_export.value = export->index;
bin_export.name_len = strlen(export->name);
fwrite(&bin_export, 1, sizeof(struct bin_export_entry), fp);
fwrite(export->name, 1, bin_export.name_len + 1, fp);
}
for (size_t i = 0; i < u->functions.size; ++i) {
struct function *fn = vector_ref(&u->functions, i);
struct bin_func_entry bin_func;
bin_func.argc = fn->argc;
bin_func.local_count = fn->local_count;
bin_func.len = fn->bytecode.size * sizeof(uint32_t);
fwrite(&bin_func, 1, sizeof(struct bin_func_entry), fp);
fwrite(fn->bytecode.data, 1, fn->bytecode.size * sizeof(uint32_t), fp);
}
for (size_t i = 0; i < u->strtab.size; ++i) {
char **ref = vector_ref(&u->strtab, i);
const char *str = *ref;
uint32_t len = strlen(str);
fwrite(&len, 1, sizeof(uint32_t), fp);
fwrite(str, 1, len + 1, fp);
}
}
int main(int argc, char **argv) {
const char *input, *output;
assert(argc == 3);
input = argv[1];
output = argv[2];
struct unit unit;
struct node *program;
FILE *fp;
int res;
unit_init(&unit);
fp = fopen(input, "r");
assert(fp);
program = vm_load_file(fp);
fclose(fp);
struct function *main = unit_lambda(&unit);
main->args = NULL;
main->body = program;
unit.global.owner = main;
emit_function(&unit.global, main);
// Collect unit exports
for (struct node *item = program; item; item = cdr(item)) {
struct node *expr = car(item);
if (pair_q(expr)) {
struct node *name = car(expr);
if (ident_q(name) && !strcmp(name->n_ident, "export")) {
for (struct node *export_item = cdr(expr); export_item; export_item = cdr(export_item)) {
struct export *export;
size_t index;
struct node *id = car(export_item);
assert(ident_q(id));
if ((res = unit_lookup_global(&unit, id->n_ident, &index)) != 0) {
fprintf(stderr, "Cannot export undefined value %s\n", id->n_ident);
return -1;
}
export = vector_append(&unit.exports);
export->index = index;
assert(strlen(id->n_ident) < sizeof(export->name) - 1);
strcpy(export->name, id->n_ident);
}
}
}
}
fp = fopen(output, "wb");
if (!fp) {
perror(output);
return -1;
}
write_unit(fp, &unit);
fclose(fp);
return 0;
}