✨ native function support with lazy evaluation of its arguments.
parent
12fd626cd5
commit
b761c1849f
|
@ -1,7 +1,12 @@
|
||||||
ROOT ::= ATOM*
|
ROOT ::= ATOM*
|
||||||
|
EXPR ::=
|
||||||
|
| ATOM
|
||||||
|
| CALL
|
||||||
|
CALL ::= opar EXPR EXPR* cpar
|
||||||
ATOM ::=
|
ATOM ::=
|
||||||
| int
|
| int
|
||||||
| float
|
| float
|
||||||
| bool
|
| bool
|
||||||
| string
|
| string
|
||||||
| symbol
|
| symbol
|
||||||
|
| ident
|
||||||
|
|
|
@ -16,6 +16,8 @@ add_library(moka-core
|
||||||
value.c
|
value.c
|
||||||
exec.c
|
exec.c
|
||||||
moka.c
|
moka.c
|
||||||
|
symtable.c
|
||||||
|
native.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(moka-core
|
target_compile_options(moka-core
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
typedef size_t MOKA;
|
||||||
|
|
||||||
#define MK_STRLEN 4096
|
#define MK_STRLEN 4096
|
||||||
#define MK_ENUM_ENUM(X) X
|
#define MK_ENUM_ENUM(X) X
|
||||||
#define MK_ENUM_STRING(X) #X
|
#define MK_ENUM_STRING(X) #X
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self,
|
void compiler_init(struct compiler* self,
|
||||||
struct status* status)
|
struct status* status)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -12,22 +12,43 @@ void compiler_free(struct compiler* self)
|
||||||
assert(self);
|
assert(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)
|
||||||
{
|
{
|
||||||
assert(self); assert(node); assert(prog);
|
assert(self); assert(node); assert(prog);
|
||||||
|
|
||||||
switch (node->kind)
|
switch (node->kind)
|
||||||
{
|
{
|
||||||
case NODE_ROOT: {
|
case NODE_ROOT: {
|
||||||
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);
|
compiler_compile(self, child, prog, symtable);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_CALL: {
|
||||||
|
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 value* val = malloc(sizeof(struct value));
|
||||||
|
value_init_lazy(val, child, child->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);
|
||||||
|
|
||||||
|
prog_add_instruction(prog, OP_CALL, node->children.size - 1);
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_INT: {
|
case NODE_INT: {
|
||||||
struct value* value = malloc(sizeof(struct value));
|
struct value* value = malloc(sizeof(struct value));
|
||||||
int val = atoi(node->token->value);
|
int val = atoi(node->token->value);
|
||||||
|
@ -65,6 +86,27 @@ void compiler_compile(struct compiler* self,
|
||||||
ssize_t addr = prog_add_new_value(prog, value);
|
ssize_t addr = prog_add_new_value(prog, value);
|
||||||
prog_add_instruction(prog, OP_PUSH, addr);
|
prog_add_instruction(prog, OP_PUSH, addr);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_IDENT: {
|
||||||
|
struct entry const* entry = symtable_try_get(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: {
|
default: {
|
||||||
fprintf(stderr, "cannot compile node %s\n",
|
fprintf(stderr, "cannot compile node %s\n",
|
||||||
NodeKindStr[node->kind]);
|
NodeKindStr[node->kind]);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "prog.h"
|
#include "prog.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "symtable.h"
|
||||||
|
|
||||||
struct compiler
|
struct compiler
|
||||||
{
|
{
|
||||||
|
@ -17,5 +18,6 @@ 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);
|
||||||
#endif
|
#endif
|
||||||
|
|
31
lib/exec.c
31
lib/exec.c
|
@ -37,6 +37,34 @@ void exec_instr(struct exec* self,
|
||||||
|
|
||||||
switch (instr->opcode)
|
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);
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_GLOBAL_LOAD: {
|
||||||
|
moka_push_ref(moka, param, 0);
|
||||||
|
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)
|
||||||
|
@ -61,6 +89,9 @@ void exec_instr(struct exec* self,
|
||||||
moka_push_symbol(moka, value->data.sym, value->line);
|
moka_push_symbol(moka, value->data.sym, value->line);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TY_LAZY: {
|
||||||
|
moka_push_lazy(moka, value->data.lazy, value->line);
|
||||||
|
} break;
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"cannot push value of type <%s>\n",
|
"cannot push value of type <%s>\n",
|
||||||
|
|
93
lib/lexer.c
93
lib/lexer.c
|
@ -16,12 +16,16 @@ void lexer_init(struct lexer* self,
|
||||||
}
|
}
|
||||||
self->context.line = 1;
|
self->context.line = 1;
|
||||||
self->context.cursor = 0;
|
self->context.cursor = 0;
|
||||||
|
str_init(&self->separators);
|
||||||
|
str_push(&self->separators, '(');
|
||||||
|
str_push(&self->separators, ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_free(struct lexer* self)
|
void lexer_free(struct lexer* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
free(self->source);
|
free(self->source);
|
||||||
|
str_free(&self->separators);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct token* lexer_try_new_next(struct lexer* self)
|
struct token* lexer_try_new_next(struct lexer* self)
|
||||||
|
@ -31,6 +35,16 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
|
|
||||||
lexer_skip_spaces(self);
|
lexer_skip_spaces(self);
|
||||||
|
|
||||||
|
if ( (tok=lexer_try_new_text(self, TOKEN_OPAR, "(")) )
|
||||||
|
{
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (tok=lexer_try_new_text(self, TOKEN_CPAR, ")")) )
|
||||||
|
{
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (tok=lexer_try_new_float(self)) )
|
if ( (tok=lexer_try_new_float(self)) )
|
||||||
{
|
{
|
||||||
return tok;
|
return tok;
|
||||||
|
@ -61,6 +75,11 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (tok=lexer_try_new_ident(self)) )
|
||||||
|
{
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
if (self->context.cursor < self->len)
|
if (self->context.cursor < self->len)
|
||||||
{
|
{
|
||||||
struct str str;
|
struct str str;
|
||||||
|
@ -88,6 +107,25 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lexer_skip(struct lexer* self, TokenKind kind)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
struct token* tok = lexer_try_new_next(self);
|
||||||
|
assert(tok);
|
||||||
|
|
||||||
|
if (tok->kind != kind)
|
||||||
|
{
|
||||||
|
status_push(self->status, STATUS_ERROR, tok->line,
|
||||||
|
"expected token <%s>, got <%s>",
|
||||||
|
TokenKindStr[kind] + strlen("TOKEN_"),
|
||||||
|
TokenKindStr[tok->kind] + strlen("TOKEN_")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
token_free(tok);
|
||||||
|
free(tok);
|
||||||
|
}
|
||||||
|
|
||||||
void lexer_skip_spaces(struct lexer* self)
|
void lexer_skip_spaces(struct lexer* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -288,6 +326,36 @@ struct token* lexer_try_new_symbol(struct lexer* self)
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct token* lexer_try_new_ident(struct lexer* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
size_t cursor = self->context.cursor;
|
||||||
|
|
||||||
|
if (cursor >= self->len
|
||||||
|
|| isdigit(self->source[cursor]))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct str value;
|
||||||
|
str_init(&value);
|
||||||
|
|
||||||
|
while (cursor < self->len
|
||||||
|
&& lexer_is_ident(self, cursor))
|
||||||
|
{
|
||||||
|
char c = self->source[cursor];
|
||||||
|
str_push(&value, c);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct token* tok = malloc(sizeof(struct token));
|
||||||
|
token_init(tok, TOKEN_IDENT, value.value);
|
||||||
|
str_free(&value);
|
||||||
|
|
||||||
|
self->context.cursor = cursor;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
bool lexer_is_sep(struct lexer* self, size_t index)
|
bool lexer_is_sep(struct lexer* self, size_t index)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -298,9 +366,34 @@ bool lexer_is_sep(struct lexer* self, size_t index)
|
||||||
}
|
}
|
||||||
|
|
||||||
char c = self->source[index];
|
char c = self->source[index];
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->separators.size; i++)
|
||||||
|
{
|
||||||
|
if (c == self->separators.value[i])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return isspace(c);
|
return isspace(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lexer_is_ident(struct lexer* self, size_t index)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
if (index >= self->len)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char c = self->source[index];
|
||||||
|
|
||||||
|
return isalnum(c)
|
||||||
|
|| c == '_'
|
||||||
|
|| c == '!'
|
||||||
|
|| c == '?'
|
||||||
|
|| c == '-';
|
||||||
|
}
|
||||||
|
|
||||||
struct token* lexer_try_new_text(struct lexer* self,
|
struct token* lexer_try_new_text(struct lexer* self,
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
char const* text)
|
char const* text)
|
||||||
|
|
|
@ -28,14 +28,18 @@ void lexer_init(struct lexer* self,
|
||||||
void lexer_free(struct lexer* self);
|
void lexer_free(struct lexer* self);
|
||||||
|
|
||||||
struct token* lexer_try_new_next(struct lexer* self);
|
struct token* lexer_try_new_next(struct lexer* self);
|
||||||
|
void lexer_skip(struct lexer* self, TokenKind kind);
|
||||||
void lexer_skip_spaces(struct lexer* self);
|
void lexer_skip_spaces(struct lexer* self);
|
||||||
|
|
||||||
struct token* lexer_try_new_int(struct lexer* self);
|
struct token* lexer_try_new_int(struct lexer* self);
|
||||||
struct token* lexer_try_new_float(struct lexer* self);
|
struct token* lexer_try_new_float(struct lexer* self);
|
||||||
struct token* lexer_try_new_string(struct lexer* self);
|
struct token* lexer_try_new_string(struct lexer* self);
|
||||||
struct token* lexer_try_new_symbol(struct lexer* self);
|
struct token* lexer_try_new_symbol(struct lexer* self);
|
||||||
|
struct token* lexer_try_new_ident(struct lexer* self);
|
||||||
|
|
||||||
bool lexer_is_sep(struct lexer* self, size_t index);
|
bool lexer_is_sep(struct lexer* self, size_t index);
|
||||||
|
bool lexer_is_ident(struct lexer* self, size_t index);
|
||||||
|
|
||||||
struct token* lexer_try_new_text(struct lexer* self,
|
struct token* lexer_try_new_text(struct lexer* self,
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
char const* text);
|
char const* text);
|
||||||
|
|
150
lib/moka.c
150
lib/moka.c
|
@ -1,8 +1,14 @@
|
||||||
#include "moka.h"
|
#include "moka.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "prog.h"
|
||||||
|
#include "exec.h"
|
||||||
|
|
||||||
void moka_init(struct moka* self)
|
void moka_init(struct moka* self, struct status* status)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
self->status = status;
|
||||||
|
symtable_init(&self->symtable);
|
||||||
vec_init(&self->frame_stack);
|
vec_init(&self->frame_stack);
|
||||||
vec_init(&self->global_values);
|
vec_init(&self->global_values);
|
||||||
|
|
||||||
|
@ -28,11 +34,29 @@ void frame_free(struct frame* self)
|
||||||
void moka_free(struct moka* self)
|
void moka_free(struct moka* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
symtable_free(&self->symtable);
|
||||||
vec_free_elements(&self->frame_stack, (void*) frame_free);
|
vec_free_elements(&self->frame_stack, (void*) frame_free);
|
||||||
vec_free(&self->frame_stack);
|
vec_free(&self->frame_stack);
|
||||||
|
vec_free_elements(&self->global_values, (void*) value_free);
|
||||||
vec_free(&self->global_values);
|
vec_free(&self->global_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
struct frame* moka_frame(struct moka* self)
|
struct frame* moka_frame(struct moka* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -58,6 +82,15 @@ MOKA moka_top(struct moka* self)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
||||||
{
|
{
|
||||||
return moka_type_of(self, value) == type;
|
return moka_type_of(self, value) == type;
|
||||||
|
@ -73,6 +106,12 @@ 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)
|
||||||
{
|
{
|
||||||
|
if (moka_is(self, value, TY_REF))
|
||||||
|
{
|
||||||
|
printf("&%zu", moka_get_ref(self, value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (moka_is(self, value, TY_INT))
|
if (moka_is(self, value, TY_INT))
|
||||||
{
|
{
|
||||||
printf("%d", moka_get_int(self, value));
|
printf("%d", moka_get_int(self, value));
|
||||||
|
@ -214,3 +253,112 @@ char* moka_get_symbol(struct moka* self, MOKA value)
|
||||||
assert(val->type == TY_SYMBOL);
|
assert(val->type == TY_SYMBOL);
|
||||||
return val->data.sym;
|
return val->data.sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
21
lib/moka.h
21
lib/moka.h
|
@ -4,8 +4,7 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "symtable.h"
|
||||||
typedef size_t MOKA;
|
|
||||||
|
|
||||||
struct frame
|
struct frame
|
||||||
{
|
{
|
||||||
|
@ -15,18 +14,25 @@ struct frame
|
||||||
|
|
||||||
struct moka
|
struct moka
|
||||||
{
|
{
|
||||||
|
struct status* status;
|
||||||
|
struct symtable symtable;
|
||||||
struct vec frame_stack;
|
struct vec frame_stack;
|
||||||
struct vec global_values;
|
struct vec global_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
void moka_init(struct moka* self);
|
void moka_init(struct moka* self, struct status* status);
|
||||||
void frame_init(struct frame* self);
|
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_decl_native(struct moka* self,
|
||||||
|
char* name,
|
||||||
|
native_fun_t fun);
|
||||||
|
|
||||||
struct frame* moka_frame(struct moka* self);
|
struct frame* moka_frame(struct moka* self);
|
||||||
bool moka_has_top(struct moka* self);
|
bool moka_has_top(struct moka* self);
|
||||||
MOKA moka_top(struct moka* self);
|
MOKA moka_top(struct moka* self);
|
||||||
|
MOKA moka_pop(struct moka* self);
|
||||||
|
|
||||||
bool moka_is(struct moka* self, MOKA value, TypeKind type);
|
bool moka_is(struct moka* self, MOKA value, TypeKind type);
|
||||||
TypeKind moka_type_of(struct moka* self, MOKA value);
|
TypeKind moka_type_of(struct moka* self, MOKA value);
|
||||||
|
@ -48,4 +54,13 @@ char* moka_get_string(struct moka* self, MOKA value);
|
||||||
MOKA moka_push_symbol(struct moka* self, char const* value, int line);
|
MOKA moka_push_symbol(struct moka* self, char const* value, int line);
|
||||||
char* moka_get_symbol(struct moka* self, MOKA value);
|
char* moka_get_symbol(struct moka* self, MOKA value);
|
||||||
|
|
||||||
|
MOKA moka_push_ref(struct moka* self, size_t value, int line);
|
||||||
|
size_t moka_get_ref(struct moka* self, MOKA value);
|
||||||
|
|
||||||
|
MOKA moka_push_native(struct moka* self, native_fun_t value, int line);
|
||||||
|
native_fun_t moka_get_native(struct moka* self, MOKA value);
|
||||||
|
|
||||||
|
MOKA moka_eval_lazy(struct moka* self, MOKA lazy_value);
|
||||||
|
MOKA moka_push_lazy(struct moka* self, struct node* value, int line);
|
||||||
|
struct node* moka_get_lazy(struct moka* self, MOKA value);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "native.h"
|
||||||
|
|
||||||
|
void native_init(struct native* self, native_fun_t fun)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->fun = fun;
|
||||||
|
}
|
||||||
|
|
||||||
|
void native_free(struct native* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef MK_NATIVE_H
|
||||||
|
#define MK_NATIVE_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
|
struct moka;
|
||||||
|
|
||||||
|
typedef MOKA (*native_fun_t)(struct moka*, struct vec* args);
|
||||||
|
|
||||||
|
|
||||||
|
struct native
|
||||||
|
{
|
||||||
|
native_fun_t fun;
|
||||||
|
};
|
||||||
|
|
||||||
|
void native_init(struct native* self, native_fun_t fun);
|
||||||
|
void native_free(struct native* self);
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,6 +16,8 @@ void node_init(struct node* self,
|
||||||
|
|
||||||
void node_free(struct node* self)
|
void node_free(struct node* self)
|
||||||
{
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
if (self->token)
|
if (self->token)
|
||||||
{
|
{
|
||||||
token_free(self->token);
|
token_free(self->token);
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#define NODE_KIND(G) \
|
#define NODE_KIND(G) \
|
||||||
G(NODE_ROOT), \
|
G(NODE_ROOT), \
|
||||||
G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), \
|
G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), \
|
||||||
G(NODE_STRING), G(NODE_SYMBOL)
|
G(NODE_STRING), G(NODE_SYMBOL), G(NODE_CALL),\
|
||||||
|
G(NODE_IDENT)
|
||||||
|
|
||||||
MK_ENUM_H(NodeKind, NODE_KIND);
|
MK_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
77
lib/parser.c
77
lib/parser.c
|
@ -46,20 +46,81 @@ struct node* parser_try_new_root(struct parser* self)
|
||||||
|
|
||||||
while (!lexer_end(self->lexer))
|
while (!lexer_end(self->lexer))
|
||||||
{
|
{
|
||||||
struct node* atom = MK_TRY(parser_try_new_atom);
|
struct node* expr = MK_TRY(parser_try_new_expr);
|
||||||
if (!atom && !lexer_end(self->lexer))
|
if (!expr && !lexer_end(self->lexer))
|
||||||
{
|
{
|
||||||
node_free(root);
|
node_free(root);
|
||||||
free(root);
|
free(root);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_add_new_child(root, atom);
|
node_add_new_child(root, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct node* parser_try_new_expr(struct parser* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if (lexer_next_is(self->lexer, TOKEN_OPAR, 0))
|
||||||
|
{
|
||||||
|
return MK_TRY(parser_try_new_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MK_TRY(parser_try_new_atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node* parser_try_new_call(struct parser* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if (!lexer_next_is(self->lexer, TOKEN_OPAR, 0))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_skip(self->lexer, TOKEN_OPAR);
|
||||||
|
|
||||||
|
struct node* target = MK_TRY(parser_try_new_expr);
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node* call = malloc(sizeof(struct node));
|
||||||
|
node_init(call, NODE_CALL, NULL, target->line);
|
||||||
|
node_add_new_child(call, target);
|
||||||
|
|
||||||
|
while (!lexer_next_is(self->lexer, TOKEN_CPAR, 0))
|
||||||
|
{
|
||||||
|
struct node* arg = MK_TRY(parser_try_new_expr);
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
{
|
||||||
|
node_free(target); free(target);
|
||||||
|
node_free(call); free(call);
|
||||||
|
node_free(arg); free(arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_add_new_child(call, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lexer_next_is(self->lexer, TOKEN_CPAR, 0))
|
||||||
|
{
|
||||||
|
node_free(target); free(target);
|
||||||
|
node_free(call); free(call);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_skip(self->lexer, TOKEN_CPAR);
|
||||||
|
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
|
||||||
struct node* parser_try_new_atom(struct parser* self)
|
struct node* parser_try_new_atom(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -113,6 +174,16 @@ struct node* parser_try_new_atom(struct parser* self)
|
||||||
self->lexer->context.line);
|
self->lexer->context.line);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lexer_next_is(self->lexer, TOKEN_IDENT, 0))
|
||||||
|
{
|
||||||
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
struct token* tok = lexer_try_new_next(self->lexer);
|
||||||
|
assert(tok);
|
||||||
|
node_init(node, NODE_IDENT, tok,
|
||||||
|
self->lexer->context.line);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ struct node* parser_try(struct parser* self,
|
||||||
struct node* (*rule)(struct parser*));
|
struct node* (*rule)(struct parser*));
|
||||||
|
|
||||||
struct node* parser_try_new_root(struct parser* self);
|
struct node* parser_try_new_root(struct parser* self);
|
||||||
|
struct node* parser_try_new_expr(struct parser* self);
|
||||||
|
struct node* parser_try_new_call(struct parser* self);
|
||||||
struct node* parser_try_new_atom(struct parser* self);
|
struct node* parser_try_new_atom(struct parser* self);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
lib/prog.c
16
lib/prog.c
|
@ -7,6 +7,7 @@ void prog_init(struct prog* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_init(&self->instructions);
|
vec_init(&self->instructions);
|
||||||
vec_init(&self->values);
|
vec_init(&self->values);
|
||||||
|
self->stack_addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prog_free(struct prog* self)
|
void prog_free(struct prog* self)
|
||||||
|
@ -30,6 +31,21 @@ size_t prog_add_instruction(struct prog* self,
|
||||||
|
|
||||||
vec_push(&self->instructions, instr);
|
vec_push(&self->instructions, instr);
|
||||||
|
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case OP_CALL:
|
||||||
|
case OP_GLOBAL_LOAD:
|
||||||
|
case OP_PUSH: {
|
||||||
|
self->stack_addr++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "cannot find stack address of <%s>\n",
|
||||||
|
OpcodeKindStr[opcode]);
|
||||||
|
abort();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
return self->instructions.size - 1;
|
return self->instructions.size - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
#define OPCODE_KIND(G) \
|
#define OPCODE_KIND(G) \
|
||||||
G(OP_PUSH)
|
G(OP_PUSH), \
|
||||||
|
G(OP_LOCAL_LOAD), \
|
||||||
|
G(OP_GLOBAL_LOAD), \
|
||||||
|
G(OP_CALL)
|
||||||
|
|
||||||
MK_ENUM_H(OpcodeKind, OPCODE_KIND);
|
MK_ENUM_H(OpcodeKind, OPCODE_KIND);
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ struct prog
|
||||||
{
|
{
|
||||||
struct vec instructions;
|
struct vec instructions;
|
||||||
struct vec values;
|
struct vec values;
|
||||||
|
size_t stack_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void prog_init(struct prog* self);
|
void prog_init(struct prog* self);
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include "symtable.h"
|
||||||
|
|
||||||
|
void entry_init(struct entry* self,
|
||||||
|
char const* name,
|
||||||
|
size_t addr,
|
||||||
|
bool is_local)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->name = strdup(name);
|
||||||
|
self->addr = addr;
|
||||||
|
self->is_local = is_local;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entry_free(struct entry* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
free(self->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_init(struct env* self, struct env* parent)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
vec_init(&self->entries);
|
||||||
|
self->parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_free(struct env* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if (self->parent)
|
||||||
|
{
|
||||||
|
env_free(self->parent);
|
||||||
|
free(self->parent);
|
||||||
|
self->parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_free_elements(&self->entries, (void*) entry_free);
|
||||||
|
vec_free(&self->entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entry* env_try_get(struct env* self, char* name)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->entries.size; i++)
|
||||||
|
{
|
||||||
|
struct entry* entry = self->entries.data[i];
|
||||||
|
|
||||||
|
if (strcmp(entry->name, name) == 0)
|
||||||
|
{
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->parent)
|
||||||
|
{
|
||||||
|
return env_try_get(self->parent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtable_init(struct symtable* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->root = malloc(sizeof(struct env));
|
||||||
|
env_init(self->root, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtable_free(struct symtable* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
env_free(self->root);
|
||||||
|
free(self->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtable_declare(struct symtable* self,
|
||||||
|
char* name,
|
||||||
|
size_t addr,
|
||||||
|
bool is_local)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
assert(self->root);
|
||||||
|
|
||||||
|
struct entry* entry = malloc(sizeof(struct entry));
|
||||||
|
entry_init(entry, name, addr, is_local);
|
||||||
|
|
||||||
|
vec_push(&self->root->entries, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entry* symtable_try_get(struct symtable* self, char* name)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
return env_try_get(self->root, name);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef MK_SYMTABLE_H
|
||||||
|
#define MK_SYMTABLE_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
|
struct entry
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
size_t addr;
|
||||||
|
bool is_local;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct env
|
||||||
|
{
|
||||||
|
struct vec entries;
|
||||||
|
struct env* parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symtable
|
||||||
|
{
|
||||||
|
struct env* root;
|
||||||
|
};
|
||||||
|
|
||||||
|
void entry_init(struct entry* self,
|
||||||
|
char const* name,
|
||||||
|
size_t addr,
|
||||||
|
bool is_local);
|
||||||
|
void entry_free(struct entry* self);
|
||||||
|
|
||||||
|
void env_init(struct env* self, struct env* parent);
|
||||||
|
void env_free(struct env* self);
|
||||||
|
struct entry* env_try_get(struct env* self, char* name);
|
||||||
|
|
||||||
|
void symtable_init(struct symtable* self);
|
||||||
|
void symtable_free(struct symtable* self);
|
||||||
|
|
||||||
|
void symtable_declare(struct symtable* self,
|
||||||
|
char* name,
|
||||||
|
size_t addr,
|
||||||
|
bool is_local);
|
||||||
|
|
||||||
|
struct entry* symtable_try_get(struct symtable* self, char* name);
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,7 +6,8 @@
|
||||||
#define TOKEN_KIND(G) \
|
#define TOKEN_KIND(G) \
|
||||||
G(TOKEN_INT), G(TOKEN_FLOAT), \
|
G(TOKEN_INT), G(TOKEN_FLOAT), \
|
||||||
G(TOKEN_BOOL), G(TOKEN_STRING), \
|
G(TOKEN_BOOL), G(TOKEN_STRING), \
|
||||||
G(TOKEN_SYMBOL)
|
G(TOKEN_SYMBOL), G(TOKEN_IDENT), \
|
||||||
|
G(TOKEN_OPAR), G(TOKEN_CPAR)
|
||||||
|
|
||||||
MK_ENUM_H(TokenKind, TOKEN_KIND);
|
MK_ENUM_H(TokenKind, TOKEN_KIND);
|
||||||
|
|
||||||
|
|
32
lib/value.c
32
lib/value.c
|
@ -1,4 +1,5 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
MK_ENUM_C(TypeKind, TYPE_KIND);
|
MK_ENUM_C(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -44,6 +45,32 @@ void value_init_symbol(struct value* self, char const* value, int line)
|
||||||
self->line = line;
|
self->line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void value_init_ref(struct value* self, size_t value, int line)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->data.ref = value;
|
||||||
|
self->type = TY_REF;
|
||||||
|
self->line = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value_init_native(struct value* self, struct native* value, int line)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(value);
|
||||||
|
self->data.native = value;
|
||||||
|
self->type = TY_NATIVE;
|
||||||
|
self->line = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value_init_lazy(struct value* self, struct node* value, int line)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(value);
|
||||||
|
self->data.lazy = value;
|
||||||
|
self->type = TY_LAZY;
|
||||||
|
self->line = line;
|
||||||
|
}
|
||||||
|
|
||||||
void value_free(struct value* self)
|
void value_free(struct value* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -58,4 +85,9 @@ void value_free(struct value* self)
|
||||||
free(self->data.sym);
|
free(self->data.sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->type == TY_NATIVE)
|
||||||
|
{
|
||||||
|
native_free(self->data.native);
|
||||||
|
free(self->data.native);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
lib/value.h
10
lib/value.h
|
@ -2,10 +2,12 @@
|
||||||
#define MK_VALUE_H
|
#define MK_VALUE_H
|
||||||
|
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
#include "native.h"
|
||||||
|
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TY_INT), G(TY_FLOAT), G(TY_BOOL), \
|
G(TY_INT), G(TY_FLOAT), G(TY_BOOL), \
|
||||||
G(TY_STRING), G(TY_SYMBOL)
|
G(TY_STRING), G(TY_SYMBOL), G(TY_REF), \
|
||||||
|
G(TY_NATIVE), G(TY_LAZY)
|
||||||
|
|
||||||
MK_ENUM_H(TypeKind, TYPE_KIND);
|
MK_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -16,6 +18,9 @@ union value_data
|
||||||
bool boolean;
|
bool boolean;
|
||||||
char* str;
|
char* str;
|
||||||
char* sym;
|
char* sym;
|
||||||
|
size_t ref;
|
||||||
|
struct native* native;
|
||||||
|
struct node* lazy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct value
|
struct value
|
||||||
|
@ -30,6 +35,9 @@ void value_init_float(struct value* self, float value, int line);
|
||||||
void value_init_bool(struct value* self, bool value, int line);
|
void value_init_bool(struct value* self, bool value, int line);
|
||||||
void value_init_string(struct value* self, char const* value, int line);
|
void value_init_string(struct value* self, char const* value, int line);
|
||||||
void value_init_symbol(struct value* self, char const* value, int line);
|
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);
|
void value_free(struct value* self);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
11
src/main.c
11
src/main.c
|
@ -46,16 +46,17 @@ int main(int argc, char** argv)
|
||||||
struct prog prog;
|
struct prog prog;
|
||||||
prog_init(&prog);
|
prog_init(&prog);
|
||||||
|
|
||||||
compiler_compile(&compiler, root, &prog);
|
|
||||||
|
struct moka moka;
|
||||||
|
moka_init(&moka, &status);
|
||||||
|
compiler_compile(&compiler, root, &prog, &moka.symtable);
|
||||||
|
|
||||||
if (!status_is_ok(&status))
|
if (!status_is_ok(&status))
|
||||||
{
|
{
|
||||||
status_dump(&status);
|
status_dump(&status);
|
||||||
goto free_compiler;
|
goto free_moka;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct moka moka;
|
|
||||||
moka_init(&moka);
|
|
||||||
|
|
||||||
struct exec exec;
|
struct exec exec;
|
||||||
exec_init(&exec);
|
exec_init(&exec);
|
||||||
|
@ -70,9 +71,9 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_free(&exec);
|
exec_free(&exec);
|
||||||
|
free_moka:
|
||||||
moka_free(&moka);
|
moka_free(&moka);
|
||||||
prog_free(&prog);
|
prog_free(&prog);
|
||||||
free_compiler:
|
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
node_free(root);
|
node_free(root);
|
||||||
free(root);
|
free(root);
|
||||||
|
|
|
@ -75,10 +75,20 @@ START_TEST(lexer_atom)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(lexer_funcall)
|
||||||
|
{
|
||||||
|
test_lexer(" (_0pizza?!) ", 3,
|
||||||
|
TOKEN_OPAR, "(",
|
||||||
|
TOKEN_IDENT, "_0pizza?!",
|
||||||
|
TOKEN_CPAR, ")"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
void register_lexer(Suite* suite)
|
void register_lexer(Suite* suite)
|
||||||
{
|
{
|
||||||
TCase* tcase = tcase_create("Lexer");
|
TCase* tcase = tcase_create("Lexer");
|
||||||
tcase_add_test(tcase, lexer_atom);
|
tcase_add_test(tcase, lexer_atom);
|
||||||
|
tcase_add_test(tcase, lexer_funcall);
|
||||||
suite_add_tcase(suite, tcase);
|
suite_add_tcase(suite, tcase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,24 @@ START_TEST(parser_atom)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(parser_call)
|
||||||
|
{
|
||||||
|
test_parser("ROOT(CALL(IDENT[hello-noparam]))",
|
||||||
|
" (hello-noparam) ");
|
||||||
|
|
||||||
|
test_parser("ROOT(CALL(IDENT[hello],SYMBOL[world]))",
|
||||||
|
" (hello 'world) ");
|
||||||
|
|
||||||
|
test_parser("ROOT(CALL(IDENT[is-ok?],BOOL[true],INT[4]))",
|
||||||
|
" (is-ok? true 4) ");
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
void register_parser(Suite* suite)
|
void register_parser(Suite* suite)
|
||||||
{
|
{
|
||||||
TCase* tcase = tcase_create("Parser");
|
TCase* tcase = tcase_create("Parser");
|
||||||
tcase_add_test(tcase, parser_atom);
|
tcase_add_test(tcase, parser_atom);
|
||||||
|
tcase_add_test(tcase, parser_call);
|
||||||
|
|
||||||
suite_add_tcase(suite, tcase);
|
suite_add_tcase(suite, tcase);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue