diff --git a/doc/grammar.bnf b/doc/grammar.bnf index afbfe21..8281f27 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -1,7 +1,12 @@ ROOT ::= ATOM* +EXPR ::= +| ATOM +| CALL +CALL ::= opar EXPR EXPR* cpar ATOM ::= | int | float | bool | string | symbol +| ident diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index df906d0..128d7d1 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -16,6 +16,8 @@ add_library(moka-core value.c exec.c moka.c + symtable.c + native.c ) target_compile_options(moka-core diff --git a/lib/commons.h b/lib/commons.h index 4250fbc..09e6e4d 100644 --- a/lib/commons.h +++ b/lib/commons.h @@ -9,6 +9,8 @@ #include #include +typedef size_t MOKA; + #define MK_STRLEN 4096 #define MK_ENUM_ENUM(X) X #define MK_ENUM_STRING(X) #X diff --git a/lib/compiler.c b/lib/compiler.c index 342eda6..9c10f2a 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -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; ichildren.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; ichildren.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]); diff --git a/lib/compiler.h b/lib/compiler.h index f2bf6f4..c2b255f 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -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 diff --git a/lib/exec.c b/lib/exec.c index c3bb43f..b2a5f56 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -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; iglobal_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", diff --git a/lib/lexer.c b/lib/lexer.c index 4ba70f7..24db680 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -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; iseparators.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) diff --git a/lib/lexer.h b/lib/lexer.h index f891efd..bb8a901 100644 --- a/lib/lexer.h +++ b/lib/lexer.h @@ -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); diff --git a/lib/moka.c b/lib/moka.c index 4912bcd..764831e 100644 --- a/lib/moka.c +++ b/lib/moka.c @@ -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; +} diff --git a/lib/moka.h b/lib/moka.h index fd80f77..2b6baf6 100644 --- a/lib/moka.h +++ b/lib/moka.h @@ -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 diff --git a/lib/native.c b/lib/native.c new file mode 100644 index 0000000..882ce07 --- /dev/null +++ b/lib/native.c @@ -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); +} diff --git a/lib/native.h b/lib/native.h new file mode 100644 index 0000000..7f17ad4 --- /dev/null +++ b/lib/native.h @@ -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 diff --git a/lib/node.c b/lib/node.c index 2bc67d2..c53d2b9 100644 --- a/lib/node.c +++ b/lib/node.c @@ -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); diff --git a/lib/node.h b/lib/node.h index 2f7137c..84cc8c3 100644 --- a/lib/node.h +++ b/lib/node.h @@ -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); diff --git a/lib/parser.c b/lib/parser.c index 32645b9..b01027f 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -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; } diff --git a/lib/parser.h b/lib/parser.h index 1754a19..1246c6f 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -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 diff --git a/lib/prog.c b/lib/prog.c index aeab237..ddddfc1 100644 --- a/lib/prog.c +++ b/lib/prog.c @@ -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; } diff --git a/lib/prog.h b/lib/prog.h index 7ff0dfe..d5f1a5e 100644 --- a/lib/prog.h +++ b/lib/prog.h @@ -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); diff --git a/lib/symtable.c b/lib/symtable.c new file mode 100644 index 0000000..c76af11 --- /dev/null +++ b/lib/symtable.c @@ -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; ientries.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); + +} diff --git a/lib/symtable.h b/lib/symtable.h new file mode 100644 index 0000000..d3c162e --- /dev/null +++ b/lib/symtable.h @@ -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 diff --git a/lib/token.h b/lib/token.h index 2135ba4..62aa117 100644 --- a/lib/token.h +++ b/lib/token.h @@ -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); diff --git a/lib/value.c b/lib/value.c index 25b0675..77394e9 100644 --- a/lib/value.c +++ b/lib/value.c @@ -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); + } } diff --git a/lib/value.h b/lib/value.h index 78bd79a..00f89d5 100644 --- a/lib/value.h +++ b/lib/value.h @@ -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 diff --git a/src/main.c b/src/main.c index b86237f..ad87625 100644 --- a/src/main.c +++ b/src/main.c @@ -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); diff --git a/tests/lexer.h b/tests/lexer.h index 32fa986..bca2b59 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -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); } diff --git a/tests/parser.h b/tests/parser.h index 94eff23..90ad0bc 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -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); }