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
156 lines
5.1 KiB
C
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;
|
|
}
|