266 lines
7.9 KiB
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;
|
|
}
|
|
}
|