1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-05 03:22:54 +00:00

Merge branch 'master' into ev

This commit is contained in:
Calvin Rose 2020-09-26 11:50:13 -05:00
commit 959a577b5f
9 changed files with 168 additions and 92 deletions

9
.gitattributes vendored
View File

@ -1 +1,10 @@
*.janet linguist-language=Clojure *.janet linguist-language=Clojure
*.janet text eol=lf
*.c text eol=lf
*.h text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.build text eol=lf
*.txt text eol=lf
*.sh text eol=lf

View File

@ -1,7 +1,9 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## Unreleased - ??? ## 1.12.2 - 2020-09-20
- Add janet\_try and janet\_restore to C API.
- Fix `os/execute` regression on windows.
- Add :pipe option to `os/spawn`. - Add :pipe option to `os/spawn`.
- Fix docstring typos. - Fix docstring typos.

16
jpm.1
View File

@ -74,6 +74,7 @@ $JANET_LIBPATH, or a reasonable default. See JANET_LIBPATH for more.
Sets the C compiler used for compiling native modules and standalone executables. Defaults Sets the C compiler used for compiling native modules and standalone executables. Defaults
to cc. to cc.
.TP
.BR \-\-cpp\-compiler=$CXX .BR \-\-cpp\-compiler=$CXX
Sets the C++ compiler used for compiling native modules and standalone executables. Defaults Sets the C++ compiler used for compiling native modules and standalone executables. Defaults
to c++.. to c++..
@ -105,7 +106,6 @@ be created in the ./build/ directory.
.TP .TP
.BR install\ [\fBrepo...\fR] .BR install\ [\fBrepo...\fR]
When run with no arguments, installs all installable artifacts in the current project to When run with no arguments, installs all installable artifacts in the current project to
the current JANET_MODPATH for modules and JANET_BINPATH for executables and scripts. Can also the current JANET_MODPATH for modules and JANET_BINPATH for executables and scripts. Can also
take an optional git repository URL and will install all artifacts in that repository instead. take an optional git repository URL and will install all artifacts in that repository instead.
@ -115,7 +115,7 @@ install multiple dependencies in one command.
.TP .TP
.BR uninstall\ [\fBname...\fR] .BR uninstall\ [\fBname...\fR]
Uninstall a project installed with install. uninstall expects the name of the project, not the Uninstall a project installed with install. uninstall expects the name of the project, not the
repository url, path to installed file or executable name. The name of the project must be specified repository url, path to installed file, or executable name. The name of the project must be specified
at the top of the project.janet file in the declare-project form. If no name is given, uninstalls at the top of the project.janet file in the declare-project form. If no name is given, uninstalls
the current project if installed. Will also uninstall multiple packages in one command. the current project if installed. Will also uninstall multiple packages in one command.
@ -148,7 +148,7 @@ required.
List all installed packages in the current syspath. List all installed packages in the current syspath.
.TP .TP
.BR list-pkgs [\fBsearch\fR] .BR list-pkgs\ [\fBsearch\fR]
List all package aliases in the current package listing that contain the given search string. List all package aliases in the current package listing that contain the given search string.
If no search string is given, prints the entire listing. If no search string is given, prints the entire listing.
@ -172,7 +172,7 @@ like make. run will run a single rule or build a single file.
List all rules that can be run via run. This is useful for exploring rules in the project. List all rules that can be run via run. This is useful for exploring rules in the project.
.TP .TP
.BR rule-tree\ [\fBroot\fR] [\fdepth\fR] .BR rule-tree\ [\fBroot\fR]\ [\fBdepth\fR]
Show rule dependency tree in a pretty format. Optionally provide a rule to use as the tree Show rule dependency tree in a pretty format. Optionally provide a rule to use as the tree
root, as well as a max depth to print. By default, prints the full tree for all rules. This root, as well as a max depth to print. By default, prints the full tree for all rules. This
can be quite long, so it is recommended to give a root rule. can be quite long, so it is recommended to give a root rule.
@ -186,7 +186,7 @@ Show all of the paths used when installing and building artifacts.
Update the package listing by installing the 'pkgs' package. Same as jpm install pkgs Update the package listing by installing the 'pkgs' package. Same as jpm install pkgs
.TP .TP
.BR quickbin [\fBentry\fR] [\fBexecutable\fR] .BR quickbin\ [\fBentry\fR]\ [\fBexecutable\fR]
Create a standalone, statically linked executable from a Janet source file that contains a main function. Create a standalone, statically linked executable from a Janet source file that contains a main function.
The main function is the entry point of the program and will receive command line arguments The main function is the entry point of the program and will receive command line arguments
as function arguments. The entry file can import other modules, including native C modules, and as function arguments. The entry file can import other modules, including native C modules, and
@ -222,7 +222,7 @@ the default location set at compile time, which can be determined with (dyn :sys
.RS .RS
The location that jpm will use to install libraries to. Defaults to JANET_PATH, but you could The location that jpm will use to install libraries to. Defaults to JANET_PATH, but you could
set this to a different directory if you want to. Doing so would let you import Janet modules set this to a different directory if you want to. Doing so would let you import Janet modules
on the normal system path (JANET_PATH or (dyn :syspath)), but install to a different directory. It is also a more reliable way to install on the normal system path (JANET_PATH or (dyn :syspath)), but install to a different directory. It is also a more reliable way to install.
This variable is overwritten by the --modpath=/some/path if it is provided. This variable is overwritten by the --modpath=/some/path if it is provided.
.RE .RE
@ -238,7 +238,7 @@ variable.
.B JANET_LIBPATH .B JANET_LIBPATH
.RS .RS
Similar to JANET_HEADERPATH, this path is where jpm will look for Similar to JANET_HEADERPATH, this path is where jpm will look for
libjanet.a for creating standalong executables. This does not need to be libjanet.a for creating standalone executables. This does not need to be
set on a normal install. set on a normal install.
If not provided, this will default to <jpm script location>/../lib. If not provided, this will default to <jpm script location>/../lib.
The --libpath=/some/path option will override this variable. The --libpath=/some/path option will override this variable.
@ -257,11 +257,13 @@ The --binpath=/some/path will override this variable.
The git repository URL that contains a listing of packages. This allows installing packages with shortnames, which The git repository URL that contains a listing of packages. This allows installing packages with shortnames, which
is mostly a convenience. However, package dependencies can use short names, package listings is mostly a convenience. However, package dependencies can use short names, package listings
can be used to choose a particular set of dependency versions for a whole project. can be used to choose a particular set of dependency versions for a whole project.
.RE
.B JANET_GIT .B JANET_GIT
.RS .RS
An optional path to a git executable to use to clone git dependencies. By default, uses "git" on the current $PATH. You shouldn't need to set this An optional path to a git executable to use to clone git dependencies. By default, uses "git" on the current $PATH. You shouldn't need to set this
if you have a normal install of git. if you have a normal install of git.
.RE
.SH AUTHOR .SH AUTHOR
Written by Calvin Rose <calsrose@gmail.com> Written by Calvin Rose <calsrose@gmail.com>

View File

@ -1702,7 +1702,7 @@
(print (doc-format (string "Bindings:\n\n" (string/join bindings " ")))) (print (doc-format (string "Bindings:\n\n" (string/join bindings " "))))
(print) (print)
(print (doc-format (string "Dynamics:\n\n" (string/join dynamics " ")))) (print (doc-format (string "Dynamics:\n\n" (string/join dynamics " "))))
(print)) (print "\n Use (doc sym) for more information on a binding.\n"))
(defn doc* (defn doc*
"Get the documentation for a symbol in a given environment. Function form of doc." "Get the documentation for a symbol in a given environment. Function form of doc."
@ -2868,7 +2868,7 @@
(when (and (not *compile-only*) (or *should-repl* *no-file*)) (when (and (not *compile-only*) (or *should-repl* *no-file*))
(if-not *quiet* (if-not *quiet*
(print "Janet " janet/version "-" janet/build " " (os/which) "/" (os/arch))) (print "Janet " janet/version "-" janet/build " " (os/which) "/" (os/arch) " - '(doc)' for help"))
(flush) (flush)
(defn getprompt [p] (defn getprompt [p]
(def [line] (parser/where p)) (def [line] (parser/where p))

View File

@ -28,9 +28,9 @@
#define JANET_VERSION_MAJOR 1 #define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 12 #define JANET_VERSION_MINOR 12
#define JANET_VERSION_PATCH 1 #define JANET_VERSION_PATCH 2
#define JANET_VERSION_EXTRA "" #define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.12.1" #define JANET_VERSION "1.12.2"
/* #define JANET_BUILD "local" */ /* #define JANET_BUILD "local" */

View File

@ -221,7 +221,8 @@ static char **os_execute_env(int32_t argc, const Janet *argv) {
return envp; return envp;
} }
/* Free memory from os_execute */ /* Free memory from os_execute. Not actually needed, but doesn't pressure the GC
in the happy path. */
static void os_execute_cleanup(char **envp, const char **child_argv) { static void os_execute_cleanup(char **envp, const char **child_argv) {
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
(void) child_argv; (void) child_argv;
@ -414,33 +415,66 @@ static Janet os_proc_kill(int32_t argc, Janet *argv) {
} }
} }
/* Create piped file for os/execute and os/spawn. */ static void swap_handles(JanetHandle *handles) {
static JanetFile *make_pipes(JanetHandle *handle, int reverse) { JanetHandle temp = handles[0];
handles[0] = handles[1];
handles[1] = temp;
}
static void close_handle(JanetHandle handle) {
#ifdef JANET_WINDOWS
CloseHandle(handle);
#else
close(handle);
#endif
}
/* Create piped file for os/execute and os/spawn. Need to be careful that we mark
the error flag if we can't create pipe and don't leak handles. *handle will be cleaned
up by the calling function. If everything goes well, *handle is owned by the calling function,
(if it is set) and the returned JanetFile owns the other end of the pipe, which will be closed
on GC or fclose. */
static JanetFile *make_pipes(JanetHandle *handle, int reverse, int *errflag) {
JanetHandle handles[2]; JanetHandle handles[2];
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
if (!CreatePipe(handles, handles + 1, NULL, 0)) janet_panic("failed to create pipe"); SECURITY_ATTRIBUTES saAttr;
if (reverse) { memset(&saAttr, 0, sizeof(saAttr));
JanetHandle temp = handles[0]; saAttr.nLength = sizeof(saAttr);
handles[0] = handles[1]; saAttr.bInheritHandle = TRUE;
handles[1] = temp; if (!CreatePipe(handles, handles + 1, &saAttr, 0)) goto error_pipe;
} if (reverse) swap_handles(handles);
/* Don't inherit the side of the pipe owned by this process */
if (!SetHandleInformation(handles[0], HANDLE_FLAG_INHERIT, 0)) goto error_set_handle_info;
*handle = handles[1]; *handle = handles[1];
int fd = _open_osfhandle((intptr_t) handles[0], reverse ? _O_WRONLY : _O_RDONLY); int fd = _open_osfhandle((intptr_t) handles[0], reverse ? _O_WRONLY : _O_RDONLY);
if (fd == -1) janet_panic("could not create file for piping"); if (fd == -1) goto error_open_osfhandle;
FILE *f = _fdopen(fd, reverse ? "w" : "r"); FILE *f = _fdopen(fd, reverse ? "w" : "r");
if (NULL == f) janet_panic(strerror(errno)); if (NULL == f) goto error_fdopen;
return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ); return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ);
error_fdopen:
_close(fd); /* we need to close the fake file descriptor instead of the handle, as ownership has been transfered. */
*errflag = 1;
return NULL;
error_set_handle_info:
error_open_osfhandle:
close_handle(handles[0]);
/* fallthrough */
error_pipe:
*errflag = 1;
return NULL;
#else #else
if (pipe(handles)) janet_panic(strerror(errno)); if (pipe(handles)) goto error_pipe;
if (reverse) { if (reverse) swap_handles(handles);
JanetHandle temp = handles[0];
handles[0] = handles[1];
handles[1] = temp;
}
*handle = handles[1]; *handle = handles[1];
FILE *f = fdopen(handles[0], reverse ? "w" : "r"); FILE *f = fdopen(handles[0], reverse ? "w" : "r");
if (NULL == f) janet_panic(strerror(errno)); if (NULL == f) goto error_fdopen;
return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ); return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ);
error_fdopen:
close_handle(handles[0]);
/* fallthrough */
error_pipe:
*errflag = 1;
return NULL;
#endif #endif
} }
@ -490,6 +524,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
} }
/* Get environment */ /* Get environment */
int use_environ = !janet_flag_at(flags, 0);
char **envp = os_execute_env(argc, argv); char **envp = os_execute_env(argc, argv);
/* Get arguments */ /* Get arguments */
@ -501,6 +536,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
/* Optional stdio redirections */ /* Optional stdio redirections */
JanetFile *new_in = NULL, *new_out = NULL, *new_err = NULL; JanetFile *new_in = NULL, *new_out = NULL, *new_err = NULL;
JanetHandle pipe_in = JANET_HANDLE_NONE, pipe_out = JANET_HANDLE_NONE, pipe_err = JANET_HANDLE_NONE; JanetHandle pipe_in = JANET_HANDLE_NONE, pipe_out = JANET_HANDLE_NONE, pipe_err = JANET_HANDLE_NONE;
int pipe_errflag = 0; /* Track errors setting up pipes */
/* Get optional redirections */ /* Get optional redirections */
if (argc > 2) { if (argc > 2) {
@ -509,34 +545,46 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out")); Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
Janet maybe_stderr = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("err")); Janet maybe_stderr = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("err"));
if (janet_keyeq(maybe_stdin, "pipe")) { if (janet_keyeq(maybe_stdin, "pipe")) {
new_in = make_pipes(&pipe_in, 1); new_in = make_pipes(&pipe_in, 1, &pipe_errflag);
} else if (!janet_checktype(maybe_stdin, JANET_NIL)) { } else if (!janet_checktype(maybe_stdin, JANET_NIL)) {
new_in = janet_getjfile(&maybe_stdin, 0); new_in = janet_getjfile(&maybe_stdin, 0);
} }
if (janet_keyeq(maybe_stdout, "pipe")) { if (janet_keyeq(maybe_stdout, "pipe")) {
new_out = make_pipes(&pipe_out, 0); new_out = make_pipes(&pipe_out, 0, &pipe_errflag);
} else if (!janet_checktype(maybe_stdout, JANET_NIL)) { } else if (!janet_checktype(maybe_stdout, JANET_NIL)) {
new_out = janet_getjfile(&maybe_stdout, 0); new_out = janet_getjfile(&maybe_stdout, 0);
} }
if (janet_keyeq(maybe_stderr, "err")) { if (janet_keyeq(maybe_stderr, "err")) {
new_err = make_pipes(&pipe_err, 0); new_err = make_pipes(&pipe_err, 0, &pipe_errflag);
} else if (!janet_checktype(maybe_stderr, JANET_NIL)) { } else if (!janet_checktype(maybe_stderr, JANET_NIL)) {
new_err = janet_getjfile(&maybe_stderr, 0); new_err = janet_getjfile(&maybe_stderr, 0);
} }
} }
/* Clean up if any of the pipes have any issues */
if (pipe_errflag) {
if (pipe_in != JANET_HANDLE_NONE) close_handle(pipe_in);
if (pipe_out != JANET_HANDLE_NONE) close_handle(pipe_out);
if (pipe_err != JANET_HANDLE_NONE) close_handle(pipe_err);
janet_panic("failed to create pipes");
}
/* Result */ /* Result */
int status = 0; int status = 0;
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
HANDLE pHandle, tHandle; HANDLE pHandle, tHandle;
SECURITY_ATTRIBUTES saAttr;
PROCESS_INFORMATION processInfo; PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo; STARTUPINFO startupInfo;
memset(&saAttr, 0, sizeof(saAttr));
memset(&processInfo, 0, sizeof(processInfo)); memset(&processInfo, 0, sizeof(processInfo));
memset(&startupInfo, 0, sizeof(startupInfo)); memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo); startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags |= STARTF_USESTDHANDLES; startupInfo.dwFlags |= STARTF_USESTDHANDLES;
saAttr.nLength = sizeof(saAttr);
saAttr.bInheritHandle = TRUE;
JanetBuffer *buf = os_exec_escape(exargs); JanetBuffer *buf = os_exec_escape(exargs);
if (buf->count > 8191) { if (buf->count > 8191) {
@ -550,47 +598,58 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
startupInfo.hStdInput = pipe_in; startupInfo.hStdInput = pipe_in;
} else if (new_in != NULL) { } else if (new_in != NULL) {
startupInfo.hStdInput = (HANDLE) _get_osfhandle(_fileno(new_in->file)); startupInfo.hStdInput = (HANDLE) _get_osfhandle(_fileno(new_in->file));
} else {
startupInfo.hStdInput = (HANDLE) _get_osfhandle(0);
} }
if (pipe_out != JANET_HANDLE_NONE) { if (pipe_out != JANET_HANDLE_NONE) {
startupInfo.hStdInput = pipe_out; startupInfo.hStdOutput = pipe_out;
} else if (new_out != NULL) { } else if (new_out != NULL) {
startupInfo.hStdOutput = (HANDLE) _get_osfhandle(_fileno(new_out->file)); startupInfo.hStdOutput = (HANDLE) _get_osfhandle(_fileno(new_out->file));
} else {
startupInfo.hStdOutput = (HANDLE) _get_osfhandle(1);
} }
if (pipe_err != JANET_HANDLE_NONE) { if (pipe_err != JANET_HANDLE_NONE) {
startupInfo.hStdInput = pipe_err; startupInfo.hStdError = pipe_err;
} else if (new_err != NULL) { } else if (new_err != NULL) {
startupInfo.hStdError = (HANDLE) _get_osfhandle(_fileno(new_err->file)); startupInfo.hStdError = (HANDLE) _get_osfhandle(_fileno(new_err->file));
} else {
startupInfo.hStdError = (HANDLE) _get_osfhandle(2);
} }
/* Use _spawn family of functions. */ /* Use _spawn family of functions. */
/* Windows docs say do this before any spawns. */ /* Windows docs say do this before any spawns. */
_flushall(); _flushall();
/* TODO - redirection, :p flag */ int cp_failed = 0;
if (!CreateProcess(janet_flag_at(flags, 1) ? NULL : path, /* NULL? */ if (!CreateProcess(janet_flag_at(flags, 1) ? NULL : path,
(char *) buf->data, /* Single CLI argument */ (char *) buf->data, /* Single CLI argument */
NULL, /* no proc inheritance */ &saAttr, /* no proc inheritance */
NULL, /* no thread inheritance */ &saAttr, /* no thread inheritance */
TRUE, /* handle inheritance */ TRUE, /* handle inheritance */
0, /* flags */ 0, /* flags */
envp, /* pass in environment */ use_environ ? NULL : envp, /* pass in environment */
NULL, /* use parents starting directory */ NULL, /* use parents starting directory */
&startupInfo, &startupInfo,
&processInfo)) { &processInfo)) {
janet_panic("failed to create process"); cp_failed = 1;
} }
if (pipe_in != JANET_HANDLE_NONE) CloseHandle(pipe_in); if (pipe_in != JANET_HANDLE_NONE) CloseHandle(pipe_in);
if (pipe_out != JANET_HANDLE_NONE) CloseHandle(pipe_out); if (pipe_out != JANET_HANDLE_NONE) CloseHandle(pipe_out);
if (pipe_err != JANET_HANDLE_NONE) CloseHandle(pipe_err); if (pipe_err != JANET_HANDLE_NONE) CloseHandle(pipe_err);
os_execute_cleanup(envp, NULL);
if (cp_failed) {
janet_panic("failed to create process");
}
pHandle = processInfo.hProcess; pHandle = processInfo.hProcess;
tHandle = processInfo.hThread; tHandle = processInfo.hThread;
os_execute_cleanup(envp, NULL);
/* Wait and cleanup immedaitely */ /* Wait and cleanup immedaitely */
if (!is_async) { if (!is_async) {
DWORD code; DWORD code;
@ -612,8 +671,6 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
/* Use posix_spawn to spawn new process */ /* Use posix_spawn to spawn new process */
int use_environ = !janet_flag_at(flags, 0);
if (use_environ) { if (use_environ) {
janet_lock_environ(); janet_lock_environ();
} }

View File

@ -1315,8 +1315,25 @@ static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
return JANET_SIGNAL_OK; return JANET_SIGNAL_OK;
} }
void janet_try_init(JanetTryState *state) {
state->stackn = janet_vm_stackn++;
state->gc_handle = janet_vm_gc_suspend;
state->vm_fiber = janet_vm_fiber;
state->vm_jmp_buf = janet_vm_jmp_buf;
state->vm_return_reg = janet_vm_return_reg;
janet_vm_return_reg = &(state->payload);
janet_vm_jmp_buf = &(state->buf);
}
void janet_restore(JanetTryState *state) {
janet_vm_stackn = state->stackn;
janet_vm_gc_suspend = state->gc_handle;
janet_vm_fiber = state->vm_fiber;
janet_vm_jmp_buf = state->vm_jmp_buf;
janet_vm_return_reg = state->vm_return_reg;
}
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out) { static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out) {
jmp_buf buf;
JanetFiberStatus old_status = janet_fiber_status(fiber); JanetFiberStatus old_status = janet_fiber_status(fiber);
@ -1353,45 +1370,23 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
} }
/* Save global state */ /* Save global state */
int32_t oldn = janet_vm_stackn++; JanetTryState tstate;
int handle = janet_vm_gc_suspend; JanetSignal signal = janet_try(&tstate);
JanetFiber *old_vm_fiber = janet_vm_fiber; if (!signal) {
jmp_buf *old_vm_jmp_buf = janet_vm_jmp_buf; /* Normal setup */
Janet *old_vm_return_reg = janet_vm_return_reg;
/* Setup fiber */
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber; if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
janet_vm_fiber = fiber; janet_vm_fiber = fiber;
janet_gcroot(janet_wrap_fiber(fiber)); janet_gcroot(janet_wrap_fiber(fiber));
janet_fiber_set_status(fiber, JANET_STATUS_ALIVE); janet_fiber_set_status(fiber, JANET_STATUS_ALIVE);
janet_vm_return_reg = out;
janet_vm_jmp_buf = &buf;
/* Run loop */
JanetSignal signal;
int jmpsig;
#if defined(JANET_BSD) || defined(JANET_APPLE)
jmpsig = _setjmp(buf);
#else
jmpsig = setjmp(buf);
#endif
if (jmpsig) {
signal = (JanetSignal) jmpsig;
} else {
signal = run_vm(fiber, in); signal = run_vm(fiber, in);
} }
/* Tear down fiber */ /* Restore */
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
janet_fiber_set_status(fiber, signal); janet_fiber_set_status(fiber, signal);
janet_gcunroot(janet_wrap_fiber(fiber)); janet_gcunroot(janet_wrap_fiber(fiber));
janet_restore(&tstate);
/* Restore global state */ *out = tstate.payload;
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
janet_vm_gc_suspend = handle;
janet_vm_fiber = old_vm_fiber;
janet_vm_stackn = oldn;
janet_vm_return_reg = old_vm_return_reg;
janet_vm_jmp_buf = old_vm_jmp_buf;
return signal; return signal;
} }

View File

@ -1095,6 +1095,19 @@ struct JanetFile {
int32_t flags; int32_t flags;
}; };
/* For janet_try and janet_restore */
typedef struct {
/* old state */
int32_t stackn;
int gc_handle;
JanetFiber *vm_fiber;
jmp_buf *vm_jmp_buf;
Janet *vm_return_reg;
/* new state */
jmp_buf buf;
Janet payload;
} JanetTryState;
/* Thread types */ /* Thread types */
#ifdef JANET_THREADS #ifdef JANET_THREADS
typedef struct JanetThread JanetThread; typedef struct JanetThread JanetThread;
@ -1498,6 +1511,13 @@ JANET_API JanetBuffer *janet_pretty(JanetBuffer *buffer, int depth, int flags, J
#define JANET_HASH_KEY_SIZE 16 #define JANET_HASH_KEY_SIZE 16
JANET_API void janet_init_hash_key(uint8_t key[JANET_HASH_KEY_SIZE]); JANET_API void janet_init_hash_key(uint8_t key[JANET_HASH_KEY_SIZE]);
#endif #endif
JANET_API void janet_try_init(JanetTryState *state);
#if defined(JANET_BSD) || defined(JANET_APPLE)
#define janet_try(state) (janet_try_init(state), (JanetSignal) _setjmp((state)->buf))
#else
#define janet_try(state) (janet_try_init(state), (JanetSignal) setjmp((state)->buf))
#endif
JANET_API void janet_restore(JanetTryState *state);
JANET_API int janet_equals(Janet x, Janet y); JANET_API int janet_equals(Janet x, Janet y);
JANET_API int32_t janet_hash(Janet x); JANET_API int32_t janet_hash(Janet x);
JANET_API int janet_compare(Janet x, Janet y); JANET_API int janet_compare(Janet x, Janet y);

View File

@ -3,7 +3,6 @@
(var num-tests-passed 0) (var num-tests-passed 0)
(var num-tests-run 0) (var num-tests-run 0)
(var suite-num 0) (var suite-num 0)
(var numchecks 0)
(var start-time 0) (var start-time 0)
(defn assert (defn assert
@ -13,16 +12,8 @@
(++ num-tests-run) (++ num-tests-run)
(when x (++ num-tests-passed)) (when x (++ num-tests-passed))
(if x (if x
(do (xprintf stdout "\e[32m✔\e[0m %s: %v" (string e) x)
(when (= numchecks 25) (xprintf stdout "\n\e[31m✘\e[0m %s: %v" (string e) x))
(set numchecks 0)
(print))
(++ numchecks)
(file/write stdout "\e[32m✔\e[0m"))
(do
(file/write stdout "\n\e[31m✘\e[0m ")
(set numchecks 0)
(print e)))
x) x)
(defmacro assert-error (defmacro assert-error