mirror of
https://github.com/janet-lang/janet
synced 2025-08-04 04:53:57 +00:00
Allow iterating over fibers with each and similar.
This commit is contained in:
parent
ecc6eb7497
commit
c357af02c2
4
Makefile
4
Makefile
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2020 Calvin Rose
|
# Copyright (c) 2021 Calvin Rose
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to
|
# of this software and associated documentation files (the "Software"), to
|
||||||
@ -27,7 +27,7 @@ PREFIX?=/usr/local
|
|||||||
INCLUDEDIR?=$(PREFIX)/include
|
INCLUDEDIR?=$(PREFIX)/include
|
||||||
BINDIR?=$(PREFIX)/bin
|
BINDIR?=$(PREFIX)/bin
|
||||||
LIBDIR?=$(PREFIX)/lib
|
LIBDIR?=$(PREFIX)/lib
|
||||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n &>2 /dev/null || echo local)\""
|
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 2> /dev/null || echo local)\""
|
||||||
CLIBS=-lm -lpthread
|
CLIBS=-lm -lpthread
|
||||||
JANET_TARGET=build/janet
|
JANET_TARGET=build/janet
|
||||||
JANET_LIBRARY=build/libjanet.so
|
JANET_LIBRARY=build/libjanet.so
|
||||||
|
28
examples/iterate-fiber.janet
Normal file
28
examples/iterate-fiber.janet
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
(def f
|
||||||
|
(coro
|
||||||
|
(for i 0 10
|
||||||
|
(yield (string "yield " i))
|
||||||
|
(os/sleep 0))))
|
||||||
|
|
||||||
|
(print "simple yielding")
|
||||||
|
(each item f (print "got: " item ", now " (fiber/status f)))
|
||||||
|
|
||||||
|
(def f
|
||||||
|
(coro
|
||||||
|
(for i 0 10
|
||||||
|
(yield (string "yield " i))
|
||||||
|
(ev/sleep 0))))
|
||||||
|
|
||||||
|
(print "old style fiber iteration")
|
||||||
|
(eachy item f (print "got: " item ", now " (fiber/status f)))
|
||||||
|
|
||||||
|
(def f
|
||||||
|
(coro
|
||||||
|
(for i 0 10
|
||||||
|
(yield (string "yield " i))
|
||||||
|
(ev/sleep 0))))
|
||||||
|
|
||||||
|
(print "complex yielding")
|
||||||
|
(each item f (print "got: " item ", now " (fiber/status f)))
|
||||||
|
|
||||||
|
(print (fiber/status f))
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Calvin Rose
|
* Copyright (c) 2021 Calvin Rose
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Calvin Rose
|
* Copyright (c) 2021 Calvin Rose
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
@ -37,6 +37,7 @@ static void fiber_reset(JanetFiber *fiber) {
|
|||||||
fiber->child = NULL;
|
fiber->child = NULL;
|
||||||
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||||
fiber->env = NULL;
|
fiber->env = NULL;
|
||||||
|
fiber->last_value = janet_wrap_nil();
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
fiber->waiting = NULL;
|
fiber->waiting = NULL;
|
||||||
fiber->sched_id = 0;
|
fiber->sched_id = 0;
|
||||||
@ -586,6 +587,12 @@ static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_boolean(!isFinished);
|
return janet_wrap_boolean(!isFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet cfun_fiber_last_value(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||||
|
return fiber->last_value;
|
||||||
|
}
|
||||||
|
|
||||||
static const JanetReg fiber_cfuns[] = {
|
static const JanetReg fiber_cfuns[] = {
|
||||||
{
|
{
|
||||||
"fiber/new", cfun_fiber_new,
|
"fiber/new", cfun_fiber_new,
|
||||||
@ -663,6 +670,11 @@ static const JanetReg fiber_cfuns[] = {
|
|||||||
JDOC("(fiber/can-resume? fiber)\n\n"
|
JDOC("(fiber/can-resume? fiber)\n\n"
|
||||||
"Check if a fiber is finished and cannot be resumed.")
|
"Check if a fiber is finished and cannot be resumed.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fiber/last-value", cfun_fiber_last_value,
|
||||||
|
JDOC("(fiber/last-value\n\n"
|
||||||
|
"Get the last value returned or signaled from the fiber.")
|
||||||
|
},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,6 +244,8 @@ recur:
|
|||||||
return;
|
return;
|
||||||
janet_gc_mark(fiber);
|
janet_gc_mark(fiber);
|
||||||
|
|
||||||
|
janet_mark(fiber->last_value);
|
||||||
|
|
||||||
/* Mark values on the argument stack */
|
/* Mark values on the argument stack */
|
||||||
janet_mark_many(fiber->data + fiber->stackstart,
|
janet_mark_many(fiber->data + fiber->stackstart,
|
||||||
fiber->stacktop - fiber->stackstart);
|
fiber->stacktop - fiber->stackstart);
|
||||||
|
@ -91,6 +91,7 @@ void janet_buffer_format(
|
|||||||
int32_t argstart,
|
int32_t argstart,
|
||||||
int32_t argc,
|
int32_t argc,
|
||||||
Janet *argv);
|
Janet *argv);
|
||||||
|
Janet janet_next_impl(Janet ds, Janet key, int is_interpreter);
|
||||||
|
|
||||||
/* Inside the janet core, defining globals is different
|
/* Inside the janet core, defining globals is different
|
||||||
* at bootstrap time and normal runtime */
|
* at bootstrap time and normal runtime */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Calvin Rose
|
* Copyright (c) 2021 Calvin Rose
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
#include "fiber.h"
|
||||||
#include <janet.h>
|
#include <janet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -115,6 +116,10 @@ static int traversal_next(Janet *x, Janet *y) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Janet janet_next(Janet ds, Janet key) {
|
Janet janet_next(Janet ds, Janet key) {
|
||||||
|
return janet_next_impl(ds, key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Janet janet_next_impl(Janet ds, Janet key, int is_interpreter) {
|
||||||
JanetType t = janet_type(ds);
|
JanetType t = janet_type(ds);
|
||||||
switch (t) {
|
switch (t) {
|
||||||
default:
|
default:
|
||||||
@ -177,6 +182,44 @@ Janet janet_next(Janet ds, Janet key) {
|
|||||||
if (NULL == at->next) break;
|
if (NULL == at->next) break;
|
||||||
return at->next(abst, key);
|
return at->next(abst, key);
|
||||||
}
|
}
|
||||||
|
case JANET_FIBER: {
|
||||||
|
JanetFiber *child = janet_unwrap_fiber(ds);
|
||||||
|
Janet retreg;
|
||||||
|
JanetFiberStatus status = janet_fiber_status(child);
|
||||||
|
if (status == JANET_STATUS_ALIVE ||
|
||||||
|
status == JANET_STATUS_DEAD ||
|
||||||
|
status == JANET_STATUS_ERROR ||
|
||||||
|
status == JANET_STATUS_USER0 ||
|
||||||
|
status == JANET_STATUS_USER1 ||
|
||||||
|
status == JANET_STATUS_USER2 ||
|
||||||
|
status == JANET_STATUS_USER3 ||
|
||||||
|
status == JANET_STATUS_USER4) {
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
janet_vm_fiber->child = child;
|
||||||
|
JanetSignal sig = janet_continue(child, janet_wrap_nil(), &retreg);
|
||||||
|
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
||||||
|
if (is_interpreter) {
|
||||||
|
janet_signalv(sig, retreg);
|
||||||
|
} else {
|
||||||
|
janet_vm_fiber->child = NULL;
|
||||||
|
janet_panicv(retreg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
janet_vm_fiber->child = NULL;
|
||||||
|
if (sig == JANET_SIGNAL_OK ||
|
||||||
|
sig == JANET_SIGNAL_ERROR ||
|
||||||
|
sig == JANET_SIGNAL_USER0 ||
|
||||||
|
sig == JANET_SIGNAL_USER1 ||
|
||||||
|
sig == JANET_SIGNAL_USER2 ||
|
||||||
|
sig == JANET_SIGNAL_USER3 ||
|
||||||
|
sig == JANET_SIGNAL_USER4) {
|
||||||
|
/* Fiber cannot be resumed, so discard last value. */
|
||||||
|
return janet_wrap_nil();
|
||||||
|
} else {
|
||||||
|
return janet_wrap_integer(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
@ -434,6 +477,14 @@ Janet janet_in(Janet ds, Janet key) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case JANET_FIBER: {
|
||||||
|
/* Bit of a hack to allow iterating over fibers. */
|
||||||
|
if (janet_equals(key, janet_wrap_integer(0))) {
|
||||||
|
return janet_unwrap_fiber(ds)->last_value;
|
||||||
|
} else {
|
||||||
|
janet_panicf("expected key 0, got %v", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -489,6 +540,14 @@ Janet janet_get(Janet ds, Janet key) {
|
|||||||
const JanetKV *st = janet_unwrap_struct(ds);
|
const JanetKV *st = janet_unwrap_struct(ds);
|
||||||
return janet_struct_get(st, key);
|
return janet_struct_get(st, key);
|
||||||
}
|
}
|
||||||
|
case JANET_FIBER: {
|
||||||
|
/* Bit of a hack to allow iterating over fibers. */
|
||||||
|
if (janet_equals(key, janet_wrap_integer(0))) {
|
||||||
|
return janet_unwrap_fiber(ds)->last_value;
|
||||||
|
} else {
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +604,14 @@ Janet janet_getindex(Janet ds, int32_t index) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case JANET_FIBER: {
|
||||||
|
if (index == 0) {
|
||||||
|
value = janet_unwrap_fiber(ds)->last_value;
|
||||||
|
} else {
|
||||||
|
value = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Calvin Rose
|
* Copyright (c) 2021 Calvin Rose
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
@ -815,7 +815,11 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
|
|
||||||
VM_OP(JOP_NEXT)
|
VM_OP(JOP_NEXT)
|
||||||
vm_commit();
|
vm_commit();
|
||||||
stack[A] = janet_next(stack[B], stack[C]);
|
{
|
||||||
|
Janet temp = janet_next_impl(stack[B], stack[C], 1);
|
||||||
|
vm_restore();
|
||||||
|
stack[A] = temp;
|
||||||
|
}
|
||||||
vm_pcnext();
|
vm_pcnext();
|
||||||
|
|
||||||
VM_OP(JOP_LOAD_NIL)
|
VM_OP(JOP_LOAD_NIL)
|
||||||
@ -1341,10 +1345,14 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
|||||||
janet_fiber_did_resume(fiber);
|
janet_fiber_did_resume(fiber);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Clear last value */
|
||||||
|
fiber->last_value = janet_wrap_nil();
|
||||||
|
|
||||||
/* Continue child fiber if it exists */
|
/* Continue child fiber if it exists */
|
||||||
if (fiber->child) {
|
if (fiber->child) {
|
||||||
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
|
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
|
||||||
JanetFiber *child = fiber->child;
|
JanetFiber *child = fiber->child;
|
||||||
|
uint32_t instr = (janet_stack_frame(fiber->data + fiber->frame)->pc)[0];
|
||||||
janet_vm_stackn++;
|
janet_vm_stackn++;
|
||||||
JanetSignal sig = janet_continue(child, in, &in);
|
JanetSignal sig = janet_continue(child, in, &in);
|
||||||
janet_vm_stackn--;
|
janet_vm_stackn--;
|
||||||
@ -1353,6 +1361,25 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
|||||||
*out = in;
|
*out = in;
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
/* Check if we need any special handling for certain opcodes */
|
||||||
|
switch (instr & 0x7F) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case JOP_NEXT: {
|
||||||
|
if (sig == JANET_SIGNAL_OK ||
|
||||||
|
sig == JANET_SIGNAL_ERROR ||
|
||||||
|
sig == JANET_SIGNAL_USER0 ||
|
||||||
|
sig == JANET_SIGNAL_USER1 ||
|
||||||
|
sig == JANET_SIGNAL_USER2 ||
|
||||||
|
sig == JANET_SIGNAL_USER3 ||
|
||||||
|
sig == JANET_SIGNAL_USER4) {
|
||||||
|
in = janet_wrap_nil();
|
||||||
|
} else {
|
||||||
|
in = janet_wrap_integer(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
fiber->child = NULL;
|
fiber->child = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1384,6 +1411,7 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
|||||||
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
||||||
janet_fiber_set_status(fiber, signal);
|
janet_fiber_set_status(fiber, signal);
|
||||||
janet_restore(&tstate);
|
janet_restore(&tstate);
|
||||||
|
fiber->last_value = tstate.payload;
|
||||||
*out = tstate.payload;
|
*out = tstate.payload;
|
||||||
|
|
||||||
return signal;
|
return signal;
|
||||||
|
@ -838,6 +838,7 @@ struct JanetFiber {
|
|||||||
JanetTable *env; /* Dynamic bindings table (usually current environment). */
|
JanetTable *env; /* Dynamic bindings table (usually current environment). */
|
||||||
Janet *data; /* Dynamically resized stack memory */
|
Janet *data; /* Dynamically resized stack memory */
|
||||||
JanetFiber *child; /* Keep linked list of fibers for restarting pending fibers */
|
JanetFiber *child; /* Keep linked list of fibers for restarting pending fibers */
|
||||||
|
Janet last_value; /* Last returned value from a fiber */
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
JanetListenerState *waiting;
|
JanetListenerState *waiting;
|
||||||
uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */
|
uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user