Browse files

next and last for loop flow control

  • Loading branch information...
1 parent 947ab74 commit 6fed1aa7de00a2198c6d5dd376de364f3e2da09e @charliesome committed Aug 5, 2012
Showing with 94 additions and 8 deletions.
  1. +3 −1 inc/ast.h
  2. +6 −1 inc/error.h
  3. +6 −0 inc/eval.h
  4. +2 −0 inc/lex.h
  5. +3 −0 inc/parse.h
  6. +54 −6 src/eval.c
  7. +2 −0 src/lex.yy
  8. +12 −0 src/parse.c
  9. +6 −0 src/parse_helper.c
View
4 inc/ast.h
@@ -36,7 +36,9 @@ typedef enum sl_node_type {
SL_NODE_ARRAY,
SL_NODE_DICT,
SL_NODE_RETURN,
- SL_NODE_RANGE
+ SL_NODE_RANGE,
+ SL_NODE_NEXT,
+ SL_NODE_LAST
}
sl_node_type_t;
View
7 inc/error.h
@@ -8,6 +8,8 @@ typedef enum sl_unwind_type {
SL_UNWIND_EXCEPTION = 1,
SL_UNWIND_RETURN = 2,
SL_UNWIND_EXIT = 4,
+ SL_UNWIND_NEXT = 8,
+ SL_UNWIND_LAST = 16,
SL_UNWIND_ALL = 0xff
}
sl_unwind_type_t;
@@ -33,6 +35,9 @@ void
sl_error_add_frame(struct sl_vm* vm, SLVAL error, SLVAL receiver, SLVAL method, SLVAL file, SLVAL line);
void
+sl_unwind(struct sl_vm* vm, SLVAL value, sl_unwind_type_t type);
+
+void
sl_throw(struct sl_vm* vm, SLVAL error);
void
@@ -42,7 +47,7 @@ void
sl_return(struct sl_vm* vm, SLVAL value);
void
-sl_exit(struct sl_vm* vm, SLVAL value);
+sl_exit(struct sl_vm* vm, SLVAL value);
void
sl_throw_message(struct sl_vm* vm, char* cstr);
View
6 inc/eval.h
@@ -109,4 +109,10 @@ sl_eval_return(sl_node_unary_t* node, sl_eval_ctx_t* ctx);
SLVAL
sl_eval_range(sl_node_range_t* node, sl_eval_ctx_t* ctx);
+SLVAL
+sl_eval_next(sl_node_base_t* node, sl_eval_ctx_t* ctx);
+
+SLVAL
+sl_eval_last(sl_node_base_t* node, sl_eval_ctx_t* ctx);
+
#endif
View
2 inc/lex.h
@@ -43,6 +43,8 @@ typedef enum sl_token_type {
SL_TOK_TRY,
SL_TOK_CATCH,
SL_TOK_RETURN,
+ SL_TOK_NEXT,
+ SL_TOK_LAST,
SL_TOK_OPEN_PAREN,
SL_TOK_CLOSE_PAREN,
View
3 inc/parse.h
@@ -40,6 +40,9 @@ sl_parse_error(sl_parse_state_t* ps, char* message);
int
sl_node_is_lval(sl_node_base_t* node);
+sl_node_base_t*
+sl_make_singleton_node(sl_parse_state_t* ps, sl_node_type_t type, sl_node_eval_fn_t fn);
+
sl_node_seq_t*
sl_make_seq_node(sl_parse_state_t* ps);
View
60 src/eval.c
@@ -368,15 +368,29 @@ sl_eval_if(sl_node_if_t* node, sl_eval_ctx_t* ctx)
SLVAL
sl_eval_for(sl_node_for_t* node, sl_eval_ctx_t* ctx)
{
+ sl_catch_frame_t frame;
+ sl_vm_t* vm = ctx->vm;
SLVAL enumerable = node->expr->eval(node->expr, ctx);
- SLVAL enumerator = sl_send(ctx->vm, enumerable, "enumerate", 0, NULL);
+ SLVAL enumerator = sl_send(vm, enumerable, "enumerate", 0, NULL);
SLVAL val;
- int iterated = 0;
- while(sl_is_truthy(sl_send(ctx->vm, enumerator, "next", 0, NULL))) {
- val = sl_send(ctx->vm, enumerator, "current", 0, NULL);
+ int iterated = 0, cont_break;
+ while(sl_is_truthy(sl_send(vm, enumerator, "next", 0, NULL))) {
+ val = sl_send(vm, enumerator, "current", 0, NULL);
set_lval(node->lval, ctx, val);
iterated = 1;
- node->body->eval(node->body, ctx);
+ cont_break = 0;
+ SL_TRY(frame, SL_UNWIND_NEXT | SL_UNWIND_LAST, {
+ node->body->eval(node->body, ctx);
+ }, val, {
+ cont_break = 1;
+ });
+ if(cont_break) {
+ if(frame.type == SL_UNWIND_NEXT) {
+ continue;
+ } else {
+ break;
+ }
+ }
}
if(!iterated) {
if(node->else_body) {
@@ -389,8 +403,24 @@ sl_eval_for(sl_node_for_t* node, sl_eval_ctx_t* ctx)
SLVAL
sl_eval_while(sl_node_while_t* node, sl_eval_ctx_t* ctx)
{
+ sl_catch_frame_t frame;
+ SLVAL dummy;
+ int cont_break;
+ sl_vm_t* vm = ctx->vm;
while(sl_is_truthy(node->expr->eval(node->expr, ctx))) {
- node->body->eval(node->body, ctx);
+ cont_break = 0;
+ SL_TRY(frame, SL_UNWIND_NEXT | SL_UNWIND_LAST, {
+ node->body->eval(node->body, ctx);
+ }, dummy, {
+ cont_break = 1;
+ });
+ if(cont_break) {
+ if(frame.type == SL_UNWIND_NEXT) {
+ continue;
+ } else {
+ break;
+ }
+ }
}
return ctx->vm->lib.nil;
}
@@ -512,3 +542,21 @@ sl_eval_range(sl_node_range_t* node, sl_eval_ctx_t* ctx)
return sl_make_range(ctx->vm, left, right);
}
}
+
+SLVAL
+sl_eval_next(sl_node_base_t* node, sl_eval_ctx_t* ctx)
+{
+ sl_unwind(ctx->vm, ctx->vm->lib.nil, SL_UNWIND_NEXT);
+ /* never reached: */
+ (void)node;
+ return ctx->vm->lib.nil;
+}
+
+SLVAL
+sl_eval_last(sl_node_base_t* node, sl_eval_ctx_t* ctx)
+{
+ sl_unwind(ctx->vm, ctx->vm->lib.nil, SL_UNWIND_LAST);
+ /* never reached: */
+ (void)node;
+ return ctx->vm->lib.nil;
+}
View
2 src/lex.yy
@@ -110,6 +110,8 @@ HEX [0-9a-fA-F]
<SLASH>"try"/{NKW} { ADD_TOKEN(sl_make_token(SL_TOK_TRY)); }
<SLASH>"catch"/{NKW} { ADD_TOKEN(sl_make_token(SL_TOK_CATCH)); }
<SLASH>"return"/{NKW} { ADD_TOKEN(sl_make_token(SL_TOK_RETURN)); }
+<SLASH>"next"/{NKW} { ADD_TOKEN(sl_make_token(SL_TOK_NEXT)); }
+<SLASH>"last"/{NKW} { ADD_TOKEN(sl_make_token(SL_TOK_LAST)); }
<SLASH>[A-Z]{IDT}? { ADD_TOKEN(sl_make_string_token(yyextra, SL_TOK_CONSTANT, yytext, yyleng)); }
<SLASH>{ID} { ADD_TOKEN(sl_make_string_token(yyextra, SL_TOK_IDENTIFIER, yytext, yyleng)); }
View
12 src/parse.c
@@ -525,6 +525,18 @@ primary_expression(sl_parse_state_t* ps)
return bracketed_expression(ps);
case SL_TOK_OPEN_BRACE:
return dict_expression(ps);
+ case SL_TOK_NEXT:
+ tok = next_token(ps);
+ if(!(ps->scope->flags & SL_PF_CAN_NEXT_LAST)) {
+ error(ps, sl_make_cstring(ps->vm, "next invalid outside loop"), tok);
+ }
+ return sl_make_singleton_node(ps, SL_NODE_NEXT, sl_eval_next);
+ case SL_TOK_LAST:
+ tok = next_token(ps);
+ if(!(ps->scope->flags & SL_PF_CAN_NEXT_LAST)) {
+ error(ps, sl_make_cstring(ps->vm, "last invalid outside loop"), tok);
+ }
+ return sl_make_singleton_node(ps, SL_NODE_LAST, sl_eval_last);
default:
unexpected(ps, peek_token(ps));
return NULL;
View
6 src/parse_helper.c
@@ -50,6 +50,12 @@ sl_make_node(sl_parse_state_t* ps, sl_node_type_t type, sl_node_eval_fn_t eval,
return node;
}
+sl_node_base_t*
+sl_make_singleton_node(sl_parse_state_t* ps, sl_node_type_t type, sl_node_eval_fn_t fn)
+{
+ return sl_make_node(ps, type, fn, sizeof(sl_node_base_t));
+}
+
#define MAKE_NODE(t, eval, type, block) do { \
type* node = (type*)sl_make_node(ps, (t), (sl_node_eval_fn_t)(eval), sizeof(type)); \
block; \

0 comments on commit 6fed1aa

Please sign in to comment.