From 7b42ed66f242d2edcfa3f9948514a8b976f17c50 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 9 Aug 2020 09:30:58 -0500 Subject: [PATCH 1/9] Add xprint, xprin, xprintf, and xprinf. --- src/core/io.c | 95 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/src/core/io.c b/src/core/io.c index d192f9b6..d6db1476 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -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" From 9121feb44fc3c9d925563acaa9aaed5f4237af67 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 9 Aug 2020 11:39:40 -0500 Subject: [PATCH 2/9] Update changelog.` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca4e49fa..1bed45d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. ## Unreleased - ??? - Update meson build script to fix bug on Debian's version of meson +- Add `xprint`, `xprin`, `xprintf`, and `xprinf`. ## 1.11.3 - 2020-08-03 - Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled. From c903e49a4f6ad08e061edd958e7a51197cd28849 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 10 Aug 2020 10:38:54 -0500 Subject: [PATCH 3/9] Change feature flags for BSD. --- src/core/features.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/core/features.h b/src/core/features.h index ef9a0aea..3ceaa0ad 100644 --- a/src/core/features.h +++ b/src/core/features.h @@ -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) From 6f2f3fdb6830c9f09f5442e027eb7768c3595b5a Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 10 Aug 2020 11:01:57 -0500 Subject: [PATCH 4/9] Return an error message if writes fail. Address #462. --- CHANGELOG.md | 2 ++ src/core/net.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bed45d0..ad3b16c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ## Unreleased - ??? - Update meson build script to fix bug on Debian's version of meson - Add `xprint`, `xprin`, `xprintf`, and `xprinf`. +- `net/write` now returns 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. diff --git a/src/core/net.c b/src/core/net.c index 29a49883..f20dfff0 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -350,6 +350,12 @@ static size_t janet_loop_event(size_t index) { if (nwrote > 0) { start += nwrote; } else { + if (nwrote == -1) { + const uint8_t *msg = janet_formatc("write error: %s", strerror(JLASTERR)); + resumeval = janet_wrap_string(msg); + } else { + resumeval = janet_cstringv("could not write"); + } start = len; } } @@ -637,7 +643,7 @@ static const JanetReg net_cfuns[] = { JDOC("(net/read stream nbytes &opt buf)\n\n" "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. " - "Returns a buffer with up to n more bytes in it.") + "Returns a buffer with up to n more bytes in it, or nil if the read failed.") }, { "net/chunk", cfun_stream_chunk, @@ -648,7 +654,7 @@ static const JanetReg net_cfuns[] = { "net/write", cfun_stream_write, JDOC("(net/write stream data)\n\n" "Write data to a stream, suspending the current fiber until the write " - "completes. Returns stream.") + "completes. Returns nil, or an error message if the write failed.") }, { "net/close", cfun_stream_close, From ca75f8dc201f444c4bce7953e4e6d06e8442e7fd Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 10 Aug 2020 18:45:44 -0500 Subject: [PATCH 5/9] Address #463 - prevent sigpipe on client connections. We erroneously did not set SO_NOSIGPIPE on connections aquired with net/connect, only those quired thorugh net/server. This meant that failed writes by a client could send sigpipe. --- src/core/net.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/net.c b/src/core/net.c index f20dfff0..fc4a0914 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -497,6 +497,18 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset) { * C Funs */ +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 Janet cfun_net_connect(int32_t argc, Janet *argv) { janet_fixarity(argc, 2); @@ -517,6 +529,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); @@ -542,12 +556,7 @@ static Janet cfun_net_server(int32_t argc, Janet *argv) { JSOCKCLOSE(sfd); janet_panic("setsockopt(SO_REUSEADDR) failed"); } -#ifdef SO_NOSIGPIPE - if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) { - JSOCKCLOSE(sfd); - janet_panic("setsockopt(SO_NOSIGPIPE) failed"); - } -#endif + nosigpipe(sfd); #ifdef SO_REUSEPORT if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) { JSOCKCLOSE(sfd); From 9b36e2b1455e776a0355ca42ceb2b9b902fd8dce Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 10 Aug 2020 18:59:53 -0500 Subject: [PATCH 6/9] Be aggressive with setting SO_NOSIGPIPE on BSD/Apple. --- src/core/net.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/core/net.c b/src/core/net.c index fc4a0914..eccac2cd 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -139,6 +139,19 @@ 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 +} + /* * Event loop */ @@ -308,6 +321,7 @@ static size_t janet_loop_event(size_t index) { JSock connfd = accept(fd, 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); JanetFunction *handler = jlfd->data.read_accept.handler; @@ -497,18 +511,6 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset) { * C Funs */ -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 Janet cfun_net_connect(int32_t argc, Janet *argv) { janet_fixarity(argc, 2); From 06c268c274972692611a5ae27881adf5cb447ec3 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Tue, 11 Aug 2020 07:19:34 -0500 Subject: [PATCH 7/9] Start working on throwing errors from async functions. --- CHANGELOG.md | 5 ++++- src/core/fiber.h | 3 ++- src/core/net.c | 24 +++++++++++++++++++----- src/core/vm.c | 23 +++++++++++++++++++++++ src/include/janet.h | 1 + 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad3b16c9..4b4fb4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,12 @@ All notable changes to this project will be documented in this file. ## Unreleased - ??? +- 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 returns an error message if write fails. +- `net/write` now raises an error message if write fails. - Fix issue with SIGPIPE on macOS and BSDs. ## 1.11.3 - 2020-08-03 diff --git a/src/core/fiber.h b/src/core/fiber.h index e99fa718..82427795 100644 --- a/src/core/fiber.h +++ b/src/core/fiber.h @@ -46,7 +46,8 @@ #define JANET_FIBER_MASK_USERN(N) (16 << (N)) #define JANET_FIBER_MASK_USER 0x3FF0 -#define JANET_FIBER_STATUS_MASK 0xFF0000 +#define JANET_FIBER_RESUME_SIGNAL 0x800000 +#define JANET_FIBER_STATUS_MASK 0x7F0000 #define JANET_FIBER_STATUS_OFFSET 16 #define JANET_FIBER_BREAKPOINT 0x1000000 diff --git a/src/core/net.c b/src/core/net.c index eccac2cd..06cd25eb 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -275,8 +275,11 @@ static size_t janet_loop_event(size_t index) { int ret = 1; int should_resume = 0; Janet resumeval = janet_wrap_nil(); + JanetSignal resumesignal = JANET_SIGNAL_OK; if (stream->flags & JANET_STREAM_CLOSED) { should_resume = 1; + resumeval = janet_cstringv("stream is closed"); + resumesignal = JANET_SIGNAL_ERROR; ret = 0; } else { switch (jlfd->event_type) { @@ -288,6 +291,8 @@ static size_t janet_loop_event(size_t index) { if (!(stream->flags & JANET_STREAM_READABLE)) { should_resume = 1; ret = 0; + resumesignal = JANET_SIGNAL_ERROR; + resumeval = janet_cstringv("stream not readable"); break; } JReadInt nread; @@ -309,6 +314,13 @@ static size_t janet_loop_event(size_t index) { should_resume = 1; if (nread > 0) { resumeval = janet_wrap_buffer(buffer); + } else { + if (nread == 0) { + resumeval = janet_cstringv("could not read from stream"); + } else { + resumeval = janet_cstringv(strerror(JLASTERR)); + } + resumesignal = JANET_SIGNAL_ERROR; } ret = 0; } else { @@ -342,6 +354,8 @@ static size_t janet_loop_event(size_t index) { const uint8_t *bytes; if (!(stream->flags & JANET_STREAM_WRITABLE)) { should_resume = 1; + resumesignal = JANET_SIGNAL_ERROR; + resumeval = janet_cstringv("stream not writeable"); ret = 0; break; } @@ -364,9 +378,9 @@ static size_t janet_loop_event(size_t index) { if (nwrote > 0) { start += nwrote; } else { + resumesignal = JANET_SIGNAL_ERROR; if (nwrote == -1) { - const uint8_t *msg = janet_formatc("write error: %s", strerror(JLASTERR)); - resumeval = janet_wrap_string(msg); + resumeval = janet_cstringv(strerror(JLASTERR)); } else { resumeval = janet_cstringv("could not write"); } @@ -396,7 +410,7 @@ static size_t janet_loop_event(size_t index) { if (NULL != jlfd->fiber && should_resume) { /* Resume the fiber */ Janet out; - JanetSignal sig = janet_continue(jlfd->fiber, resumeval, &out); + JanetSignal sig = janet_continue_signal(jlfd->fiber, resumeval, &out, resumesignal); if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) { janet_stacktrace(jlfd->fiber, out); } @@ -654,7 +668,7 @@ static const JanetReg net_cfuns[] = { JDOC("(net/read stream nbytes &opt buf)\n\n" "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. " - "Returns a buffer with up to n more bytes in it, or nil if the read failed.") + "Returns a buffer with up to n more bytes in it, or raises an error if the read failed.") }, { "net/chunk", cfun_stream_chunk, @@ -665,7 +679,7 @@ static const JanetReg net_cfuns[] = { "net/write", cfun_stream_write, JDOC("(net/write stream data)\n\n" "Write data to a stream, suspending the current fiber until the write " - "completes. Returns nil, or an error message if the write failed.") + "completes. Returns nil, or raises an error if the write failed.") }, { "net/close", cfun_stream_close, diff --git a/src/core/vm.c b/src/core/vm.c index a48f2434..3acea522 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -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) { @@ -1366,6 +1375,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, diff --git a/src/include/janet.h b/src/include/janet.h index ff6b26e0..946cfb16 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1412,6 +1412,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); From 7e7498350fdd03563c6aaf34fa5f559fe4b24d71 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 12 Aug 2020 06:09:06 -0500 Subject: [PATCH 8/9] Fix #463 Fix outdated code in macex1, such as checking for unquote-splicing, which no longer exists. Also fix macex1 for quasiquoted tables and structs. macex1 is not the macro expander used by the compiler, so these bugs only affected code which called macex manually, such as the short-fn macro. --- src/boot/boot.janet | 16 +++++++++------- test/suite0010.janet | 10 ++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 4d989f1d..931dcebb 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -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)))) diff --git a/test/suite0010.janet b/test/suite0010.janet index dafb912a..0b51aa31 100644 --- a/test/suite0010.janet +++ b/test/suite0010.janet @@ -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) From 58374623b711b403c6df6545c07331771cdbf086 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 13 Aug 2020 22:28:50 -0500 Subject: [PATCH 9/9] Add a vm_commit before JOP_NEXT. --- src/core/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/vm.c b/src/core/vm.c index 3acea522..4e5c6b06 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -810,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();