moka/lib/compiler.c

266 lines
7.9 KiB
C

#include "compiler.h"
#include "moka.h"
#include "module.h"
#include "path.h"
#include "conf.h"
void compiler_init(struct compiler* self,
struct status* status)
{
assert(self);
self->status = status;
}
void compiler_free(struct compiler* self)
{
assert(self);
}
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog,
struct moka* moka)
{
assert(self); assert(node); assert(prog);
switch (node->kind)
{
case NODE_ROOT: {
for (size_t i=0; i<node->children.size; i++)
{
struct node* child = node->children.data[i];
compiler_compile(self, child, prog, moka);
}
} break;
case NODE_CALL: {
struct node* child = node->children.data[0];
if (strcmp(child->token->value, "quote") == 0)
{
assert(node->children.size == 2);
struct node* arg = node->children.data[1];
compiler_quote(self, arg, prog, moka);
break;
}
if (strcmp(child->token->value, "import") == 0)
{
compiler_import(self, moka, node);
break;
}
for (size_t i=0; i<node->children.size - 1; i++)
{
size_t k = node->children.size - 1 - i;
struct node* mychild = node->children.data[k];
struct value* val = malloc(sizeof(struct value));
value_init_lazy(val, mychild, mychild->line);
size_t addr = prog_add_new_value(prog, val);
prog_add_instruction(prog, OP_PUSH, addr);
}
compiler_compile(self, child, prog, moka);
prog_add_instruction(prog, OP_CALL, node->children.size - 1);
} break;
case NODE_INT: {
struct value* value = malloc(sizeof(struct value));
int val = atoi(node->token->value);
value_init_int(value, val, node->line);
ssize_t addr = prog_add_new_value(prog, value);
prog_add_instruction(prog, OP_PUSH, addr);
} break;
case NODE_FLOAT: {
struct value* value = malloc(sizeof(struct value));
float val = atof(node->token->value);
value_init_float(value, val, node->line);
ssize_t addr = prog_add_new_value(prog, value);
prog_add_instruction(prog, OP_PUSH, addr);
} break;
case NODE_BOOL: {
struct value* value = malloc(sizeof(struct value));
bool val = strcmp("true", node->token->value) == 0;
value_init_bool(value, val, node->line);
ssize_t addr = prog_add_new_value(prog, value);
prog_add_instruction(prog, OP_PUSH, addr);
} break;
case NODE_STRING: {
struct value* value = malloc(sizeof(struct value));
value_init_string(value, node->token->value, node->line);
ssize_t addr = prog_add_new_value(prog, value);
prog_add_instruction(prog, OP_PUSH, addr);
} break;
case NODE_SYMBOL: {
struct value* value = malloc(sizeof(struct value));
value_init_symbol(value, node->token->value, node->line);
ssize_t addr = prog_add_new_value(prog, value);
prog_add_instruction(prog, OP_PUSH, addr);
} break;
case NODE_IDENT: {
struct entry const* entry = symtable_try_get(
&moka->symtable,
node->token->value
);
if (!entry)
{
status_push(self->status, STATUS_ERROR, node->line,
"undefined <%s>", node->token->value);
return;
}
if (entry->is_local)
{
prog_add_instruction(prog, OP_LOCAL_LOAD, entry->addr);
}
else
{
prog_add_instruction(prog, OP_GLOBAL_LOAD, entry->addr);
}
} break;
default: {
fprintf(stderr, "cannot compile node %s\n",
NodeKindStr[node->kind]);
abort();
} break;
}
}
void compiler_import(struct compiler* self,
struct moka* moka,
struct node* node)
{
(void) self;
struct node* arg = node->children.data[1];
char const* name = arg->token->value;
if (!path_is_local(name))
{
char source_name_loc[MK_STRLEN];
path_apply_ext(name, "mk", source_name_loc, MK_STRLEN);
char source_name[MK_STRLEN*2];
snprintf(source_name, MK_STRLEN * 2, "%s/%s",
MOKA_LIB_DIR,
source_name_loc);
char lib_name_tmp[MK_STRLEN];
path_apply_ext(name, "so", lib_name_tmp, MK_STRLEN);
char lib_name_loc[MK_STRLEN];
path_apply_prefix(lib_name_tmp, "lib", lib_name_loc, MK_STRLEN);
char lib_name[MK_STRLEN * 2];
snprintf(lib_name, MK_STRLEN * 2, "%s/%s",
MOKA_LIB_DIR,
lib_name_loc);
if (path_exists(source_name))
{
struct module* module = malloc(sizeof(struct module));
module_init(module);
module_load_from_file(module, source_name);
char modname[MK_STRLEN];
path_get_mod_name(name, modname, MK_STRLEN);
moka_import_module(moka, modname, module);
return;
}
else if (path_exists(lib_name))
{
struct module* module = malloc(sizeof(struct module));
module_init(module);
module_load_from_dl(module, lib_name);
char modname[MK_STRLEN];
path_get_mod_name(name, modname, MK_STRLEN);
moka_import_module(moka, modname, module);
return;
}
}
else
{
char source_name[MK_STRLEN];
path_apply_ext(name, "mk", source_name, MK_STRLEN);
char lib_name_tmp[MK_STRLEN];
path_apply_ext(name, "so", lib_name_tmp, MK_STRLEN);
char lib_name[MK_STRLEN];
path_apply_prefix(lib_name_tmp, "lib", lib_name, MK_STRLEN);
if (path_exists(source_name))
{
struct module* module = malloc(sizeof(struct module));
module_init(module);
module_load_from_file(module, source_name);
char modname[MK_STRLEN];
path_get_mod_name(name, modname, MK_STRLEN);
moka_import_module(moka, modname, module);
return;
}
else if (path_exists(lib_name))
{
struct module* module = malloc(sizeof(struct module));
module_init(module);
module_load_from_dl(module, lib_name);
char modname[MK_STRLEN];
path_get_mod_name(name, modname, MK_STRLEN);
moka_import_module(moka, modname, module);
return;
}
}
status_push(
self->status,
STATUS_ERROR,
node->line,
"unknown module <%s>",
name
);
}
void compiler_quote(struct compiler* self,
struct node* node,
struct prog* prog,
struct moka* moka)
{
assert(self);
assert(node);
assert(prog);
assert(moka);
switch (node->kind)
{
case NODE_IDENT: {
node->kind = NODE_SYMBOL;
compiler_compile(self, node, prog, moka);
} break;
case NODE_CALL: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_quote(self, node->children.data[i],
prog, moka);
}
prog_add_instruction(prog, OP_MAKE_ARRAY,
node->children.size);
} break;
default: {
compiler_compile(self, node, prog, moka);
} break;
}
}