#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; ichildren.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; ichildren.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; ichildren.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; } }