native function support with lazy evaluation of its arguments.

main
bog 2024-03-27 11:49:10 +01:00
parent 12fd626cd5
commit b761c1849f
26 changed files with 706 additions and 22 deletions

View File

@ -1,7 +1,12 @@
ROOT ::= ATOM*
EXPR ::=
| ATOM
| CALL
CALL ::= opar EXPR EXPR* cpar
ATOM ::=
| int
| float
| bool
| string
| symbol
| ident

View File

@ -16,6 +16,8 @@ add_library(moka-core
value.c
exec.c
moka.c
symtable.c
native.c
)
target_compile_options(moka-core

View File

@ -9,6 +9,8 @@
#include <stdbool.h>
#include <ctype.h>
typedef size_t MOKA;
#define MK_STRLEN 4096
#define MK_ENUM_ENUM(X) X
#define MK_ENUM_STRING(X) #X

View File

@ -1,6 +1,6 @@
#include "compiler.h"
void compiler_init(struct compiler* self,
void compiler_init(struct compiler* self,
struct status* status)
{
assert(self);
@ -12,22 +12,43 @@ void compiler_free(struct compiler* self)
assert(self);
}
void compiler_compile(struct compiler* self,
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog)
struct prog* prog,
struct symtable* symtable)
{
assert(self); assert(node); assert(prog);
switch (node->kind)
{
case NODE_ROOT: {
for (size_t i=0; i<node->children.size; i++)
{
struct node* child = node->children.data[i];
compiler_compile(self, child, prog);
compiler_compile(self, child, prog, symtable);
}
} 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: {
struct value* value = malloc(sizeof(struct 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);
prog_add_instruction(prog, OP_PUSH, addr);
} 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: {
fprintf(stderr, "cannot compile node %s\n",
NodeKindStr[node->kind]);

View File

@ -5,6 +5,7 @@
#include "status.h"
#include "prog.h"
#include "node.h"
#include "symtable.h"
struct compiler
{
@ -17,5 +18,6 @@ void compiler_free(struct compiler* self);
void compiler_compile(struct compiler* self,
struct node* node,
struct prog* prog);
struct prog* prog,
struct symtable* symtable);
#endif

View File

@ -37,6 +37,34 @@ 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);
self->pc++;
} break;
case OP_GLOBAL_LOAD: {
moka_push_ref(moka, param, 0);
self->pc++;
} break;
case OP_PUSH: {
struct value* value = prog->values.data[param];
switch (value->type)
@ -61,6 +89,9 @@ void exec_instr(struct exec* self,
moka_push_symbol(moka, value->data.sym, value->line);
} break;
case TY_LAZY: {
moka_push_lazy(moka, value->data.lazy, value->line);
} break;
default: {
fprintf(stderr,
"cannot push value of type <%s>\n",

View File

@ -16,12 +16,16 @@ void lexer_init(struct lexer* self,
}
self->context.line = 1;
self->context.cursor = 0;
str_init(&self->separators);
str_push(&self->separators, '(');
str_push(&self->separators, ')');
}
void lexer_free(struct lexer* self)
{
assert(self);
free(self->source);
str_free(&self->separators);
}
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);
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)) )
{
return tok;
@ -61,6 +75,11 @@ struct token* lexer_try_new_next(struct lexer* self)
return tok;
}
if ( (tok=lexer_try_new_ident(self)) )
{
return tok;
}
if (self->context.cursor < self->len)
{
struct str str;
@ -88,6 +107,25 @@ struct token* lexer_try_new_next(struct lexer* self)
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)
{
assert(self);
@ -288,6 +326,36 @@ struct token* lexer_try_new_symbol(struct lexer* self)
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)
{
assert(self);
@ -298,9 +366,34 @@ bool lexer_is_sep(struct lexer* self, size_t 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);
}
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,
TokenKind kind,
char const* text)

View File

@ -28,14 +28,18 @@ void lexer_init(struct lexer* self,
void lexer_free(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);
struct token* lexer_try_new_int(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_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_ident(struct lexer* self, size_t index);
struct token* lexer_try_new_text(struct lexer* self,
TokenKind kind,
char const* text);

View File

@ -1,8 +1,14 @@
#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);
self->status = status;
symtable_init(&self->symtable);
vec_init(&self->frame_stack);
vec_init(&self->global_values);
@ -28,11 +34,29 @@ void frame_free(struct frame* self)
void moka_free(struct moka* self)
{
assert(self);
symtable_free(&self->symtable);
vec_free_elements(&self->frame_stack, (void*) frame_free);
vec_free(&self->frame_stack);
vec_free_elements(&self->global_values, (void*) value_free);
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)
{
assert(self);
@ -58,6 +82,15 @@ MOKA moka_top(struct moka* self)
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)
{
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)
{
if (moka_is(self, value, TY_REF))
{
printf("&%zu", moka_get_ref(self, value));
return;
}
if (moka_is(self, value, TY_INT))
{
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);
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;
}

View File

@ -4,8 +4,7 @@
#include "commons.h"
#include "vec.h"
#include "value.h"
typedef size_t MOKA;
#include "symtable.h"
struct frame
{
@ -15,18 +14,25 @@ struct frame
struct moka
{
struct status* status;
struct symtable symtable;
struct vec frame_stack;
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_free(struct frame* 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);
bool moka_has_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);
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);
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

12
lib/native.c Normal file
View File

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

20
lib/native.h Normal file
View File

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

View File

@ -16,6 +16,8 @@ void node_init(struct node* self,
void node_free(struct node* self)
{
assert(self);
if (self->token)
{
token_free(self->token);

View File

@ -9,7 +9,8 @@
#define NODE_KIND(G) \
G(NODE_ROOT), \
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);

View File

@ -46,20 +46,81 @@ struct node* parser_try_new_root(struct parser* self)
while (!lexer_end(self->lexer))
{
struct node* atom = MK_TRY(parser_try_new_atom);
if (!atom && !lexer_end(self->lexer))
struct node* expr = MK_TRY(parser_try_new_expr);
if (!expr && !lexer_end(self->lexer))
{
node_free(root);
free(root);
return NULL;
}
node_add_new_child(root, atom);
node_add_new_child(root, expr);
}
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)
{
assert(self);
@ -113,6 +174,16 @@ struct node* parser_try_new_atom(struct parser* self)
self->lexer->context.line);
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;
}

View File

@ -19,6 +19,8 @@ struct node* parser_try(struct parser* self,
struct node* (*rule)(struct parser*));
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);
#endif

View File

@ -7,6 +7,7 @@ void prog_init(struct prog* self)
assert(self);
vec_init(&self->instructions);
vec_init(&self->values);
self->stack_addr = 0;
}
void prog_free(struct prog* self)
@ -30,6 +31,21 @@ size_t prog_add_instruction(struct prog* self,
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;
}

View File

@ -6,7 +6,10 @@
#include "value.h"
#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);
@ -20,6 +23,7 @@ struct prog
{
struct vec instructions;
struct vec values;
size_t stack_addr;
};
void prog_init(struct prog* self);

101
lib/symtable.c Normal file
View File

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

45
lib/symtable.h Normal file
View File

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

View File

@ -6,7 +6,8 @@
#define TOKEN_KIND(G) \
G(TOKEN_INT), G(TOKEN_FLOAT), \
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);

View File

@ -1,4 +1,5 @@
#include "value.h"
#include "node.h"
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;
}
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)
{
assert(self);
@ -58,4 +85,9 @@ void value_free(struct value* self)
free(self->data.sym);
}
if (self->type == TY_NATIVE)
{
native_free(self->data.native);
free(self->data.native);
}
}

View File

@ -2,10 +2,12 @@
#define MK_VALUE_H
#include "commons.h"
#include "native.h"
#define TYPE_KIND(G) \
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);
@ -16,6 +18,9 @@ union value_data
bool boolean;
char* str;
char* sym;
size_t ref;
struct native* native;
struct node* lazy;
};
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_string(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);
#endif

View File

@ -46,16 +46,17 @@ int main(int argc, char** argv)
struct prog 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))
{
status_dump(&status);
goto free_compiler;
goto free_moka;
}
struct moka moka;
moka_init(&moka);
struct exec exec;
exec_init(&exec);
@ -70,9 +71,9 @@ int main(int argc, char** argv)
}
exec_free(&exec);
free_moka:
moka_free(&moka);
prog_free(&prog);
free_compiler:
compiler_free(&compiler);
node_free(root);
free(root);

View File

@ -75,10 +75,20 @@ START_TEST(lexer_atom)
}
END_TEST
START_TEST(lexer_funcall)
{
test_lexer(" (_0pizza?!) ", 3,
TOKEN_OPAR, "(",
TOKEN_IDENT, "_0pizza?!",
TOKEN_CPAR, ")"
);
}
END_TEST
void register_lexer(Suite* suite)
{
TCase* tcase = tcase_create("Lexer");
tcase_add_test(tcase, lexer_atom);
tcase_add_test(tcase, lexer_funcall);
suite_add_tcase(suite, tcase);
}

View File

@ -59,10 +59,24 @@ START_TEST(parser_atom)
}
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)
{
TCase* tcase = tcase_create("Parser");
tcase_add_test(tcase, parser_atom);
tcase_add_test(tcase, parser_call);
suite_add_tcase(suite, tcase);
}