Merge branch 'master' into ev

This commit is contained in:
Calvin Rose 2020-08-16 17:29:57 -05:00
commit 30522bbf7d
11 changed files with 219 additions and 65 deletions

View File

@ -3,7 +3,13 @@ All notable changes to this project will be documented in this file.
## Unreleased - ???
- Silence warnings in some compilers.
- Change `net/read`, `net/chunk`, and `net/write` to raise errors in the case of failures.
- Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop
to raise errors or other signals.
- Update meson build script to fix bug on Debian's version of meson
- Add `xprint`, `xprin`, `xprintf`, and `xprinf`.
- `net/write` now raises an error message if write fails.
- Fix issue with SIGPIPE on macOS and BSDs.
## 1.11.3 - 2020-08-03
- Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled.

View File

@ -15,6 +15,6 @@
(let [server (net/server "127.0.0.1" "8000")]
(print "Starting echo server on 127.0.0.1:8000")
(forever
(if-let [conn (:accept server 2.8)]
(if-let [conn (:accept server)]
(ev/call handler conn)
(print "no new connections"))))

View File

@ -1804,14 +1804,16 @@
(defn expandqq [t]
(defn qq [x]
(case (type x)
:tuple (do
(def x0 (in x 0))
(if (or (= 'unquote x0) (= 'unquote-splicing x0))
(tuple x0 (recur (in x 1)))
(tuple/slice (map qq x))))
:tuple (if (= :brackets (tuple/type x))
~[,;(map qq x)]
(do
(def x0 (get x 0))
(if (= 'unquote x0)
(tuple x0 (recur (get x 1)))
(tuple/slice (map qq x)))))
:array (map qq x)
:table (table (map qq (kvs x)))
:struct (struct (map qq (kvs x)))
:table (table ;(map qq (kvs x)))
:struct (struct ;(map qq (kvs x)))
x))
(tuple (in t 0) (qq (in t 1))))

View File

@ -113,6 +113,7 @@ typedef struct JanetTask JanetTask;
struct JanetTask {
JanetFiber *fiber;
Janet value;
JanetSignal sig;
};
/* Min priority queue of timestamps for timeouts. */
@ -121,6 +122,7 @@ typedef struct JanetTimeout JanetTimeout;
struct JanetTimeout {
JanetTimestamp when;
JanetFiber *fiber;
int is_error;
};
/* Forward declaration */
@ -300,8 +302,25 @@ void janet_pollable_deinit(JanetPollable *pollable) {
pollable->state = NULL;
}
/* Cancel any state machines waiting on this fiber. */
void janet_cancel(JanetFiber *fiber) {
/* Register a fiber to resume with value */
void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig) {
if (fiber->flags & JANET_FIBER_FLAG_SCHEDULED) return;
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
fiber->sched_id++;
JanetTask t = { fiber, value, sig };
janet_q_push(&janet_vm_spawn, &t, sizeof(t));
}
void janet_cancel(JanetFiber *fiber, Janet value) {
janet_schedule_signal(fiber, value, JANET_SIGNAL_ERROR);
}
void janet_schedule(JanetFiber *fiber, Janet value) {
janet_schedule_signal(fiber, value, JANET_SIGNAL_OK);
}
void janet_fiber_did_resume(JanetFiber *fiber) {
/* Cancel any pending fibers */
if (fiber->waiting) janet_unlisten(fiber->waiting);
if (fiber->timeout_index >= 0) {
pop_timeout(fiber->timeout_index);
@ -309,15 +328,6 @@ void janet_cancel(JanetFiber *fiber) {
}
}
/* Register a fiber to resume with value */
void janet_schedule(JanetFiber *fiber, Janet value) {
if (fiber->flags & JANET_FIBER_FLAG_SCHEDULED) return;
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
fiber->sched_id++;
JanetTask t = { fiber, value };
janet_q_push(&janet_vm_spawn, &t, sizeof(t));
}
/* Mark all pending tasks */
void janet_ev_mark(void) {
JanetTask *tasks = janet_vm_spawn.data;
@ -342,10 +352,10 @@ void janet_ev_mark(void) {
}
/* Run a top level task */
static void run_one(JanetFiber *fiber, Janet value) {
static void run_one(JanetFiber *fiber, Janet value, JanetSignal sigin) {
fiber->flags &= ~JANET_FIBER_FLAG_SCHEDULED;
Janet res;
JanetSignal sig = janet_continue(fiber, value, &res);
JanetSignal sig = janet_continue_signal(fiber, value, &res, sigin);
if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) {
janet_stacktrace(fiber, res);
}
@ -377,6 +387,7 @@ void janet_addtimeout(double sec) {
JanetTimeout to;
to.when = ts_delta(ts_now(), sec);
to.fiber = fiber;
to.is_error = 1;
add_timeout(to);
}
@ -595,9 +606,9 @@ void janet_loop(void) {
}
/* Run scheduled fibers */
while (janet_vm_spawn.head != janet_vm_spawn.tail) {
JanetTask task = {NULL, janet_wrap_nil()};
JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK};
janet_q_pop(&janet_vm_spawn, &task, sizeof(task));
run_one(task.fiber, task.value);
run_one(task.fiber, task.value, task.sig);
}
/* Poll for events */
if (janet_vm_active_listeners || janet_vm_tq_count) {
@ -707,7 +718,11 @@ void janet_loop1_impl(void) {
/* Timer event */
pop_timeout(0);
/* Cancel waiters for this fiber */
janet_schedule(to.fiber, janet_wrap_nil());
if (to.is_error) {
janet_cancel(to.fiber, janet_cstringv("timeout"));
} else {
janet_schedule(to.fiber, janet_wrap_nil());
}
} else {
/* Normal event */
int mask = events[i].events;
@ -784,6 +799,7 @@ static Janet cfun_ev_sleep(int32_t argc, Janet *argv) {
JanetTimeout to;
to.when = ts_delta(ts_now(), sec);
to.fiber = janet_vm_root_fiber;
to.is_error = 0;
add_timeout(to);
janet_await();
}

View File

@ -25,8 +25,15 @@
#ifndef JANET_FEATURES_H_defined
#define JANET_FEATURES_H_defined
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|| defined(__bsdi__) || defined(__DragonFly__)
/* Use BSD soucre on any BSD systems, include OSX */
# define _BSD_SOURCE
#else
/* Use POSIX feature flags */
# ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200809L
# endif
#endif
#if defined(WIN32) || defined(_WIN32)

View File

@ -46,8 +46,9 @@
#define JANET_FIBER_MASK_USERN(N) (16 << (N))
#define JANET_FIBER_MASK_USER 0x3FF0
#define JANET_FIBER_STATUS_MASK 0x7F0000
#define JANET_FIBER_STATUS_MASK 0x3F0000
#define JANET_FIBER_FLAG_SCHEDULED 0x800000
#define JANET_FIBER_RESUME_SIGNAL 0x400000
#define JANET_FIBER_STATUS_OFFSET 16
#define JANET_FIBER_BREAKPOINT 0x1000000
@ -77,4 +78,8 @@ void janet_fiber_popframe(JanetFiber *fiber);
void janet_env_maybe_detach(JanetFuncEnv *env);
int janet_env_valid(JanetFuncEnv *env);
#ifdef JANET_EV
void janet_fiber_did_resume(JanetFiber *fiber);
#endif
#endif

View File

@ -391,18 +391,16 @@ FILE *janet_dynfile(const char *name, FILE *def) {
return iofile->file;
}
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
int newline, const char *name, FILE *dflt_file) {
static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
FILE *dflt_file, int32_t offset, Janet x) {
FILE *f;
Janet x = janet_dyn(name);
switch (janet_type(x)) {
default:
/* Other values simply do nothing */
return janet_wrap_nil();
janet_panicf("cannot print to %v", x);
case JANET_BUFFER: {
/* Special case buffer */
JanetBuffer *buf = janet_unwrap_buffer(x);
for (int32_t i = 0; i < argc; ++i) {
for (int32_t i = offset; i < argc; ++i) {
janet_to_string_b(buf, argv[i]);
}
if (newline)
@ -411,6 +409,7 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
}
case JANET_NIL:
f = dflt_file;
if (f == NULL) janet_panic("cannot print to nil");
break;
case JANET_ABSTRACT: {
void *abstract = janet_unwrap_abstract(x);
@ -421,7 +420,7 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
break;
}
}
for (int32_t i = 0; i < argc; ++i) {
for (int32_t i = offset; i < argc; ++i) {
int32_t len;
const uint8_t *vstr;
if (janet_checktype(argv[i], JANET_BUFFER)) {
@ -434,7 +433,11 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
}
if (len) {
if (1 != fwrite(vstr, len, 1, f)) {
janet_panicf("could not print %d bytes to (dyn :%s)", len, name);
if (f == dflt_file) {
janet_panicf("cannot print %d bytes", len);
} else {
janet_panicf("cannot print %d bytes to %v", len, x);
}
}
}
}
@ -443,6 +446,13 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
return janet_wrap_nil();
}
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
int newline, const char *name, FILE *dflt_file) {
Janet x = janet_dyn(name);
return cfun_io_print_impl_x(argc, argv, newline, dflt_file, 0, x);
}
static Janet cfun_io_print(int32_t argc, Janet *argv) {
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
}
@ -459,25 +469,33 @@ static Janet cfun_io_eprin(int32_t argc, Janet *argv) {
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
}
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
const char *name, FILE *dflt_file) {
FILE *f;
static Janet cfun_io_xprint(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
const char *fmt = janet_getcstring(argv, 0);
Janet x = janet_dyn(name);
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}
static Janet cfun_io_xprin(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
FILE *dflt_file, int32_t offset, Janet x) {
FILE *f;
const char *fmt = janet_getcstring(argv, offset);
switch (janet_type(x)) {
default:
/* Other values simply do nothing */
return janet_wrap_nil();
janet_panicf("cannot print to %v", x);
case JANET_BUFFER: {
/* Special case buffer */
JanetBuffer *buf = janet_unwrap_buffer(x);
janet_buffer_format(buf, fmt, 0, argc, argv);
janet_buffer_format(buf, fmt, offset, argc, argv);
if (newline) janet_buffer_push_u8(buf, '\n');
return janet_wrap_nil();
}
case JANET_NIL:
f = dflt_file;
if (f == NULL) janet_panic("cannot print to nil");
break;
case JANET_ABSTRACT: {
void *abstract = janet_unwrap_abstract(x);
@ -489,11 +507,11 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
}
}
JanetBuffer *buf = janet_buffer(10);
janet_buffer_format(buf, fmt, 0, argc, argv);
janet_buffer_format(buf, fmt, offset, argc, argv);
if (newline) janet_buffer_push_u8(buf, '\n');
if (buf->count) {
if (1 != fwrite(buf->data, buf->count, 1, f)) {
janet_panicf("could not print %d bytes to file", buf->count, name);
janet_panicf("could not print %d bytes to file", buf->count);
}
}
/* Clear buffer to make things easier for GC */
@ -504,6 +522,14 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
return janet_wrap_nil();
}
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
const char *name, FILE *dflt_file) {
janet_arity(argc, 1, -1);
Janet x = janet_dyn(name);
return cfun_io_printf_impl_x(argc, argv, newline, dflt_file, 0, x);
}
static Janet cfun_io_printf(int32_t argc, Janet *argv) {
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
}
@ -520,6 +546,16 @@ static Janet cfun_io_eprinf(int32_t argc, Janet *argv) {
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
}
static Janet cfun_io_xprintf(int32_t argc, Janet *argv) {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}
static Janet cfun_io_xprinf(int32_t argc, Janet *argv) {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
static void janet_flusher(const char *name, FILE *dflt_file) {
Janet x = janet_dyn(name);
switch (janet_type(x)) {
@ -633,6 +669,29 @@ static const JanetReg io_cfuns[] = {
JDOC("(eprinf fmt & xs)\n\n"
"Like eprintf but with no trailing newline.")
},
{
"xprint", cfun_io_xprint,
JDOC("(xprint to & xs)\n\n"
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
"newline character. The value to print "
"to is the first argument, and is otherwise the same as print. Returns nil.")
},
{
"xprin", cfun_io_xprin,
JDOC("(xprin to & xs)\n\n"
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
"to is the first argument, and is otherwise the same as prin. Returns nil.")
},
{
"xprintf", cfun_io_xprintf,
JDOC("(xprint to fmt & xs)\n\n"
"Like printf but prints to an explicit file or value to. Returns nil.")
},
{
"xprinf", cfun_io_xprinf,
JDOC("(xprin to fmt & xs)\n\n"
"Like prinf but prints to an explicit file or value to. Returns nil.")
},
{
"flush", cfun_io_flush,
JDOC("(flush)\n\n"

View File

@ -139,6 +139,18 @@ static int janet_stream_close(void *p, size_t s) {
return 0;
}
static void nosigpipe(JSock s) {
#ifdef SO_NOSIGPIPE
int enable = 1;
if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) {
JSOCKCLOSE(s);
janet_panic("setsockopt(SO_NOSIGPIPE) failed");
}
#else
(void) s;
#endif
}
static int janet_stream_mark(void *p, size_t s) {
(void) s;
janet_pollable_mark((JanetPollable *) p);
@ -166,8 +178,7 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event)
janet_mark(janet_wrap_buffer(state->buf));
break;
case JANET_ASYNC_EVENT_CLOSE:
/* Read is finished, even if chunk is incomplete */
janet_schedule(s->fiber, janet_wrap_nil());
janet_cancel(s->fiber, janet_cstringv("stream closed"));
return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_READ:
/* Read in bytes */
@ -201,15 +212,23 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event)
/* Resume if done */
if (!state->is_chunk || bytes_left == 0) {
JanetSignal sig = JANET_SIGNAL_OK;
Janet resume_val;
if (state->is_recv_from) {
void *abst = janet_abstract(&AddressAT, socklen);
memcpy(abst, &saddr, socklen);
resume_val = janet_wrap_abstract(abst);
} else {
resume_val = nread > 0 ? janet_wrap_buffer(buffer) : janet_wrap_nil();
if (nread > 0) {
resume_val = janet_wrap_buffer(buffer);
} else {
sig = JANET_SIGNAL_ERROR;
resume_val = (nread == -1)
? janet_cstringv(strerror(JLASTERR))
: janet_cstringv("could not read");
}
}
janet_schedule(s->fiber, resume_val);
janet_schedule_signal(s->fiber, resume_val, sig);
return JANET_ASYNC_STATUS_DONE;
}
}
@ -277,7 +296,7 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
}
break;
case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(s->fiber, janet_wrap_nil());
janet_cancel(s->fiber, janet_cstringv("stream closed"));
return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_WRITE: {
int32_t start, len;
@ -291,9 +310,9 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
bytes = state->src.str;
len = janet_string_length(bytes);
}
JReadInt nwrote = 0;
if (start < len) {
int32_t nbytes = len - start;
JReadInt nwrote;
do {
void *dest_abst = state->dest_abst;
if (dest_abst) {
@ -311,7 +330,13 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
}
state->start = start;
if (start >= len) {
janet_schedule(s->fiber, janet_wrap_nil());
if (nwrote > 0) {
janet_schedule(s->fiber, janet_wrap_nil());
} else if (nwrote == 0) {
janet_cancel(s->fiber, janet_cstringv("could not write"));
} else {
janet_cancel(s->fiber, janet_cstringv(strerror(JLASTERR)));
}
return JANET_ASYNC_STATUS_DONE;
}
break;
@ -370,6 +395,7 @@ JanetAsyncStatus net_machine_simple_server(JanetListenerState *s, JanetAsyncEven
JSock connfd = accept(s->pollable->handle, NULL, NULL);
if (JSOCKVALID(connfd)) {
/* Made a new connection socket */
nosigpipe(connfd);
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
Janet streamv = janet_wrap_abstract(stream);
JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
@ -392,11 +418,12 @@ JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event
default:
break;
case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(s->fiber, janet_wrap_nil());
janet_cancel(s->fiber, janet_cstringv("stream closed"));
return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_READ: {
JSock connfd = accept(s->pollable->handle, NULL, NULL);
if (JSOCKVALID(connfd)) {
nosigpipe(connfd);
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
Janet streamv = janet_wrap_abstract(stream);
janet_schedule(s->fiber, streamv);
@ -551,6 +578,8 @@ static Janet cfun_net_connect(int32_t argc, Janet *argv) {
janet_panic("could not connect to socket");
}
nosigpipe(sock);
/* Wrap socket in abstract type JanetStream */
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
return janet_wrap_abstract(stream);
@ -562,11 +591,6 @@ static const char *serverify_socket(JSock sfd) {
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
return "setsockopt(SO_REUSEADDR) failed";
}
#ifdef SO_NOSIGPIPE
if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) {
return "setsockopt(SO_NOSIGPIPE) failed";
}
#endif
#ifdef SO_REUSEPORT
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
return "setsockopt(SO_REUSEPORT) failed";
@ -620,6 +644,8 @@ static Janet cfun_net_server(int32_t argc, Janet *argv) {
}
}
nosigpipe(sfd);
if (socktype == SOCK_DGRAM) {
/* Datagram server (UDP) */
@ -807,7 +833,7 @@ static const JanetReg net_cfuns[] = {
"Read up to n bytes from a stream, suspending the current fiber until the bytes are available. "
"If less than n bytes are available (and more than 0), will push those bytes and return early. "
"Takes an optional timeout in seconds, after which will return nil. "
"Returns a buffer with up to n more bytes in it.")
"Returns a buffer with up to n more bytes in it, or raises an error if the read failed.")
},
{
"net/chunk", cfun_stream_chunk,
@ -820,7 +846,7 @@ static const JanetReg net_cfuns[] = {
JDOC("(net/write stream data &opt timeout)\n\n"
"Write data to a stream, suspending the current fiber until the write "
"completes. Takes an optional timeout in seconds, after which will return nil. "
"Returns stream.")
"Returns nil, or raises an error if the write failed.")
},
{
"net/send-to", cfun_stream_send_to,

View File

@ -564,6 +564,15 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
register Janet *stack;
register uint32_t *pc;
register JanetFunction *func;
if (fiber->flags & JANET_FIBER_RESUME_SIGNAL) {
JanetSignal sig = (fiber->gc.flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
fiber->gc.flags &= ~JANET_FIBER_STATUS_MASK;
fiber->flags &= ~(JANET_FIBER_RESUME_SIGNAL | JANET_FIBER_FLAG_MASK);
janet_vm_return_reg[0] = in;
return sig;
}
vm_restore();
if (fiber->flags & JANET_FIBER_DID_LONGJUMP) {
@ -801,6 +810,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_pcnext();
VM_OP(JOP_NEXT)
vm_commit();
stack[A] = janet_next(stack[B], stack[C]);
vm_pcnext();
@ -1287,7 +1297,7 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
JanetFiberStatus old_status = janet_fiber_status(fiber);
#ifdef JANET_EV
janet_cancel(fiber);
janet_fiber_did_resume(fiber);
#endif
/* Continue child fiber if it exists */
@ -1370,6 +1380,20 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
return janet_continue_no_check(fiber, in, out);
}
/* Enter the main vm loop but immediately raise a signal */
JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig) {
JanetSignal tmp_signal = janet_check_can_resume(fiber, out);
if (tmp_signal) return tmp_signal;
if (sig != JANET_SIGNAL_OK) {
JanetFiber *child = fiber;
while (child->child) child = child->child;
child->gc.flags &= ~JANET_FIBER_STATUS_MASK;
child->gc.flags |= sig << JANET_FIBER_STATUS_OFFSET;
child->flags |= JANET_FIBER_RESUME_SIGNAL;
}
return janet_continue_no_check(fiber, in, out);
}
JanetSignal janet_pcall(
JanetFunction *fun,
int32_t argc,

View File

@ -1217,6 +1217,8 @@ JANET_API void janet_pollable_deinit(JanetPollable *pollable);
/* Queue a fiber to run on the event loop */
JANET_API void janet_schedule(JanetFiber *fiber, Janet value);
JANET_API void janet_cancel(JanetFiber *fiber, Janet value);
JANET_API void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig);
/* Start a state machine listening for events from a pollable */
JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size);
@ -1224,10 +1226,6 @@ JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListene
/* Shorthand for yielding to event loop in C */
JANET_NO_RETURN JANET_API void janet_await(void);
/* Cancel a waiting fiber. Will notify the canceled state machines, but will not
* unwind the fiber. */
void janet_cancel(JanetFiber *fiber);
/* For use inside listeners - adds a timeout to the current fiber, such that
* it will be resumed after sec seconds if no other event schedules the current fiber. */
void janet_addtimeout(double sec);
@ -1500,6 +1498,7 @@ JANET_API int janet_symeq(Janet x, const char *cstring);
JANET_API int janet_init(void);
JANET_API void janet_deinit(void);
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig);
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
JANET_API JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out);
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);

View File

@ -34,4 +34,14 @@
(assert (= nil (index-of 10 @[])) "index-of 10")
(assert (= nil (index-of 10 @[1 2 3])) "index-of 11")
# Regression
(assert (= {:x 10} (|(let [x $] ~{:x ,x}) 10)) "issue 463")
# macex testing
(assert (deep= (macex1 '~{1 2 3 4}) '~{1 2 3 4}) "macex1 qq struct")
(assert (deep= (macex1 '~@{1 2 3 4}) '~@{1 2 3 4}) "macex1 qq table")
(assert (deep= (macex1 '~(1 2 3 4)) '~[1 2 3 4]) "macex1 qq tuple")
(assert (= :brackets (tuple/type (1 (macex1 '~[1 2 3 4])))) "macex1 qq bracket tuple")
(assert (deep= (macex1 '~@[1 2 3 4 ,blah]) '~@[1 2 3 4 ,blah]) "macex1 qq array")
(end-suite)