1
0
mirror of https://github.com/janet-lang/janet synced 2025-01-12 16:40:27 +00:00

Add early returns via break.

Inside a while loop, the argument to
break does nothing as while loops always
return nil.
This commit is contained in:
Calvin Rose 2019-03-09 22:01:10 -05:00
parent 9a080197e7
commit 8ba1121161
2 changed files with 35 additions and 9 deletions

View File

@ -479,11 +479,12 @@ static int32_t janetc_addfuncdef(JanetCompiler *c, JanetFuncDef *def) {
static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
JanetScope *scope = c->scope;
(void) argv;
if (argn != 0) {
janetc_cerror(c, "expected no arguments");
if (argn > 1) {
janetc_cerror(c, "expected at most 1 argument");
return janetc_cslot(janet_wrap_nil());
}
/* Find scope to break from */
while (scope) {
if (scope->flags & (JANET_SCOPE_FUNCTION | JANET_SCOPE_WHILE))
break;
@ -493,13 +494,32 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_cerror(c, "break must occur in while loop or closure");
return janetc_cslot(janet_wrap_nil());
}
if (scope->flags | JANET_SCOPE_FUNCTION) {
/* Just return, either in IIFE or closure body */
/* Emit code to break from that scope */
JanetFopts subopts = janetc_fopts_default(c);
if (scope->flags & JANET_SCOPE_FUNCTION) {
if (!(scope->flags & JANET_SCOPE_WHILE) && argn) {
/* Closure body with return argument */
subopts.flags |= JANET_FOPTS_TAIL;
JanetSlot ret = janetc_value(subopts, argv[0]);
ret.flags |= JANET_SLOT_RETURNED;
return ret;
} else {
/* while loop IIFE or no argument */
if (argn) {
subopts.flags |= JANET_FOPTS_DROP;
janetc_value(subopts, argv[0]);
}
janetc_emit(c, JOP_RETURN_NIL);
JanetSlot s = janetc_cslot(janet_wrap_nil());
s.flags |= JANET_SLOT_RETURNED;
return s;
}
} else {
if (argn) {
subopts.flags |= JANET_FOPTS_DROP;
janetc_value(subopts, argv[0]);
}
/* Tag the instruction so the while special can turn it into a proper jump */
janetc_emit(c, 0x80 | JOP_JUMP);
return janetc_cslot(janet_wrap_nil());

View File

@ -74,4 +74,10 @@
(assert (= nil ((fn [] (break) 4))) "break 2")
# Break with value
# Shouldn't error out
(assert-no-error "break 3" (for i 0 10 (if (> i 8) (break i))))
(assert-no-error "break 4" ((fn [i] (if (> i 8) (break i))) 100))
(end-suite)