arrays.

main
bog 2024-03-29 21:11:46 +01:00
parent 71b6b2eabf
commit 7847fe4c5d
21 changed files with 384 additions and 27 deletions

View File

@ -2,6 +2,8 @@ ROOT ::= ATOM*
EXPR ::= EXPR ::=
| ATOM | ATOM
| CALL | CALL
| ARRAY
ARRAY ::= osquare EXPR* csquare
CALL ::= opar EXPR EXPR* cpar CALL ::= opar EXPR EXPR* cpar
ATOM ::= ATOM ::=
| int | int

View File

@ -23,6 +23,7 @@ add_library(moka-core
module.c module.c
path.c path.c
builtins.c builtins.c
array.c
) )
target_compile_options(moka-core target_compile_options(moka-core

22
lib/array.c Normal file
View File

@ -0,0 +1,22 @@
#include "array.h"
#include "value.h"
void array_init(struct array* self)
{
assert(self);
vec_init(&self->values);
}
void array_free(struct array* self)
{
assert(self);
vec_free(&self->values);
}
void array_push_value(struct array* self, MOKA value)
{
assert(self);
assert(value);
vec_push(&self->values, (void*) value);
}

20
lib/array.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef MK_ARRAY_H
#define MK_ARRAY_H
#include "commons.h"
#include "vec.h"
struct value;
struct array
{
struct vec values;
};
void array_init(struct array* self);
void array_free(struct array* self);
void array_push_value(struct array* self, MOKA value);
#endif

View File

@ -8,6 +8,7 @@ void register_builtins(struct moka* moka)
assert(moka); assert(moka);
moka_decl_native(moka, "println", mk_println); moka_decl_native(moka, "println", mk_println);
moka_decl_native(moka, "define", mk_define); moka_decl_native(moka, "define", mk_define);
moka_decl_native(moka, "array", mk_array);
} }
MOKA mk_println(struct moka* moka, struct vec* args) MOKA mk_println(struct moka* moka, struct vec* args)
@ -46,3 +47,20 @@ MOKA mk_define(struct moka* moka, struct vec* args)
return value; return value;
} }
MOKA mk_array(struct moka* moka, struct vec* args)
{
assert(moka);
assert(args);
for (size_t i=0; i<args->size; i++)
{
MOKA arg = (MOKA) args->data[i];
MOKA val = MK_EVAL(arg);
moka_push(moka, val);
}
moka_make_array(moka, args->size);
return moka_top(moka);
}

View File

@ -10,5 +10,6 @@ void register_builtins(struct moka* moka);
MOKA mk_println(struct moka* moka, struct vec* args); MOKA mk_println(struct moka* moka, struct vec* args);
MOKA mk_define(struct moka* moka, struct vec* args); MOKA mk_define(struct moka* moka, struct vec* args);
MOKA mk_array(struct moka* moka, struct vec* args);
#endif #endif

View File

@ -36,6 +36,14 @@ void compiler_compile(struct compiler* self,
case NODE_CALL: { case NODE_CALL: {
struct node* child = node->children.data[0]; struct node* child = node->children.data[0];
if (strcmp(child->token->value, "quote") == 0)
{
assert(node->children.size == 2);
struct node* arg = node->children.data[1];
compiler_quote(self, arg, prog, moka);
break;
}
if (strcmp(child->token->value, "import") == 0) if (strcmp(child->token->value, "import") == 0)
{ {
compiler_import(self, moka, node); compiler_import(self, moka, node);
@ -223,3 +231,40 @@ void compiler_import(struct compiler* self,
name name
); );
} }
void compiler_quote(struct compiler* self,
struct node* node,
struct prog* prog,
struct moka* moka)
{
assert(self);
assert(node);
assert(prog);
assert(moka);
switch (node->kind)
{
case NODE_INT: {
compiler_compile(self, node, prog, moka);
} break;
case NODE_IDENT: {
node->kind = NODE_SYMBOL;
compiler_compile(self, node, prog, moka);
} break;
case NODE_CALL: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_quote(self, node->children.data[i],
prog, moka);
}
prog_add_instruction(prog, OP_MAKE_ARRAY,
node->children.size);
} break;
default: {
fprintf(stderr, "cannot quote node <%s>\n",
NodeKindStr[node->kind]);
abort();
} break;
}
}

View File

@ -12,17 +12,22 @@ struct compiler
struct status* status; struct status* status;
}; };
void compiler_init(struct compiler* self, void compiler_init(struct compiler* self,
struct status* status); struct status* status);
void compiler_free(struct compiler* self); 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 moka* moka); struct moka* moka);
void compiler_import(struct compiler* self, void compiler_import(struct compiler* self,
struct moka* moka, struct moka* moka,
struct node* node); struct node* node);
void compiler_quote(struct compiler* self,
struct node* node,
struct prog* prog,
struct moka* moka);
#endif #endif

View File

@ -37,6 +37,11 @@ void exec_instr(struct exec* self,
switch (instr->opcode) switch (instr->opcode)
{ {
case OP_MAKE_ARRAY: {
moka_make_array(moka, param);
self->pc++;
} break;
case OP_CALL: { case OP_CALL: {
moka_call(moka, param); moka_call(moka, param);
self->pc++; self->pc++;

View File

@ -19,6 +19,8 @@ void lexer_init(struct lexer* self,
str_init(&self->separators); str_init(&self->separators);
str_push(&self->separators, '('); str_push(&self->separators, '(');
str_push(&self->separators, ')'); str_push(&self->separators, ')');
str_push(&self->separators, '[');
str_push(&self->separators, ']');
} }
void lexer_free(struct lexer* self) void lexer_free(struct lexer* self)
@ -41,6 +43,16 @@ struct token* lexer_try_new_next(struct lexer* self)
lexer_skip_spaces(self); lexer_skip_spaces(self);
lexer_skip_comments(self); lexer_skip_comments(self);
if ( (tok=lexer_try_new_text(self, TOKEN_OSQUARE, "[")) )
{
return tok;
}
if ( (tok=lexer_try_new_text(self, TOKEN_CSQUARE, "]")) )
{
return tok;
}
if ( (tok=lexer_try_new_text(self, TOKEN_OPAR, "(")) ) if ( (tok=lexer_try_new_text(self, TOKEN_OPAR, "(")) )
{ {
return tok; return tok;

View File

@ -70,7 +70,7 @@ void moka_import_module(struct moka* self,
assert(self); assert(self);
assert(name); assert(name);
assert(module); assert(module);
struct symtable* mod_sym = &module->moka.symtable; struct symtable* mod_sym = &module->moka.symtable;
struct env* env = mod_sym->root; struct env* env = mod_sym->root;
@ -98,41 +98,41 @@ void moka_import_module(struct moka* self,
{ {
case TY_NATIVE: { case TY_NATIVE: {
moka_decl_native( moka_decl_native(
self, self,
new_name, new_name,
val->data.native->fun val->data.native->fun
); );
} break; } break;
case TY_SYMBOL: { case TY_SYMBOL: {
moka_decl_var( moka_decl_var(
self, self,
new_name, new_name,
moka_push_symbol(self, moka_push_symbol(self,
val->data.sym, val->data.sym,
val->line)); val->line));
} break; } break;
case TY_STRING: { case TY_STRING: {
moka_decl_var( moka_decl_var(
self, self,
new_name, new_name,
moka_push_string(self, moka_push_string(self,
val->data.str, val->data.str,
val->line)); val->line));
} break; } break;
case TY_INT: { case TY_INT: {
moka_decl_var( moka_decl_var(
self, self,
new_name, new_name,
moka_push_int(self, moka_push_int(self,
val->data.integer, val->data.integer,
val->line)); val->line));
} break; } break;
default: { default: {
fprintf(stderr, fprintf(stderr,
"cannot import value of type <%s>\n", "cannot import value of type <%s>\n",
TypeKindStr[val->type]); TypeKindStr[val->type]);
abort(); abort();
@ -246,7 +246,28 @@ void moka_dump(struct moka* self, MOKA value)
{ {
if (moka_is(self, value, TY_REF)) if (moka_is(self, value, TY_REF))
{ {
printf("&%zu", moka_get_ref(self, value)); size_t ref = moka_get_ref(self, value);
struct value* val = self->global_values.data[ref];
if (val->type == TY_ARRAY)
{
printf("[");
for (size_t i=0; i<val->data.array->values.size; i++)
{
if (i > 0) { printf(" "); }
MOKA v = (MOKA) val->data.array->values.data[i];
moka_dump(self, v);
}
printf("]");
}
else
{
char buffer[MK_STRLEN];
value_str(val, buffer, MK_STRLEN);
printf("%s", buffer);
}
return; return;
} }
@ -276,7 +297,7 @@ void moka_dump(struct moka* self, MOKA value)
if (moka_is(self, value, TY_SYMBOL)) if (moka_is(self, value, TY_SYMBOL))
{ {
printf("'%s", moka_get_symbol(self, value)); printf("%s", moka_get_symbol(self, value));
return; return;
} }
@ -287,6 +308,40 @@ void moka_dump(struct moka* self, MOKA value)
abort(); abort();
} }
MOKA moka_make_array(struct moka* self, int elements_count)
{
struct value* value = malloc(sizeof(struct value));
struct vec elements;
vec_init(&elements);
int line = 0;
struct frame* frame = moka_frame(self);
for (int i=0; i<elements_count; i++)
{
MOKA val = moka_pop(self);
line = ((struct value*) frame->local_values.data[val])->line;
vec_push(&elements, (void*) val);
}
struct vec reverse;
vec_init(&reverse);
for (size_t i=0; i<elements.size; i++)
{
size_t k = elements.size - 1 - i;
vec_push(&reverse, elements.data[k]);
}
value_init_array(value, &reverse, line);
vec_push(&self->global_values, value);
moka_push_ref(self, self->global_values.size - 1, line);
vec_free(&elements);
vec_free(&reverse);
return 0;
}
MOKA moka_call(struct moka* self, int arg_count) MOKA moka_call(struct moka* self, int arg_count)
{ {
MOKA fun = moka_pop(self); MOKA fun = moka_pop(self);

View File

@ -63,6 +63,7 @@ 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);
MOKA moka_make_array(struct moka* self, int elements_count);
MOKA moka_call(struct moka* self, int arg_count); MOKA moka_call(struct moka* self, int arg_count);
MOKA moka_push(struct moka* self, MOKA value); MOKA moka_push(struct moka* self, MOKA value);

View File

@ -29,7 +29,7 @@ struct node* parser_try(struct parser* self,
struct lex_context ctx = lexer_state(self->lexer); struct lex_context ctx = lexer_state(self->lexer);
struct node* node = rule(self); struct node* node = rule(self);
if (node == NULL) if (node == NULL)
{ {
lexer_restore(self->lexer, ctx); lexer_restore(self->lexer, ctx);
@ -50,7 +50,6 @@ struct node* parser_try_new_root(struct parser* self)
if (!expr && !lexer_end(self->lexer)) if (!expr && !lexer_end(self->lexer))
{ {
printf("not at end: %c\n", self->lexer->source[self->lexer->context.cursor]);
node_free(root); node_free(root);
free(root); free(root);
return NULL; return NULL;
@ -71,9 +70,58 @@ struct node* parser_try_new_expr(struct parser* self)
return MK_TRY(parser_try_new_call); return MK_TRY(parser_try_new_call);
} }
if (lexer_next_is(self->lexer, TOKEN_OSQUARE, 0))
{
return MK_TRY(parser_try_new_array);
}
return MK_TRY(parser_try_new_atom); return MK_TRY(parser_try_new_atom);
} }
struct node* parser_try_new_array(struct parser* self)
{
if (!lexer_next_is(self->lexer, TOKEN_OSQUARE, 0))
{
return NULL;
}
lexer_skip(self->lexer, TOKEN_OSQUARE);
struct node* array = malloc(sizeof(struct node));
node_init(array, NODE_CALL, NULL, self->lexer->context.line);
while (!lexer_next_is(self->lexer, TOKEN_CSQUARE, 0))
{
struct node* expr = MK_TRY(parser_try_new_expr);
if (!expr)
{
node_free(array); free(array);
return NULL;
}
node_add_new_child(array, expr);
}
if (!lexer_next_is(self->lexer, TOKEN_CSQUARE, 0))
{
return NULL;
}
lexer_skip(self->lexer, TOKEN_CSQUARE);
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_CALL, NULL, self->lexer->context.line);
struct node* ident = malloc(sizeof(struct node));
struct token* tok = malloc(sizeof(struct token));
token_init(tok, TOKEN_IDENT, "quote");
node_init(ident, NODE_IDENT, tok, self->lexer->context.line);
node_add_new_child(node, ident);
node_add_new_child(node, array);
return node;
}
struct node* parser_try_new_call(struct parser* self) struct node* parser_try_new_call(struct parser* self)
{ {
assert(self); assert(self);
@ -86,7 +134,7 @@ struct node* parser_try_new_call(struct parser* self)
lexer_skip(self->lexer, TOKEN_OPAR); lexer_skip(self->lexer, TOKEN_OPAR);
struct node* target = MK_TRY(parser_try_new_expr); struct node* target = MK_TRY(parser_try_new_expr);
if (!target) if (!target)
{ {
return NULL; return NULL;
@ -185,7 +233,7 @@ struct node* parser_try_new_atom(struct parser* self)
self->lexer->context.line); self->lexer->context.line);
return node; return node;
} }
return NULL; return NULL;
} }

View File

@ -20,6 +20,7 @@ struct node* parser_try(struct parser* self,
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_expr(struct parser* self);
struct node* parser_try_new_array(struct parser* self);
struct node* parser_try_new_call(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);

View File

@ -40,6 +40,10 @@ size_t prog_add_instruction(struct prog* self,
self->stack_addr++; self->stack_addr++;
} break; } break;
case OP_MAKE_ARRAY: {
self->stack_addr += param;
} break;
default: { default: {
fprintf(stderr, "cannot find stack address of <%s>\n", fprintf(stderr, "cannot find stack address of <%s>\n",
OpcodeKindStr[opcode]); OpcodeKindStr[opcode]);
@ -64,14 +68,14 @@ size_t prog_add_new_value(struct prog* self,
void prog_dump(struct prog* self) void prog_dump(struct prog* self)
{ {
assert(self); assert(self);
printf("--- PROG ---\n"); printf("--- PROG ---\n");
for (size_t i=0; i<self->instructions.size; i++) for (size_t i=0; i<self->instructions.size; i++)
{ {
struct instruction const* instr = self->instructions.data[i]; struct instruction const* instr = self->instructions.data[i];
printf("%zu\t%s %zd\n", printf("%zu\t%s %zd\n",
i, i,
OpcodeKindStr[instr->opcode], OpcodeKindStr[instr->opcode],
instr->param); instr->param);
} }
} }

View File

@ -9,7 +9,8 @@
G(OP_PUSH), \ G(OP_PUSH), \
G(OP_LOCAL_LOAD), \ G(OP_LOCAL_LOAD), \
G(OP_GLOBAL_LOAD), \ G(OP_GLOBAL_LOAD), \
G(OP_CALL) G(OP_CALL), \
G(OP_MAKE_ARRAY)
MK_ENUM_H(OpcodeKind, OPCODE_KIND); MK_ENUM_H(OpcodeKind, OPCODE_KIND);

View File

@ -8,7 +8,7 @@ G(TOKEN_INT), G(TOKEN_FLOAT), \
G(TOKEN_BOOL), G(TOKEN_STRING), \ G(TOKEN_BOOL), G(TOKEN_STRING), \
G(TOKEN_SYMBOL), G(TOKEN_IDENT), \ G(TOKEN_SYMBOL), G(TOKEN_IDENT), \
G(TOKEN_OPAR), G(TOKEN_CPAR), \ G(TOKEN_OPAR), G(TOKEN_CPAR), \
G(TOKEN_EOF) G(TOKEN_OSQUARE), G(TOKEN_CSQUARE)
MK_ENUM_H(TokenKind, TOKEN_KIND); MK_ENUM_H(TokenKind, TOKEN_KIND);

View File

@ -71,6 +71,89 @@ void value_init_lazy(struct value* self, struct node* value, int line)
self->line = line; self->line = line;
} }
void value_init_array(struct value* self, struct vec* new_values, int line)
{
assert(self);
assert(new_values);
self->data.array = malloc(sizeof(struct array));
array_init(self->data.array);
for (size_t i=0; i<new_values->size; i++)
{
array_push_value(self->data.array, (MOKA) new_values->data[i]);
}
self->type = TY_ARRAY;
self->line = line;
}
size_t value_str(struct value* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
switch (self->type)
{
case TY_INT: {
return snprintf(buffer, size, "%d", self->data.integer);
} break;
case TY_FLOAT: {
return snprintf(buffer, size, "%f", self->data.real);
} break;
case TY_BOOL: {
return snprintf(buffer, size, "%s",
self->data.boolean ? "true" : "false");
} break;
case TY_STRING: {
return snprintf(buffer, size, "%s", self->data.str);
} break;
case TY_SYMBOL: {
return snprintf(buffer, size, "%s", self->data.sym);
} break;
case TY_REF: {
return snprintf(buffer, size, "<ref:%zu>", self->data.ref);
} break;
case TY_NATIVE: {
return snprintf(buffer, size, "<native: %p>", self->data.native);
} break;
case TY_LAZY: {
return snprintf(buffer, size, "<lazy:%s>",
NodeKindStr[self->data.lazy->kind]
+ strlen("NODE_"));
} break;
case TY_ARRAY: {
size_t sz = 0;
sz += snprintf(buffer + sz, size - sz, "[array]");
return sz;
} break;
default: {
fprintf(stderr, "cannot stringify value <%s>\n",
TypeKindStr[self->type]);
abort();
} break;
}
// void value_init_int(struct value* self, int value, int line);
// 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_init_array(struct value* self, struct vec* new_values, int line);
}
void value_free(struct value* self) void value_free(struct value* self)
{ {
assert(self); assert(self);
@ -90,4 +173,10 @@ void value_free(struct value* self)
native_free(self->data.native); native_free(self->data.native);
free(self->data.native); free(self->data.native);
} }
if (self->type == TY_ARRAY)
{
array_free(self->data.array);
free(self->data.array);
}
} }

View File

@ -3,11 +3,12 @@
#include "commons.h" #include "commons.h"
#include "native.h" #include "native.h"
#include "array.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_REF), \ G(TY_STRING), G(TY_SYMBOL), G(TY_REF), \
G(TY_NATIVE), G(TY_LAZY) G(TY_NATIVE), G(TY_LAZY), G(TY_ARRAY)
MK_ENUM_H(TypeKind, TYPE_KIND); MK_ENUM_H(TypeKind, TYPE_KIND);
@ -21,6 +22,7 @@ union value_data
size_t ref; size_t ref;
struct native* native; struct native* native;
struct node* lazy; struct node* lazy;
struct array* array;
}; };
struct value struct value
@ -38,6 +40,9 @@ 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_ref(struct value* self, size_t value, int line);
void value_init_native(struct value* self, struct native* 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_init_lazy(struct value* self, struct node* value, int line);
void value_init_array(struct value* self, struct vec* new_values, int line);
size_t value_str(struct value* self, char* buffer, size_t size);
void value_free(struct value* self); void value_free(struct value* self);

View File

@ -84,11 +84,22 @@ START_TEST(lexer_funcall)
); );
} }
END_TEST END_TEST
START_TEST(lexer_array)
{
test_lexer(" [] ", 2,
TOKEN_OSQUARE, "[",
TOKEN_CSQUARE, "]"
);
}
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); tcase_add_test(tcase, lexer_funcall);
tcase_add_test(tcase, lexer_array);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);
} }

View File

@ -72,11 +72,22 @@ START_TEST(parser_call)
} }
END_TEST END_TEST
START_TEST(parser_array)
{
test_parser("ROOT(CALL(IDENT[quote],CALL(INT[1],INT[2],INT[3])))",
" [1 2 3] ");
test_parser("ROOT(CALL(IDENT[quote],CALL(INT[1])))",
" [1] ");
}
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); tcase_add_test(tcase, parser_call);
tcase_add_test(tcase, parser_array);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);
} }