for loop expression.

main
bog 2024-03-23 00:48:16 +01:00
parent 40b8b7f68e
commit 687236fb7d
12 changed files with 235 additions and 11 deletions

View File

@ -7,8 +7,10 @@ EXPR ::=
| BEGIN | BEGIN
| IF end | IF end
| WHILE | WHILE
| FOR
| continue | continue
| break | break
FOR ::= for EXPR in EXPR BLOCK end
WHILE ::= while EXPR BLOCK end WHILE ::= while EXPR BLOCK end
IF ::= IF ::=
| if EXPR BLOCK (else (IF | BLOCK))? | if EXPR BLOCK (else (IF | BLOCK))?

View File

@ -10,7 +10,7 @@ G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \ G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \ G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
G(OP_GT), G(OP_MK_ARRAY), G(OP_LOCAL_STORE), \ G(OP_GT), G(OP_MK_ARRAY), G(OP_LOCAL_STORE), \
G(OP_LOCAL_LOAD), G(OP_ASTORE) G(OP_LOCAL_LOAD), G(OP_ASTORE), G(OP_LEN)
CCM_ENUM_H(Opcode, OPCODES); CCM_ENUM_H(Opcode, OPCODES);

View File

@ -266,10 +266,9 @@ char* ccm_from_str(ccm_t* self, CCM value)
return ccm_find_value(self, value)->data.str; return ccm_find_value(self, value)->data.str;
} }
CCM ccm_to_str(ccm_t* self, char* value, int line) CCM ccm_to_str(ccm_t* self, char const* value, int line)
{ {
assert(self); assert(self);
assert(value);
value_t* val = malloc(sizeof(value_t)); value_t* val = malloc(sizeof(value_t));
value_init_str(val, value, line); value_init_str(val, value, line);

View File

@ -51,7 +51,7 @@ CCM ccm_to_boolean(ccm_t* self, int value, int line);
int ccm_is_str(ccm_t* self, CCM value); int ccm_is_str(ccm_t* self, CCM value);
char* ccm_from_str(ccm_t* self, CCM value); char* ccm_from_str(ccm_t* self, CCM value);
CCM ccm_to_str(ccm_t* self, char* value, int line); CCM ccm_to_str(ccm_t* self, char const* value, int line);
int ccm_is_array(ccm_t* self, CCM value); int ccm_is_array(ccm_t* self, CCM value);
vec_t* ccm_from_array(ccm_t* self, CCM value); vec_t* ccm_from_array(ccm_t* self, CCM value);

View File

@ -1,4 +1,5 @@
#include "compiler.h" #include "compiler.h"
#include "prog.h"
void compiler_init(compiler_t* self, module_t* module) void compiler_init(compiler_t* self, module_t* module)
{ {
@ -59,6 +60,99 @@ void compiler_compile(compiler_t* self,
vec_push(&info->to_end, (void*) point); vec_push(&info->to_end, (void*) point);
} break; } break;
case NODE_FOR: {
node_t const* ident = node->children.data[0];
node_t* expr = node->children.data[1];
node_t* block = node->children.data[2];
sym_open_scope(sym);
sym_declare(sym, "__iter",
self->loc_counter++, 0);
sym_declare(sym, ident->value,
self->loc_counter++, 0);
int var_id =
sym_try_get_value(sym, ident->value)->id;
int iter_id =
sym_try_get_value(sym, "__iter")->id;
// initialize iteration counter
value_t* value = malloc(sizeof(value_t));
value_init_num(value, -1, node->line);
prog_add_instr(prog, OP_PUSH, prog_add_new_constant(
prog,
ccm_from_value(ccm, value)
));
prog_add_instr(prog, OP_LOCAL_STORE, iter_id);
int start = prog->instrs.size;
loop_info_t* info = malloc(sizeof(loop_info_t));
info->start_point = start;
vec_init(&info->to_end);
vec_push(&self->loop_infos, info);
// incr iteration counter
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
value_free(value); free(value);
value = malloc(sizeof(value_t));
value_init_num(value, 1, node->line);
prog_add_instr(prog, OP_PUSH, prog_add_new_constant(
prog,
ccm_from_value(ccm, value)
));
prog_add_instr(prog, OP_ADD, CCM_NO_PARAM);
prog_add_instr(prog, OP_LOCAL_STORE, iter_id);
// test if end is reached
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
compiler_compile(self, expr, prog);
prog_add_instr(prog, OP_LEN, CCM_NO_PARAM);
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
int cond_point = prog_add_instr(prog, OP_BRF, 0);
// get current element
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
compiler_compile(self, expr, prog);
prog_add_instr(prog, OP_INDEX, 1);
prog_add_instr(prog, OP_LOCAL_STORE, var_id);
// compile body
compiler_compile(self, block, prog);
// next iteration
prog_add_instr(prog, OP_BR, start);
value_free(value); free(value);
int end_point = prog->instrs.size;
((instr_t*)prog->instrs.data[cond_point])->param
= end_point;
for (size_t i=0; i<info->to_end.size; i++)
{
int addr = (size_t)info->to_end.data[i];
instr_t* instr = prog->instrs.data[addr];
instr->param = end_point;
}
sym_close_scope(sym);
info = vec_pop(&self->loop_infos);
vec_free(&info->to_end);
free(info);
} break;
case NODE_WHILE: { case NODE_WHILE: {
node_t* expr = node->children.data[0]; node_t* expr = node->children.data[0];
node_t* block = node->children.data[1]; node_t* block = node->children.data[1];

View File

@ -130,6 +130,31 @@ void exec_instr(exec_t* self,
self->pc++; self->pc++;
} break; } break;
case OP_LEN: {
CCM ccm_value = ccm_pop(ccm);
value_t* value = ccm_to_value(ccm, ccm_value);
CCM ccm_res = 0;
if (value->type == TYPE_ARRAY)
{
ccm_res = ccm_to_num(
ccm,
value->data.array->size,
value->line
);
}
else if (value->type == TYPE_STR)
{
ccm_res = ccm_to_num(
ccm,
strlen(value->data.str),
value->line
);
}
ccm_push(ccm, ccm_res);
self->pc++;
} break;
case OP_INDEX: { case OP_INDEX: {
CCM ccm_target = ccm_pop(ccm); CCM ccm_target = ccm_pop(ccm);
@ -169,7 +194,7 @@ void exec_instr(exec_t* self,
return; return;
} }
char buf[2] = {target[idx], '\0'}; char const buf[2] = {target[idx], '\0'};
ccm_push(ccm, ccm_to_str(ccm, buf, line)); ccm_push(ccm, ccm_to_str(ccm, buf, line));
} }
else if (ccm_is_tuple(ccm, ccm_target) else if (ccm_is_tuple(ccm, ccm_target)

View File

@ -451,7 +451,13 @@ node_t* lexer_try_new_str(lexer_t* self)
cursor++; cursor++;
self->cursor = cursor; self->cursor = cursor;
node_t* node = malloc(sizeof(node_t)); node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_STR, value.value, self->line);
node_init(
node,
NODE_STR,
value.size == 0 ? "" : value.value,
self->line
);
str_free(&value); str_free(&value);

View File

@ -168,6 +168,11 @@ node_t* parser_try_new_expr(parser_t* self)
return CCM_TRY(parser_try_new_while); return CCM_TRY(parser_try_new_while);
} }
if (lexer_peek_kind(self->lexer, NODE_FOR, 0))
{
return CCM_TRY(parser_try_new_for);
}
if (lexer_peek_kind(self->lexer, NODE_CONTINUE, 0) if (lexer_peek_kind(self->lexer, NODE_CONTINUE, 0)
|| lexer_peek_kind(self->lexer, NODE_BREAK, 0)) || lexer_peek_kind(self->lexer, NODE_BREAK, 0))
{ {
@ -216,6 +221,55 @@ node_t* parser_try_new_while(parser_t* self)
return node; return node;
} }
node_t* parser_try_new_for(parser_t* self)
{
assert(self);
if (!parser_consume(self, NODE_FOR))
{
return NULL;
}
node_t* ident = NULL;
if (lexer_peek_kind(self->lexer, NODE_IDENT, 0))
{
ident = lexer_try_new_next(self->lexer);
}
if (!ident) { return NULL; }
if (!parser_consume(self, NODE_IN))
{
node_free(ident); free(ident);
return NULL;
}
node_t* target = CCM_TRY(parser_try_new_expr);
if (!target)
{
node_free(ident); free(ident);
return NULL;
}
node_t* block = CCM_TRY(parser_try_new_block);
if (!block || !parser_consume(self, NODE_END))
{
node_free(ident); free(ident);
return NULL;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_FOR, "", ident->line);
node_push_new_child(node, ident);
node_push_new_child(node, target);
node_push_new_child(node, block);
return node;
}
node_t* parser_try_new_if(parser_t* self) node_t* parser_try_new_if(parser_t* self)
{ {
assert(self); assert(self);

View File

@ -26,6 +26,7 @@ int parser_ensure(parser_t* self, node_t* node, NodeKind kind);
node_t* parser_try_new_module(parser_t* self); node_t* parser_try_new_module(parser_t* self);
node_t* parser_try_new_expr(parser_t* self); node_t* parser_try_new_expr(parser_t* self);
node_t* parser_try_new_for(parser_t* self);
node_t* parser_try_new_while(parser_t* self); node_t* parser_try_new_while(parser_t* self);
node_t* parser_try_new_if(parser_t* self); node_t* parser_try_new_if(parser_t* self);
node_t* parser_try_new_begin(parser_t* self); node_t* parser_try_new_begin(parser_t* self);

View File

@ -60,7 +60,11 @@ void str_push(str_t* self, char c)
void str_push_cstr(str_t* self, char const* rhs) void str_push_cstr(str_t* self, char const* rhs)
{ {
assert(self); assert(self);
assert(rhs);
if (!rhs)
{
return;
}
for (size_t i=0; i<strlen(rhs); i++) for (size_t i=0; i<strlen(rhs); i++)
{ {

View File

@ -28,8 +28,6 @@ void value_init_boolean(value_t* self, int boolean, int line)
void value_init_str(value_t* self, char const* value, int line) void value_init_str(value_t* self, char const* value, int line)
{ {
assert(self); assert(self);
assert(value);
self->data.str = strdup(value); self->data.str = strdup(value);
self->type = TYPE_STR; self->type = TYPE_STR;
self->line = line; self->line = line;
@ -115,7 +113,6 @@ void value_free(value_t* self)
{ {
if (self->type == TYPE_ARRAY) if (self->type == TYPE_ARRAY)
{ {
//vec_free_elements(self->data.array, (void*) value_free);
vec_free(self->data.array); vec_free(self->data.array);
free(self->data.array); free(self->data.array);
} }
@ -127,7 +124,7 @@ void value_free(value_t* self)
free(self->data.tuple); free(self->data.tuple);
} }
if (self->type == TYPE_STR) if (self->type == TYPE_STR && self->data.str)
{ {
free(self->data.str); free(self->data.str);
} }

View File

@ -1,3 +1,5 @@
# WHILE LOOP
# ==========
var a = 0 var a = 0
while a < 100 while a < 100
@ -63,3 +65,43 @@ while g < 100
end end
assert_eq (21, i) assert_eq (21, i)
# FOR LOOP
# ========
var j = 0
for k in [1, 2, 3]
j = j + k
end
assert_eq (6, j)
var l = 0
var m = [7, 3, 1]
for n in m
l = l + n
end
assert_eq (11, l)
var o = 0
for p in [1, 2, 3, 4, 5, 6, 7]
if p > 5
break
end
if p % 2 == 0
continue
end
o = o + p
end
assert_eq (9, o)
var q = ""
for r in "hello"
q = r + q
end
assert_eq ("olleh", q)