✨ import modules.
parent
1875adc48d
commit
8317634e06
|
@ -2,11 +2,13 @@ cmake_minimum_required(VERSION 3.29)
|
||||||
|
|
||||||
project(moka)
|
project(moka)
|
||||||
|
|
||||||
|
set(MOKA_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/moka)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
|
||||||
|
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
add_subdirectory(std)
|
||||||
|
|
||||||
set_property(TARGET moka-core PROPERTY C_STANDARD 99)
|
set_property(TARGET moka-core PROPERTY C_STANDARD 99)
|
||||||
set_property(TARGET moka-tests PROPERTY C_STANDARD 99)
|
set_property(TARGET moka-tests PROPERTY C_STANDARD 99)
|
||||||
|
|
|
@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.29)
|
||||||
|
|
||||||
project(moka-lib)
|
project(moka-lib)
|
||||||
|
|
||||||
|
configure_file(conf.in.h ${CMAKE_SOURCE_DIR}/lib/conf.h)
|
||||||
|
|
||||||
add_library(moka-core
|
add_library(moka-core
|
||||||
commons.c
|
commons.c
|
||||||
status.c
|
status.c
|
||||||
|
@ -19,10 +21,12 @@ add_library(moka-core
|
||||||
symtable.c
|
symtable.c
|
||||||
native.c
|
native.c
|
||||||
module.c
|
module.c
|
||||||
|
path.c
|
||||||
|
builtins.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(moka-core
|
target_compile_options(moka-core
|
||||||
PUBLIC -Wall -Wextra -g
|
PUBLIC -Wall -Wextra -g -fPIC
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(moka-core
|
target_include_directories(moka-core
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "builtins.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
|
void register_builtins(struct moka* moka)
|
||||||
|
{
|
||||||
|
assert(moka);
|
||||||
|
moka_decl_native(moka, "println", mk_println);
|
||||||
|
moka_decl_native(moka, "define", mk_define);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOKA mk_println(struct moka* moka, struct vec* args)
|
||||||
|
{
|
||||||
|
assert(moka);
|
||||||
|
assert(args);
|
||||||
|
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<args->size; i++)
|
||||||
|
{
|
||||||
|
MOKA val = (MOKA) args->data[i];
|
||||||
|
if (i > 0) { printf(" "); }
|
||||||
|
else { line = moka_get_lazy(moka, val)->line; }
|
||||||
|
moka_dump(moka, MK_EVAL(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return moka_push_int(moka, 0, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOKA mk_define(struct moka* moka, struct vec* args)
|
||||||
|
{
|
||||||
|
assert(moka); assert(args);
|
||||||
|
assert(args->size == 2);
|
||||||
|
|
||||||
|
MOKA target = (MOKA) args->data[0];
|
||||||
|
MOKA value = MK_EVAL((MOKA) args->data[1]);
|
||||||
|
|
||||||
|
struct node* node = moka_get_lazy(moka, target);
|
||||||
|
|
||||||
|
moka_push(moka, value);
|
||||||
|
assert(node->token);
|
||||||
|
moka_decl_var(moka, node->token->value, value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef MK_BUILTINS_H
|
||||||
|
#define MK_BUILTINS_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "moka.h"
|
||||||
|
|
||||||
|
#define MK_EVAL(X) moka_eval_lazy(moka, X)
|
||||||
|
|
||||||
|
void register_builtins(struct moka* moka);
|
||||||
|
|
||||||
|
MOKA mk_println(struct moka* moka, struct vec* args);
|
||||||
|
MOKA mk_define(struct moka* moka, struct vec* args);
|
||||||
|
|
||||||
|
#endif
|
131
lib/compiler.c
131
lib/compiler.c
|
@ -1,4 +1,8 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "moka.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self,
|
void compiler_init(struct compiler* self,
|
||||||
struct status* status)
|
struct status* status)
|
||||||
|
@ -15,7 +19,7 @@ void compiler_free(struct compiler* self)
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct symtable* symtable)
|
struct moka* moka)
|
||||||
{
|
{
|
||||||
assert(self); assert(node); assert(prog);
|
assert(self); assert(node); assert(prog);
|
||||||
|
|
||||||
|
@ -25,26 +29,30 @@ void compiler_compile(struct compiler* self,
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
struct node* child = node->children.data[i];
|
struct node* child = node->children.data[i];
|
||||||
compiler_compile(self, child, prog, symtable);
|
compiler_compile(self, child, prog, moka);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_CALL: {
|
case NODE_CALL: {
|
||||||
|
struct node* child = node->children.data[0];
|
||||||
|
|
||||||
|
if (strcmp(child->token->value, "import") == 0)
|
||||||
|
{
|
||||||
|
compiler_import(self, moka, node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i=0; i<node->children.size - 1; i++)
|
for (size_t i=0; i<node->children.size - 1; i++)
|
||||||
{
|
{
|
||||||
// size_t k = node->children.size - 1 - i;
|
|
||||||
// struct node* child = node->children.data[k];
|
|
||||||
// compiler_compile(self, child, prog, symtable);
|
|
||||||
size_t k = node->children.size - 1 - i;
|
size_t k = node->children.size - 1 - i;
|
||||||
struct node* child = node->children.data[k];
|
struct node* mychild = node->children.data[k];
|
||||||
struct value* val = malloc(sizeof(struct value));
|
struct value* val = malloc(sizeof(struct value));
|
||||||
value_init_lazy(val, child, child->line);
|
value_init_lazy(val, mychild, mychild->line);
|
||||||
size_t addr = prog_add_new_value(prog, val);
|
size_t addr = prog_add_new_value(prog, val);
|
||||||
prog_add_instruction(prog, OP_PUSH, addr);
|
prog_add_instruction(prog, OP_PUSH, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* child = node->children.data[0];
|
compiler_compile(self, child, prog, moka);
|
||||||
compiler_compile(self, child, prog, symtable);
|
|
||||||
|
|
||||||
prog_add_instruction(prog, OP_CALL, node->children.size - 1);
|
prog_add_instruction(prog, OP_CALL, node->children.size - 1);
|
||||||
} break;
|
} break;
|
||||||
|
@ -88,8 +96,10 @@ void compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
struct entry const* entry = symtable_try_get(symtable,
|
struct entry const* entry = symtable_try_get(
|
||||||
node->token->value);
|
&moka->symtable,
|
||||||
|
node->token->value
|
||||||
|
);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
status_push(self->status, STATUS_ERROR, node->line,
|
status_push(self->status, STATUS_ERROR, node->line,
|
||||||
|
@ -114,3 +124,102 @@ void compiler_compile(struct compiler* self,
|
||||||
} break;
|
} 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -19,5 +19,10 @@ void compiler_free(struct compiler* self);
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct symtable* symtable);
|
struct moka* moka);
|
||||||
|
|
||||||
|
void compiler_import(struct compiler* self,
|
||||||
|
struct moka* moka,
|
||||||
|
struct node* node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef MK_CONF_H
|
||||||
|
#define MK_CONF_H
|
||||||
|
|
||||||
|
#define MOKA_LIB_DIR "/usr/local/lib/moka"
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef MK_CONF_H
|
||||||
|
#define MK_CONF_H
|
||||||
|
|
||||||
|
#cmakedefine MOKA_LIB_DIR "@MOKA_LIB_DIR@"
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -47,6 +47,11 @@ void exec_instr(struct exec* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_LOCAL_LOAD: {
|
||||||
|
moka_push(moka, param);
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_PUSH: {
|
case OP_PUSH: {
|
||||||
struct value* value = prog->values.data[param];
|
struct value* value = prog->values.data[param];
|
||||||
switch (value->type)
|
switch (value->type)
|
||||||
|
|
|
@ -401,7 +401,8 @@ bool lexer_is_ident(struct lexer* self, size_t index)
|
||||||
|| c == '_'
|
|| c == '_'
|
||||||
|| c == '!'
|
|| c == '!'
|
||||||
|| c == '?'
|
|| c == '?'
|
||||||
|| c == '-';
|
|| c == '-'
|
||||||
|
|| c == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
struct token* lexer_try_new_text(struct lexer* self,
|
struct token* lexer_try_new_text(struct lexer* self,
|
||||||
|
|
37
lib/module.c
37
lib/module.c
|
@ -1,11 +1,16 @@
|
||||||
|
#include <dlfcn.h>
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "builtins.h"
|
||||||
|
|
||||||
void module_init(struct module* self)
|
void module_init(struct module* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
status_init(&self->status);
|
status_init(&self->status);
|
||||||
moka_init(&self->moka, &self->status);
|
moka_init(&self->moka, &self->status);
|
||||||
|
register_builtins(&self->moka);
|
||||||
|
|
||||||
prog_init(&self->prog);
|
prog_init(&self->prog);
|
||||||
|
self->handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_free(struct module* self)
|
void module_free(struct module* self)
|
||||||
|
@ -14,6 +19,36 @@ void module_free(struct module* self)
|
||||||
status_free(&self->status);
|
status_free(&self->status);
|
||||||
prog_free(&self->prog);
|
prog_free(&self->prog);
|
||||||
moka_free(&self->moka);
|
moka_free(&self->moka);
|
||||||
|
if (self->handle)
|
||||||
|
{
|
||||||
|
dlclose(self->handle);
|
||||||
|
self->handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int module_load_from_dl(struct module* self, char const* path)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
self->handle = dlopen(path, RTLD_NOW);
|
||||||
|
|
||||||
|
if (!self->handle)
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*f)(struct module*) = dlsym(self->handle, "create_module");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
dlclose(self->handle);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
f(self);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int module_load_from_file(struct module* self, char const* path)
|
int module_load_from_file(struct module* self, char const* path)
|
||||||
|
@ -62,7 +97,7 @@ int module_load_from_str(struct module* self, char const* source)
|
||||||
struct compiler compiler;
|
struct compiler compiler;
|
||||||
compiler_init(&compiler, &self->status);
|
compiler_init(&compiler, &self->status);
|
||||||
|
|
||||||
compiler_compile(&compiler, root, &self->prog, &self->moka.symtable);
|
compiler_compile(&compiler, root, &self->prog, &self->moka);
|
||||||
|
|
||||||
if (!status_is_ok(&self->status))
|
if (!status_is_ok(&self->status))
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,11 +16,13 @@ struct module
|
||||||
struct status status;
|
struct status status;
|
||||||
struct prog prog;
|
struct prog prog;
|
||||||
struct moka moka;
|
struct moka moka;
|
||||||
|
void* handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
void module_init(struct module* self);
|
void module_init(struct module* self);
|
||||||
void module_free(struct module* self);
|
void module_free(struct module* self);
|
||||||
|
|
||||||
|
int module_load_from_dl(struct module* self, char const* path);
|
||||||
int module_load_from_file(struct module* self, char const* path);
|
int module_load_from_file(struct module* self, char const* path);
|
||||||
int module_load_from_str(struct module* self, char const* source);
|
int module_load_from_str(struct module* self, char const* source);
|
||||||
|
|
||||||
|
|
129
lib/moka.c
129
lib/moka.c
|
@ -6,7 +6,7 @@
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
void moka_mod_init(struct moka_mod* self,
|
void moka_mod_init(struct moka_mod* self,
|
||||||
char* name,
|
char const* name,
|
||||||
struct module* new_module)
|
struct module* new_module)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -63,6 +63,122 @@ void moka_free(struct moka* self)
|
||||||
vec_free(&self->global_values);
|
vec_free(&self->global_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void moka_import_module(struct moka* self,
|
||||||
|
char const* name,
|
||||||
|
struct module* module)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
assert(module);
|
||||||
|
|
||||||
|
struct symtable* mod_sym = &module->moka.symtable;
|
||||||
|
struct env* env = mod_sym->root;
|
||||||
|
|
||||||
|
struct frame* mod_frame = moka_frame(&module->moka);
|
||||||
|
struct vec* mod_locals = &mod_frame->local_values;
|
||||||
|
struct vec* mod_globals = &module->moka.global_values;
|
||||||
|
|
||||||
|
for (size_t i=0; i<env->entries.size; i++)
|
||||||
|
{
|
||||||
|
struct entry const* entry = env->entries.data[i];
|
||||||
|
struct value* val;
|
||||||
|
if (entry->is_local)
|
||||||
|
{
|
||||||
|
val = mod_locals->data[entry->addr];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = mod_globals->data[entry->addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
char new_name[MK_STRLEN];
|
||||||
|
snprintf(new_name, MK_STRLEN, "%s::%s", name, entry->name);
|
||||||
|
|
||||||
|
switch (val->type)
|
||||||
|
{
|
||||||
|
case TY_NATIVE: {
|
||||||
|
moka_decl_native(
|
||||||
|
self,
|
||||||
|
new_name,
|
||||||
|
val->data.native->fun
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_SYMBOL: {
|
||||||
|
moka_decl_var(
|
||||||
|
self,
|
||||||
|
new_name,
|
||||||
|
moka_push_symbol(self,
|
||||||
|
val->data.sym,
|
||||||
|
val->line));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_STRING: {
|
||||||
|
moka_decl_var(
|
||||||
|
self,
|
||||||
|
new_name,
|
||||||
|
moka_push_string(self,
|
||||||
|
val->data.str,
|
||||||
|
val->line));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TY_INT: {
|
||||||
|
moka_decl_var(
|
||||||
|
self,
|
||||||
|
new_name,
|
||||||
|
moka_push_int(self,
|
||||||
|
val->data.integer,
|
||||||
|
val->line));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fprintf(stderr,
|
||||||
|
"cannot import value of type <%s>\n",
|
||||||
|
TypeKindStr[val->type]);
|
||||||
|
abort();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct moka_mod* mod = malloc(sizeof(struct moka_mod));
|
||||||
|
moka_mod_init(mod, (char*) name, module);
|
||||||
|
|
||||||
|
vec_push(&self->modules, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct module* moka_try_get_module(struct moka* self,
|
||||||
|
char const* name)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->modules.size; i++)
|
||||||
|
{
|
||||||
|
struct moka_mod* mod = self->modules.data[i];
|
||||||
|
|
||||||
|
if (strcmp(name, mod->name))
|
||||||
|
{
|
||||||
|
return mod->module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moka_decl_var(struct moka* self,
|
||||||
|
char* name,
|
||||||
|
MOKA value)
|
||||||
|
{
|
||||||
|
assert(self); assert(name);
|
||||||
|
|
||||||
|
symtable_declare(
|
||||||
|
&self->symtable,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
void moka_decl_native(struct moka* self,
|
void moka_decl_native(struct moka* self,
|
||||||
char* name,
|
char* name,
|
||||||
native_fun_t fun)
|
native_fun_t fun)
|
||||||
|
@ -195,6 +311,14 @@ MOKA moka_call(struct moka* self, int arg_count)
|
||||||
return moka_top(self);
|
return moka_top(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOKA moka_push(struct moka* self, MOKA value)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
struct frame* frame = moka_frame(self);
|
||||||
|
vec_push(&frame->stack, (void*) value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
MOKA moka_push_int(struct moka* self, int value, int line)
|
MOKA moka_push_int(struct moka* self, int value, int line)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -317,6 +441,7 @@ size_t moka_get_ref(struct moka* self, MOKA value)
|
||||||
assert(self);
|
assert(self);
|
||||||
struct frame* frame = moka_frame(self);
|
struct frame* frame = moka_frame(self);
|
||||||
struct value* val = frame->local_values.data[value];
|
struct value* val = frame->local_values.data[value];
|
||||||
|
|
||||||
assert(val->type == TY_REF);
|
assert(val->type == TY_REF);
|
||||||
return val->data.ref;
|
return val->data.ref;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +494,7 @@ MOKA moka_eval_lazy(struct moka* self, MOKA lazy_value)
|
||||||
&compiler,
|
&compiler,
|
||||||
node,
|
node,
|
||||||
&prog,
|
&prog,
|
||||||
&self->symtable);
|
self);
|
||||||
|
|
||||||
if (!status_is_ok(self->status))
|
if (!status_is_ok(self->status))
|
||||||
{
|
{
|
||||||
|
|
17
lib/moka.h
17
lib/moka.h
|
@ -28,7 +28,7 @@ struct moka
|
||||||
};
|
};
|
||||||
|
|
||||||
void moka_mod_init(struct moka_mod* self,
|
void moka_mod_init(struct moka_mod* self,
|
||||||
char* name,
|
char const* name,
|
||||||
struct module* new_module);
|
struct module* new_module);
|
||||||
void moka_mod_free(struct moka_mod* self);
|
void moka_mod_free(struct moka_mod* self);
|
||||||
|
|
||||||
|
@ -37,6 +37,18 @@ void frame_init(struct frame* self);
|
||||||
void frame_free(struct frame* self);
|
void frame_free(struct frame* self);
|
||||||
void moka_free(struct moka* self);
|
void moka_free(struct moka* self);
|
||||||
|
|
||||||
|
|
||||||
|
void moka_import_module(struct moka* self,
|
||||||
|
char const* name,
|
||||||
|
struct module* module);
|
||||||
|
|
||||||
|
struct module* moka_try_get_module(struct moka* self,
|
||||||
|
char const* name);
|
||||||
|
|
||||||
|
void moka_decl_var(struct moka* self,
|
||||||
|
char* name,
|
||||||
|
MOKA value);
|
||||||
|
|
||||||
void moka_decl_native(struct moka* self,
|
void moka_decl_native(struct moka* self,
|
||||||
char* name,
|
char* name,
|
||||||
native_fun_t fun);
|
native_fun_t fun);
|
||||||
|
@ -52,6 +64,9 @@ TypeKind moka_type_of(struct moka* self, MOKA value);
|
||||||
void moka_dump(struct moka* self, MOKA value);
|
void moka_dump(struct moka* self, MOKA value);
|
||||||
|
|
||||||
MOKA moka_call(struct moka* self, int arg_count);
|
MOKA moka_call(struct moka* self, int arg_count);
|
||||||
|
|
||||||
|
MOKA moka_push(struct moka* self, MOKA value);
|
||||||
|
|
||||||
MOKA moka_push_int(struct moka* self, int value, int line);
|
MOKA moka_push_int(struct moka* self, int value, int line);
|
||||||
int moka_get_int(struct moka* self, MOKA value);
|
int moka_get_int(struct moka* self, MOKA value);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
|
bool path_is_local(char const* path)
|
||||||
|
{
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
if (strlen(path) == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path[0] == '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_get_mod_name(char const* path, char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
assert(path);
|
||||||
|
size_t sz = strlen(path);
|
||||||
|
size_t k = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<sz; i++)
|
||||||
|
{
|
||||||
|
if (path[i] == '.' && i != 0)
|
||||||
|
{
|
||||||
|
bool at_end = true;
|
||||||
|
for (size_t j=i+1; j<sz; j++)
|
||||||
|
{
|
||||||
|
if (path[j] == '/' && j != sz - 1)
|
||||||
|
{
|
||||||
|
at_end = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at_end)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path[i] == '/' && i != sz - 1)
|
||||||
|
{
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
else if (path[i] != '/')
|
||||||
|
{
|
||||||
|
if (k >= size) { break; }
|
||||||
|
buffer[k] = path[i];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[k] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool path_exists(char const* path)
|
||||||
|
{
|
||||||
|
FILE* file;
|
||||||
|
|
||||||
|
if ( (file = fopen(path, "r")) )
|
||||||
|
{
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t path_apply_ext(char const* path,
|
||||||
|
char const* ext,
|
||||||
|
char* buffer,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
assert(path); assert(ext); assert(buffer);
|
||||||
|
|
||||||
|
ssize_t ext_idx = -1;
|
||||||
|
size_t path_sz = strlen(path);
|
||||||
|
|
||||||
|
char result[MK_STRLEN];
|
||||||
|
memset(result, '\0', sizeof(char) * MK_STRLEN);
|
||||||
|
memcpy(result, path, sizeof(char) * path_sz);
|
||||||
|
|
||||||
|
for (size_t i=0; i<path_sz; i++)
|
||||||
|
{
|
||||||
|
size_t k = path_sz - i - 1;
|
||||||
|
|
||||||
|
if (path[k] == '.')
|
||||||
|
{
|
||||||
|
ext_idx = k;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext_idx == -1 || (path[0] == '.' && ext_idx == 0))
|
||||||
|
{
|
||||||
|
return snprintf(buffer, size, "%s.%s", path, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = 0;
|
||||||
|
for (ssize_t i=0; i<=ext_idx; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%c", path[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t const ext_sz = strlen(ext);
|
||||||
|
|
||||||
|
for (size_t i=0; i<ext_sz; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%c", ext[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t path_apply_prefix(char const* path,
|
||||||
|
char const* prefix,
|
||||||
|
char* buffer,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
assert(path); assert(prefix); assert(buffer);
|
||||||
|
|
||||||
|
size_t const path_sz = strlen(path);
|
||||||
|
char const* itr = strstr(path, prefix);
|
||||||
|
size_t prefix_pos = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<path_sz; i++)
|
||||||
|
{
|
||||||
|
size_t k = path_sz - 1 - i;
|
||||||
|
|
||||||
|
if (path[k] == '/')
|
||||||
|
{
|
||||||
|
prefix_pos = k + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path + prefix_pos == itr)
|
||||||
|
{
|
||||||
|
memcpy(buffer, path, sizeof(char) * path_sz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = 0;
|
||||||
|
for (size_t i=0; i<prefix_pos; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%c", path[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t const prefix_sz = strlen(prefix);
|
||||||
|
|
||||||
|
for (size_t i=0; i<prefix_sz; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%c", prefix[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=prefix_pos; i<path_sz; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%c", path[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef MK_PATH_H
|
||||||
|
#define MK_PATH_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
bool path_is_local(char const* path);
|
||||||
|
void path_get_mod_name(char const* path, char* buffer, size_t size);
|
||||||
|
bool path_exists(char const* path);
|
||||||
|
size_t path_apply_ext(char const* path,
|
||||||
|
char const* ext,
|
||||||
|
char* buffer,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
size_t path_apply_prefix(char const* path,
|
||||||
|
char const* prefix,
|
||||||
|
char* buffer,
|
||||||
|
size_t size);
|
||||||
|
#endif
|
||||||
|
|
|
@ -35,6 +35,7 @@ size_t prog_add_instruction(struct prog* self,
|
||||||
{
|
{
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
case OP_GLOBAL_LOAD:
|
case OP_GLOBAL_LOAD:
|
||||||
|
case OP_LOCAL_LOAD:
|
||||||
case OP_PUSH: {
|
case OP_PUSH: {
|
||||||
self->stack_addr++;
|
self->stack_addr++;
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -38,6 +38,7 @@ void value_init_symbol(struct value* self, char const* value, int line);
|
||||||
void value_init_ref(struct value* self, size_t value, int line);
|
void value_init_ref(struct value* self, size_t value, int line);
|
||||||
void value_init_native(struct value* self, struct native* value, int line);
|
void value_init_native(struct value* self, struct native* value, int line);
|
||||||
void value_init_lazy(struct value* self, struct node* value, int line);
|
void value_init_lazy(struct value* self, struct node* value, int line);
|
||||||
|
|
||||||
void value_free(struct value* self);
|
void value_free(struct value* self);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,13 +16,6 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
int ret = module_load_from_file(&module, argv[1]);
|
int ret = module_load_from_file(&module, argv[1]);
|
||||||
|
|
||||||
if (moka_has_top(&module.moka))
|
|
||||||
{
|
|
||||||
MOKA value = moka_top(&module.moka);
|
|
||||||
moka_dump(&module.moka, value);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
module_free(&module);
|
module_free(&module);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
cmake_minimum_required(VERSION 3.29)
|
||||||
|
|
||||||
|
project(moka-std)
|
||||||
|
|
||||||
|
function(add_stdlib target source)
|
||||||
|
add_library(${target} SHARED
|
||||||
|
${source}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(${target} moka-core)
|
||||||
|
|
||||||
|
target_link_libraries(${target}
|
||||||
|
PUBLIC moka-core
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS ${target} LIBRARY DESTINATION lib/moka)
|
||||||
|
endfunction()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <check.h>
|
#include <check.h>
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
@ -9,6 +10,7 @@ int main()
|
||||||
|
|
||||||
register_lexer(s);
|
register_lexer(s);
|
||||||
register_parser(s);
|
register_parser(s);
|
||||||
|
register_path(s);
|
||||||
|
|
||||||
SRunner* runner = srunner_create(s);
|
SRunner* runner = srunner_create(s);
|
||||||
srunner_run_all(runner, CK_VERBOSE);
|
srunner_run_all(runner, CK_VERBOSE);
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#ifndef MK_TEST_PATH_H
|
||||||
|
#define MK_TEST_PATH_H
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
#include <path.h>
|
||||||
|
|
||||||
|
START_TEST(path_check_local)
|
||||||
|
{
|
||||||
|
ck_assert(true == path_is_local("./hello/world"));
|
||||||
|
ck_assert(true == path_is_local("../hello/world"));
|
||||||
|
ck_assert(false == path_is_local(""));
|
||||||
|
ck_assert(false == path_is_local("hello/world"));
|
||||||
|
ck_assert(false == path_is_local("/hello/world"));
|
||||||
|
ck_assert(false == path_is_local("/../hello/world"));
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_path_get_mod_name)
|
||||||
|
{
|
||||||
|
size_t const SZ = MK_STRLEN;
|
||||||
|
char buffer[SZ];
|
||||||
|
|
||||||
|
path_get_mod_name("./hello/world", buffer, SZ);
|
||||||
|
ck_assert_str_eq("world", buffer);
|
||||||
|
|
||||||
|
path_get_mod_name("./hello/world/", buffer, SZ);
|
||||||
|
ck_assert_str_eq("world", buffer);
|
||||||
|
|
||||||
|
path_get_mod_name("./hello.ext", buffer, SZ);
|
||||||
|
ck_assert_str_eq("hello", buffer);
|
||||||
|
|
||||||
|
path_get_mod_name("./hello.ext/world.com", buffer, SZ);
|
||||||
|
ck_assert_str_eq("world", buffer);
|
||||||
|
|
||||||
|
path_get_mod_name("./hello.ext/world.com/", buffer, SZ);
|
||||||
|
ck_assert_str_eq("world", buffer);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_path_apply_ext)
|
||||||
|
{
|
||||||
|
size_t const SZ = MK_STRLEN;
|
||||||
|
char buffer[SZ];
|
||||||
|
|
||||||
|
path_apply_ext("./hello/world", "abc", buffer, SZ);
|
||||||
|
ck_assert_str_eq("./hello/world.abc", buffer);
|
||||||
|
|
||||||
|
path_apply_ext("world.mk", "abc", buffer, SZ);
|
||||||
|
ck_assert_str_eq("world.abc", buffer);
|
||||||
|
|
||||||
|
path_apply_ext("./hello/world.xy", "xy", buffer, SZ);
|
||||||
|
ck_assert_str_eq("./hello/world.xy", buffer);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_path_apply_prefix)
|
||||||
|
{
|
||||||
|
size_t const SZ = MK_STRLEN;
|
||||||
|
char buffer[SZ];
|
||||||
|
|
||||||
|
path_apply_prefix("./hello/world.so", "lib", buffer, SZ);
|
||||||
|
ck_assert_str_eq("./hello/libworld.so", buffer);
|
||||||
|
|
||||||
|
path_apply_prefix("./hello/libworld.so", "lib", buffer, SZ);
|
||||||
|
ck_assert_str_eq("./hello/libworld.so", buffer);
|
||||||
|
|
||||||
|
path_apply_prefix("./hello/alibworld.so", "lib", buffer, SZ);
|
||||||
|
ck_assert_str_eq("./hello/libalibworld.so", buffer);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
void register_path(Suite* suite)
|
||||||
|
{
|
||||||
|
TCase* tcase = tcase_create("path");
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
tcase_add_test(tcase, path_check_local);
|
||||||
|
tcase_add_test(tcase, test_path_get_mod_name);
|
||||||
|
tcase_add_test(tcase, test_path_apply_ext);
|
||||||
|
tcase_add_test(tcase, test_path_apply_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue