2024-03-26 18:31:33 +00:00
|
|
|
#include "moka.h"
|
2024-03-27 10:49:10 +00:00
|
|
|
#include "node.h"
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "prog.h"
|
|
|
|
#include "exec.h"
|
2024-03-26 18:31:33 +00:00
|
|
|
|
2024-03-27 10:49:10 +00:00
|
|
|
void moka_init(struct moka* self, struct status* status)
|
2024-03-26 18:31:33 +00:00
|
|
|
{
|
|
|
|
assert(self);
|
2024-03-27 10:49:10 +00:00
|
|
|
self->status = status;
|
|
|
|
symtable_init(&self->symtable);
|
2024-03-26 18:31:33 +00:00
|
|
|
vec_init(&self->frame_stack);
|
|
|
|
vec_init(&self->global_values);
|
|
|
|
|
|
|
|
struct frame* frame = malloc(sizeof(struct frame));
|
|
|
|
frame_init(frame);
|
|
|
|
vec_push(&self->frame_stack, frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void frame_init(struct frame* self)
|
|
|
|
{
|
|
|
|
vec_init(&self->local_values);
|
|
|
|
vec_init(&self->stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
void frame_free(struct frame* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
vec_free_elements(&self->local_values, (void*)value_free);
|
|
|
|
vec_free(&self->local_values);
|
|
|
|
vec_free(&self->stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
void moka_free(struct moka* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
2024-03-27 10:49:10 +00:00
|
|
|
symtable_free(&self->symtable);
|
2024-03-26 18:31:33 +00:00
|
|
|
vec_free_elements(&self->frame_stack, (void*) frame_free);
|
|
|
|
vec_free(&self->frame_stack);
|
2024-03-27 10:49:10 +00:00
|
|
|
vec_free_elements(&self->global_values, (void*) value_free);
|
2024-03-26 18:31:33 +00:00
|
|
|
vec_free(&self->global_values);
|
|
|
|
}
|
|
|
|
|
2024-03-27 10:49:10 +00:00
|
|
|
void moka_decl_native(struct moka* self,
|
|
|
|
char* name,
|
|
|
|
native_fun_t fun)
|
|
|
|
{
|
|
|
|
struct native* native = malloc(sizeof(struct native));
|
|
|
|
native_init(native, fun);
|
|
|
|
|
|
|
|
struct value* value = malloc(sizeof(struct value));
|
|
|
|
value_init_native(value, native, 0);
|
|
|
|
|
|
|
|
vec_push(&self->global_values, value);
|
|
|
|
size_t addr = self->global_values.size - 1;
|
|
|
|
|
|
|
|
symtable_declare(&self->symtable, name, addr, false);
|
|
|
|
}
|
|
|
|
|
2024-03-26 18:31:33 +00:00
|
|
|
struct frame* moka_frame(struct moka* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
assert(self->frame_stack.size > 0);
|
|
|
|
return self->frame_stack.data[
|
|
|
|
self->frame_stack.size - 1
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool moka_has_top(struct moka* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
return frame->stack.size > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_top(struct moka* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
assert(frame->stack.size > 0);
|
|
|
|
MOKA val = (MOKA) frame->stack.data[frame->stack.size - 1];
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2024-03-27 10:49:10 +00:00
|
|
|
MOKA moka_pop(struct moka* self)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
assert(frame->stack.size > 0);
|
|
|
|
MOKA val = (MOKA) frame->stack.data[frame->stack.size - 1];
|
|
|
|
vec_pop(&frame->stack);
|
|
|
|
return val;
|
|
|
|
}
|
2024-03-26 18:31:33 +00:00
|
|
|
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
|
|
|
{
|
|
|
|
return moka_type_of(self, value) == type;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeKind moka_type_of(struct moka* self, MOKA value)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value const* val = frame->local_values.data[value];
|
|
|
|
return val->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void moka_dump(struct moka* self, MOKA value)
|
|
|
|
{
|
2024-03-27 10:49:10 +00:00
|
|
|
if (moka_is(self, value, TY_REF))
|
|
|
|
{
|
|
|
|
printf("&%zu", moka_get_ref(self, value));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-26 18:31:33 +00:00
|
|
|
if (moka_is(self, value, TY_INT))
|
|
|
|
{
|
|
|
|
printf("%d", moka_get_int(self, value));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moka_is(self, value, TY_FLOAT))
|
|
|
|
{
|
|
|
|
printf("%f", moka_get_float(self, value));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moka_is(self, value, TY_BOOL))
|
|
|
|
{
|
|
|
|
printf("%s", moka_get_bool(self, value) ? "true" : "false");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moka_is(self, value, TY_STRING))
|
|
|
|
{
|
|
|
|
printf("%s", moka_get_string(self, value));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moka_is(self, value, TY_SYMBOL))
|
|
|
|
{
|
|
|
|
printf("'%s", moka_get_symbol(self, value));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "cannot dump value of type <%s>\n",
|
|
|
|
TypeKindStr[moka_type_of(self, value)]
|
|
|
|
);
|
|
|
|
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2024-03-27 16:19:40 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-03-26 18:31:33 +00:00
|
|
|
MOKA moka_push_int(struct moka* self, int value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_int(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int moka_get_int(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_INT);
|
|
|
|
return val->data.integer;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_float(struct moka* self, float value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_float(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
float moka_get_float(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_FLOAT);
|
|
|
|
return val->data.real;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_bool(struct moka* self, bool value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_bool(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
float moka_get_bool(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_BOOL);
|
|
|
|
return val->data.boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_string(struct moka* self, char const* value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_string(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* moka_get_string(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_STRING);
|
|
|
|
return val->data.str;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_symbol(struct moka* self, char const* value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_symbol(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* moka_get_symbol(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_SYMBOL);
|
|
|
|
return val->data.sym;
|
|
|
|
}
|
2024-03-27 10:49:10 +00:00
|
|
|
|
|
|
|
MOKA moka_push_ref(struct moka* self, size_t value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_ref(val, value, line);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_native(struct moka* self, native_fun_t value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
assert(value);
|
|
|
|
|
|
|
|
struct native* native = malloc(sizeof(struct native));
|
|
|
|
native_init(native, value);
|
|
|
|
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_native(val, native, line);
|
|
|
|
|
|
|
|
vec_push(&self->global_values, val);
|
|
|
|
size_t addr = self->global_values.size - 1;
|
|
|
|
|
|
|
|
return moka_push_ref(self, addr, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
native_fun_t moka_get_native(struct moka* self, MOKA value)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
|
|
|
|
size_t addr = moka_get_ref(self, value);
|
|
|
|
struct value const* val = self->global_values.data[addr];
|
|
|
|
struct native const* native = val->data.native;
|
|
|
|
return native->fun;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_eval_lazy(struct moka* self, MOKA lazy_value)
|
|
|
|
{
|
|
|
|
assert(self);
|
2024-03-27 16:19:40 +00:00
|
|
|
|
|
|
|
if (!moka_is(self, lazy_value, TY_LAZY))
|
|
|
|
{
|
|
|
|
return lazy_value;
|
|
|
|
}
|
|
|
|
|
2024-03-27 10:49:10 +00:00
|
|
|
struct node* node = moka_get_lazy(self, lazy_value);
|
|
|
|
|
|
|
|
struct compiler compiler;
|
|
|
|
compiler_init(&compiler, self->status);
|
|
|
|
|
|
|
|
struct prog prog;
|
|
|
|
prog_init(&prog);
|
|
|
|
|
|
|
|
compiler_compile(
|
|
|
|
&compiler,
|
|
|
|
node,
|
|
|
|
&prog,
|
|
|
|
&self->symtable);
|
|
|
|
|
|
|
|
if (!status_is_ok(self->status))
|
|
|
|
{
|
|
|
|
status_dump(self->status);
|
|
|
|
moka_push_int(self, 0, 0);
|
|
|
|
goto free_prog;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct exec exec;
|
|
|
|
exec_init(&exec);
|
|
|
|
|
|
|
|
exec_prog(&exec, self, &prog);
|
|
|
|
|
|
|
|
exec_free(&exec);
|
|
|
|
free_prog:
|
|
|
|
prog_free(&prog);
|
|
|
|
compiler_free(&compiler);
|
|
|
|
|
|
|
|
return moka_pop(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOKA moka_push_lazy(struct moka* self, struct node* value, int line)
|
|
|
|
{
|
|
|
|
assert(self);
|
|
|
|
assert(value);
|
|
|
|
|
|
|
|
struct value* val = malloc(sizeof(struct value));
|
|
|
|
value_init_lazy(val, value, line);
|
|
|
|
|
|
|
|
struct frame* frame = moka_frame(self);
|
|
|
|
vec_push(&frame->local_values, val);
|
|
|
|
size_t addr = frame->local_values.size - 1;
|
|
|
|
vec_push(&frame->stack, (void*) addr);
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct node* moka_get_lazy(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_LAZY);
|
|
|
|
return val->data.lazy;
|
|
|
|
}
|