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* ROOT ::= ATOM*
EXPR ::=
| ATOM
| CALL
CALL ::= opar EXPR EXPR* cpar
ATOM ::= ATOM ::=
| int | int
| float | float
| bool | bool
| string | string
| symbol | symbol
| ident

View File

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

View File

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

View File

@ -14,7 +14,8 @@ 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)
{ {
assert(self); assert(node); assert(prog); assert(self); assert(node); assert(prog);
@ -24,10 +25,30 @@ void compiler_compile(struct compiler* self,
for (size_t i=0; i<node->children.size; i++) for (size_t i=0; i<node->children.size; i++)
{ {
struct node* child = node->children.data[i]; struct node* child = node->children.data[i];
compiler_compile(self, child, prog); 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]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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) void node_free(struct node* self)
{ {
assert(self);
if (self->token) if (self->token)
{ {
token_free(self->token); token_free(self->token);

View File

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

View File

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

View File

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

View File

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

View File

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

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) \ #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);

View File

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

View File

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

View File

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

View File

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

View File

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