Compare commits

...

3 Commits

Author SHA1 Message Date
bog 8317634e06 import modules. 2024-03-29 05:46:35 +01:00
bog 1875adc48d 🎨 clean main introducing modules. 2024-03-27 20:53:06 +01:00
bog e5b7eea0cf 🎨 moved call logic from exec.c into moka state. 2024-03-27 17:19:40 +01:00
22 changed files with 884 additions and 112 deletions

View File

@ -2,11 +2,13 @@ cmake_minimum_required(VERSION 3.29)
project(moka)
set(MOKA_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/moka)
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
add_subdirectory(lib)
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(std)
set_property(TARGET moka-core PROPERTY C_STANDARD 99)
set_property(TARGET moka-tests PROPERTY C_STANDARD 99)

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.29)
project(moka-lib)
configure_file(conf.in.h ${CMAKE_SOURCE_DIR}/lib/conf.h)
add_library(moka-core
commons.c
status.c
@ -18,10 +20,13 @@ add_library(moka-core
moka.c
symtable.c
native.c
module.c
path.c
builtins.c
)
target_compile_options(moka-core
PUBLIC -Wall -Wextra -g
PUBLIC -Wall -Wextra -g -fPIC
)
target_include_directories(moka-core

48
lib/builtins.c Normal file
View File

@ -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;
}

14
lib/builtins.h Normal file
View File

@ -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

View File

@ -1,4 +1,8 @@
#include "compiler.h"
#include "moka.h"
#include "module.h"
#include "path.h"
#include "conf.h"
void compiler_init(struct compiler* self,
struct status* status)
@ -15,7 +19,7 @@ void compiler_free(struct compiler* self)
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog,
struct symtable* symtable)
struct moka* moka)
{
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++)
{
struct node* child = node->children.data[i];
compiler_compile(self, child, prog, symtable);
compiler_compile(self, child, prog, moka);
}
} break;
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++)
{
// 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;
struct node* child = node->children.data[k];
struct node* mychild = node->children.data[k];
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);
prog_add_instruction(prog, OP_PUSH, addr);
}
struct node* child = node->children.data[0];
compiler_compile(self, child, prog, symtable);
compiler_compile(self, child, prog, moka);
prog_add_instruction(prog, OP_CALL, node->children.size - 1);
} break;
@ -88,8 +96,10 @@ void compiler_compile(struct compiler* self,
} break;
case NODE_IDENT: {
struct entry const* entry = symtable_try_get(symtable,
node->token->value);
struct entry const* entry = symtable_try_get(
&moka->symtable,
node->token->value
);
if (!entry)
{
status_push(self->status, STATUS_ERROR, node->line,
@ -114,3 +124,102 @@ void compiler_compile(struct compiler* self,
} 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
);
}

View File

@ -19,5 +19,10 @@ void compiler_free(struct compiler* self);
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog,
struct symtable* symtable);
struct moka* moka);
void compiler_import(struct compiler* self,
struct moka* moka,
struct node* node);
#endif

7
lib/conf.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MK_CONF_H
#define MK_CONF_H
#define MOKA_LIB_DIR "/usr/local/lib/moka"
#endif

7
lib/conf.in.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MK_CONF_H
#define MK_CONF_H
#cmakedefine MOKA_LIB_DIR "@MOKA_LIB_DIR@"
#endif

View File

@ -38,25 +38,7 @@ void exec_instr(struct exec* self,
switch (instr->opcode)
{
case OP_CALL: {
MOKA fun = moka_pop(moka);
struct vec args;
vec_init(&args);
for (ssize_t i=0; i<param; i++)
{
MOKA arg = moka_pop(moka);
vec_push(&args, (void*) arg);
}
struct value* val = moka->global_values.data[
moka_get_ref(moka, fun)
];
assert(val->type == TY_NATIVE);
struct native* native = val->data.native;
(native->fun)(moka, &args);
vec_free(&args);
moka_call(moka, param);
self->pc++;
} break;
@ -65,6 +47,11 @@ void exec_instr(struct exec* self,
self->pc++;
} break;
case OP_LOCAL_LOAD: {
moka_push(moka, param);
self->pc++;
} break;
case OP_PUSH: {
struct value* value = prog->values.data[param];
switch (value->type)

View File

@ -33,6 +33,11 @@ struct token* lexer_try_new_next(struct lexer* self)
assert(self);
struct token* tok = NULL;
if (!status_is_ok(self->status) > 0)
{
return NULL;
}
lexer_skip_spaces(self);
if ( (tok=lexer_try_new_text(self, TOKEN_OPAR, "(")) )
@ -348,12 +353,17 @@ struct token* lexer_try_new_ident(struct lexer* self)
cursor++;
}
struct token* tok = malloc(sizeof(struct token));
token_init(tok, TOKEN_IDENT, value.value);
str_free(&value);
if (value.size > 0)
{
struct token* tok = malloc(sizeof(struct token));
token_init(tok, TOKEN_IDENT, value.value);
str_free(&value);
self->context.cursor = cursor;
return tok;
self->context.cursor = cursor;
return tok;
}
return NULL;
}
bool lexer_is_sep(struct lexer* self, size_t index)
@ -391,7 +401,8 @@ bool lexer_is_ident(struct lexer* self, size_t index)
|| c == '_'
|| c == '!'
|| c == '?'
|| c == '-';
|| c == '-'
|| c == ':';
}
struct token* lexer_try_new_text(struct lexer* self,

125
lib/module.c Normal file
View File

@ -0,0 +1,125 @@
#include <dlfcn.h>
#include "module.h"
#include "builtins.h"
void module_init(struct module* self)
{
assert(self);
status_init(&self->status);
moka_init(&self->moka, &self->status);
register_builtins(&self->moka);
prog_init(&self->prog);
self->handle = NULL;
}
void module_free(struct module* self)
{
assert(self);
status_free(&self->status);
prog_free(&self->prog);
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)
{
assert(self);
assert(path);
struct str source;
str_init(&source);
FILE* file = fopen(path, "r+");
size_t sz;
char buf;
while ( (sz=fread(&buf, sizeof(char), 1, file)) )
{
str_push(&source, buf);
}
fclose(file);
int ret = module_load_from_str(self, source.value);
str_free(&source);
return ret;
}
int module_load_from_str(struct module* self, char const* source)
{
status_init(&self->status);
struct lexer lex;
lexer_init(&lex, source, &self->status);
struct parser parser;
parser_init(&parser, &lex);
struct node* root = parser_try_new_root(&parser);
if (!root || !status_is_ok(&self->status))
{
status_dump(&self->status);
goto free_parser;
}
struct compiler compiler;
compiler_init(&compiler, &self->status);
compiler_compile(&compiler, root, &self->prog, &self->moka);
if (!status_is_ok(&self->status))
{
status_dump(&self->status);
goto free_compiler;
}
struct exec exec;
exec_init(&exec);
exec_prog(&exec, &self->moka, &self->prog);
exec_free(&exec);
free_compiler:
compiler_free(&compiler);
node_free(root);
free(root);
free_parser:
parser_free(&parser);
lexer_free(&lex);
int ret = status_is_ok(&self->status) ? EXIT_SUCCESS : EXIT_FAILURE;
return ret;
}

29
lib/module.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef MK_MODULE_H
#define MK_MODULE_H
#include "commons.h"
#include "status.h"
#include "lexer.h"
#include "parser.h"
#include "prog.h"
#include "moka.h"
#include "compiler.h"
#include "exec.h"
#include "status.h"
struct module
{
struct status status;
struct prog prog;
struct moka moka;
void* handle;
};
void module_init(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_str(struct module* self, char const* source);
#endif

View File

@ -3,6 +3,23 @@
#include "compiler.h"
#include "prog.h"
#include "exec.h"
#include "module.h"
void moka_mod_init(struct moka_mod* self,
char const* name,
struct module* new_module)
{
assert(self);
self->name = strdup(name);
self->module = new_module;
}
void moka_mod_free(struct moka_mod* self)
{
free(self->name);
module_free(self->module);
free(self->module);
}
void moka_init(struct moka* self, struct status* status)
{
@ -11,6 +28,7 @@ void moka_init(struct moka* self, struct status* status)
symtable_init(&self->symtable);
vec_init(&self->frame_stack);
vec_init(&self->global_values);
vec_init(&self->modules);
struct frame* frame = malloc(sizeof(struct frame));
frame_init(frame);
@ -37,10 +55,130 @@ void moka_free(struct moka* self)
symtable_free(&self->symtable);
vec_free_elements(&self->frame_stack, (void*) frame_free);
vec_free(&self->frame_stack);
vec_free_elements(&self->modules, (void*) moka_mod_free);
vec_free(&self->modules);
vec_free_elements(&self->global_values, (void*) value_free);
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,
char* name,
native_fun_t fun)
@ -149,6 +287,38 @@ void moka_dump(struct moka* self, MOKA value)
abort();
}
MOKA moka_call(struct moka* self, int arg_count)
{
MOKA fun = moka_pop(self);
struct vec args;
vec_init(&args);
for (ssize_t i=0; i<arg_count; i++)
{
MOKA arg = moka_pop(self);
vec_push(&args, (void*) arg);
}
struct value* val = self->global_values.data[
moka_get_ref(self, fun)
];
assert(val->type == TY_NATIVE);
struct native* native = val->data.native;
(native->fun)(self, &args);
vec_free(&args);
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)
{
assert(self);
@ -271,6 +441,7 @@ size_t moka_get_ref(struct moka* self, MOKA value)
assert(self);
struct frame* frame = moka_frame(self);
struct value* val = frame->local_values.data[value];
assert(val->type == TY_REF);
return val->data.ref;
}
@ -305,6 +476,12 @@ native_fun_t moka_get_native(struct moka* self, MOKA value)
MOKA moka_eval_lazy(struct moka* self, MOKA lazy_value)
{
assert(self);
if (!moka_is(self, lazy_value, TY_LAZY))
{
return lazy_value;
}
struct node* node = moka_get_lazy(self, lazy_value);
struct compiler compiler;
@ -317,7 +494,7 @@ MOKA moka_eval_lazy(struct moka* self, MOKA lazy_value)
&compiler,
node,
&prog,
&self->symtable);
self);
if (!status_is_ok(self->status))
{

View File

@ -12,19 +12,43 @@ struct frame
struct vec local_values;
};
struct moka_mod
{
char* name;
struct module* module;
};
struct moka
{
struct status* status;
struct symtable symtable;
struct vec frame_stack;
struct vec global_values;
struct vec modules;
};
void moka_mod_init(struct moka_mod* self,
char const* name,
struct module* new_module);
void moka_mod_free(struct moka_mod* self);
void moka_init(struct moka* self, struct status* status);
void frame_init(struct frame* self);
void frame_free(struct frame* 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,
char* name,
native_fun_t fun);
@ -39,6 +63,10 @@ TypeKind moka_type_of(struct moka* self, MOKA value);
void moka_dump(struct moka* self, MOKA value);
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);
int moka_get_int(struct moka* self, MOKA value);

162
lib/path.c Normal file
View File

@ -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;
}

19
lib/path.h Normal file
View File

@ -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

View File

@ -35,6 +35,7 @@ size_t prog_add_instruction(struct prog* self,
{
case OP_CALL:
case OP_GLOBAL_LOAD:
case OP_LOCAL_LOAD:
case OP_PUSH: {
self->stack_addr++;
} break;

View File

@ -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_native(struct value* self, struct native* value, int line);
void value_init_lazy(struct value* self, struct node* value, int line);
void value_free(struct value* self);
#endif

View File

@ -5,85 +5,18 @@
#include <compiler.h>
#include <exec.h>
#include <moka.h>
#include <module.h>
int main(int argc, char** argv)
{
if (argc <= 1) { return EXIT_FAILURE; }
struct status status;
status_init(&status);
struct module module;
module_init(&module);
struct str source;
str_init(&source);
int ret = module_load_from_file(&module, argv[1]);
{
FILE* file = fopen(argv[1], "r+");
size_t sz;
char buf;
while ( (sz=fread(&buf, sizeof(char), 1, file)) )
{
str_push(&source, buf);
}
fclose(file);
}
struct lexer lex;
lexer_init(&lex, source.value, &status);
struct parser parser;
parser_init(&parser, &lex);
struct node* root = parser_try_new_root(&parser);
if (!root || !status_is_ok(&status))
{
status_dump(&status);
goto free_parser;
}
struct compiler compiler;
compiler_init(&compiler, &status);
struct prog prog;
prog_init(&prog);
struct moka moka;
moka_init(&moka, &status);
compiler_compile(&compiler, root, &prog, &moka.symtable);
if (!status_is_ok(&status))
{
status_dump(&status);
goto free_moka;
}
struct exec exec;
exec_init(&exec);
exec_prog(&exec, &moka, &prog);
if (moka_has_top(&moka))
{
MOKA value = moka_top(&moka);
moka_dump(&moka, value);
printf("\n");
}
exec_free(&exec);
free_moka:
moka_free(&moka);
prog_free(&prog);
compiler_free(&compiler);
node_free(root);
free(root);
free_parser:
parser_free(&parser);
lexer_free(&lex);
str_free(&source);
int ret = status_is_ok(&status) ? EXIT_SUCCESS : EXIT_FAILURE;
status_free(&status);
module_free(&module);
return ret;
}

18
std/CMakeLists.txt Normal file
View File

@ -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()

View File

@ -2,6 +2,7 @@
#include <check.h>
#include "lexer.h"
#include "parser.h"
#include "path.h"
int main()
{
@ -9,6 +10,7 @@ int main()
register_lexer(s);
register_parser(s);
register_path(s);
SRunner* runner = srunner_create(s);
srunner_run_all(runner, CK_VERBOSE);

82
tests/path.h Normal file
View File

@ -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