summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--uscript/parser.c57
-rw-r--r--uscript/vm.c2
2 files changed, 50 insertions, 9 deletions
diff --git a/uscript/parser.c b/uscript/parser.c
index d3f1432..5740474 100644
--- a/uscript/parser.c
+++ b/uscript/parser.c
@@ -156,7 +156,7 @@ void expect(struct parser *p, u16 tok, const char *err)
}
static
-void declare_variable(struct parser *p, struct token name)
+int declare_variable(struct parser *p, struct token name)
{
if (da_len(p->fp->locals) > UINT8_MAX)
show_error(p, name, "too many locals");
@@ -165,6 +165,21 @@ void declare_variable(struct parser *p, struct token name)
slot.name = name;
slot.captured = false;
da_append(struct variable, &p->fp->locals, slot);
+
+ return da_len(p->fp->locals) - 1;
+}
+
+static
+int declare_named_variable(struct parser *p, const char* name)
+{
+ struct token token;
+ token.start = name;
+ token.len = (int)strlen(name);
+ token.line = p->cur.line;
+ token.col = p->cur.col;
+ token.kind = TOKEN_IDENT;
+ token.val = create_zilch();
+ return declare_variable(p, token);
}
static
@@ -663,6 +678,7 @@ void if_stat(struct parser *p, bool is_elseif)
expr(p);
int jump = begin_jump(p, BC_FALSEY_JMP);
+ parser_add_byte(p, BC_POP);
if (!is_elseif)
expect(p, ':', "expected ':' to begin 'if' block");
@@ -683,6 +699,7 @@ void if_stat(struct parser *p, bool is_elseif)
int else_jump = begin_jump(p, BC_JMP);
end_jump(p, jump);
+ parser_add_byte(p, BC_POP);
// The only reason "elseif" was chosen over "else if" is because it
// reduces indentation in this one single spot.
@@ -705,9 +722,6 @@ void if_stat(struct parser *p, bool is_elseif)
static
void loop_stat(struct parser *p)
{
- // For now, we will just support loop <cond>. loop <var> in <expr>
- // needs a lot to happen before it can be implemented.
-
struct token begin = p->prev;
struct loop loop;
@@ -721,10 +735,36 @@ void loop_stat(struct parser *p)
int exit_jump = -1;
if (!consume(p, ':')) {
- expr(p);
- exit_jump = begin_jump(p, BC_FALSEY_JMP);
+ if (consume(p, TOKEN_LET)) {
+ expect(p, TOKEN_IDENT, "expected identifier");
+ struct token ident = p->prev;
+
+ expect(p, TOKEN_IN, "expected 'in'");
+
+ expr(p);
+
+ int iter = declare_named_variable(p, "<iter>");
+
+ begin_scope(p);
+ loop.start = da_len(p->fp->proto->bytecode) - 1;
+
+ parser_add_byte(p, BC_GET_LOCAL);
+ parser_add_byte(p, (u8)iter);
+ parser_add_byte(p, BC_CALL);
+ parser_add_byte(p, 0);
+
+ exit_jump = begin_jump(p, BC_FALSEY_JMP);
+
+ declare_variable(p, ident);
+ } else {
+ expr(p);
+ exit_jump = begin_jump(p, BC_FALSEY_JMP);
+ parser_add_byte(p, BC_POP);
+ }
expect(p, ':', "expected ':' to begin 'loop' block");
+ } else {
+ begin_scope(p);
}
if (consume(p, '<')) {
@@ -734,14 +774,15 @@ void loop_stat(struct parser *p)
expect(p, '>', "expected '>' after loop label");
}
- begin_scope(p);
while (p->cur.kind != TOKEN_END && p->cur.kind != TOKEN_EOF)
stat(p);
end_scope(p);
add_loop(p, loop.start);
- if (exit_jump != -1)
+ if (exit_jump != -1) {
end_jump(p, exit_jump);
+ parser_add_byte(p, BC_POP);
+ }
for (int i = 0; i < da_len(loop.breaks); i++)
end_jump(p, loop.breaks[i]);
diff --git a/uscript/vm.c b/uscript/vm.c
index d68e850..18f1eaf 100644
--- a/uscript/vm.c
+++ b/uscript/vm.c
@@ -403,7 +403,7 @@ void us_exec(struct us_func *func)
}
case BC_FALSEY_JMP: {
u16 jmp = read_short();
- if (as_bool(vm_pop()))
+ if (as_bool(vm_peek()))
break;
i += jmp;
break;