700 changes: 379 additions & 321 deletions src/boot/boot.janet

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/conf/janetconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
#define JANETCONF_H

#define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 21
#define JANET_VERSION_PATCH 1
#define JANET_VERSION_MINOR 22
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.21.1"
#define JANET_VERSION "1.22.0"

/* #define JANET_BUILD "local" */

Expand Down
6 changes: 3 additions & 3 deletions src/core/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Janet janet_array_peek(JanetArray *array) {
JANET_CORE_FN(cfun_array_new,
"(array/new capacity)",
"Creates a new empty array with a pre-allocated capacity. The same as "
"(array) but can be more efficient if the maximum size of an array is known.") {
"`(array)` but can be more efficient if the maximum size of an array is known.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array(cap);
Expand All @@ -136,7 +136,7 @@ JANET_CORE_FN(cfun_array_new_filled,
"(array/new-filled count &opt value)",
"Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
int32_t count = janet_getnat(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
JanetArray *array = janet_array(count);
for (int32_t i = 0; i < count; i++) {
Expand Down Expand Up @@ -194,7 +194,7 @@ JANET_CORE_FN(cfun_array_push,
JANET_CORE_FN(cfun_array_ensure,
"(array/ensure arr capacity growth)",
"Ensures that the memory backing the array is large enough for `capacity` "
"items at the given rate of growth. Capacity and growth must be integers. "
"items at the given rate of growth. `capacity` and `growth` must be integers. "
"If the backing capacity is already enough, then this function does nothing. "
"Otherwise, the backing memory will be reallocated so that there is enough space.") {
janet_fixarity(argc, 3);
Expand Down
19 changes: 10 additions & 9 deletions src/core/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {

JANET_CORE_FN(cfun_buffer_new,
"(buffer/new capacity)",
"Creates a new, empty buffer with enough backing memory for capacity bytes. "
"Creates a new, empty buffer with enough backing memory for `capacity` bytes. "
"Returns a new buffer of length 0.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
Expand All @@ -174,16 +174,17 @@ JANET_CORE_FN(cfun_buffer_new,

JANET_CORE_FN(cfun_buffer_new_filled,
"(buffer/new-filled count &opt byte)",
"Creates a new buffer of length count filled with byte. By default, byte is 0. "
"Creates a new buffer of length `count` filled with `byte`. By default, `byte` is 0. "
"Returns the new buffer.") {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
if (count < 0) count = 0;
int32_t byte = 0;
if (argc == 2) {
byte = janet_getinteger(argv, 1) & 0xFF;
}
JanetBuffer *buffer = janet_buffer(count);
if (buffer->data)
if (buffer->data && count > 0)
memset(buffer->data, byte, count);
buffer->count = count;
return janet_wrap_buffer(buffer);
Expand Down Expand Up @@ -312,7 +313,7 @@ JANET_CORE_FN(cfun_buffer_clear,

JANET_CORE_FN(cfun_buffer_popn,
"(buffer/popn buffer n)",
"Removes the last n bytes from the buffer. Returns the modified buffer.") {
"Removes the last `n` bytes from the buffer. Returns the modified buffer.") {
janet_fixarity(argc, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t n = janet_getinteger(argv, 1);
Expand All @@ -327,9 +328,9 @@ JANET_CORE_FN(cfun_buffer_popn,

JANET_CORE_FN(cfun_buffer_slice,
"(buffer/slice bytes &opt start end)",
"Takes a slice of a byte sequence from start to end. The range is half open, "
"Takes a slice of a byte sequence from `start` to `end`. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the buffer. "
"end of the array. By default, `start` is 0 and `end` is the length of the buffer. "
"Returns a new buffer.") {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
Expand Down Expand Up @@ -399,9 +400,9 @@ JANET_CORE_FN(cfun_buffer_bittoggle,

JANET_CORE_FN(cfun_buffer_blit,
"(buffer/blit dest src &opt dest-start src-start src-end)",
"Insert the contents of src into dest. Can optionally take indices that "
"indicate which part of src to copy into which part of dest. Indices can be "
"negative to index from the end of src or dest. Returns dest.") {
"Insert the contents of `src` into `dest`. Can optionally take indices that "
"indicate which part of `src` to copy into which part of `dest`. Indices can be "
"negative in order to index from the end of `src` or `dest`. Returns `dest`.") {
janet_arity(argc, 2, 5);
JanetBuffer *dest = janet_getbuffer(argv, 0);
JanetByteView src = janet_getbytes(argv, 1);
Expand Down
101 changes: 21 additions & 80 deletions src/core/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,42 +112,6 @@ static void *makef(FILE *f, int32_t flags) {
return iof;
}

/* Open a process */
#ifndef JANET_NO_PROCESSES
JANET_CORE_FN(cfun_io_popen,
"(file/popen command &opt mode) (DEPRECATED for os/spawn)",
"Open a file that is backed by a process. The file must be opened in either "
"the :r (read) or the :w (write) mode. In :r mode, the stdout of the "
"process can be read from the file. In :w mode, the stdin of the process "
"can be written to. Returns the new file.") {
janet_arity(argc, 1, 2);
const uint8_t *fname = janet_getstring(argv, 0);
const uint8_t *fmode = NULL;
int32_t flags;
if (argc == 2) {
fmode = janet_getkeyword(argv, 1);
flags = JANET_FILE_PIPED | checkflags(fmode);
if (flags & (JANET_FILE_UPDATE | JANET_FILE_BINARY | JANET_FILE_APPEND)) {
janet_panicf("invalid popen file mode :%S, expected :r or :w", fmode);
}
fmode = (const uint8_t *)((fmode[0] == 'r') ? "r" : "w");
} else {
fmode = (const uint8_t *)"r";
flags = JANET_FILE_PIPED | JANET_FILE_READ;
}
#ifdef JANET_WINDOWS
#define popen _popen
#endif
FILE *f = popen((const char *)fname, (const char *)fmode);
if (!f) {
if (flags & JANET_FILE_NONIL)
janet_panicf("failed to popen %s: %s", fname, strerror(errno));
return janet_wrap_nil();
}
return janet_makefile(f, flags);
}
#endif

JANET_CORE_FN(cfun_io_temp,
"(file/temp)",
"Open an anonymous temporary file that is removed on close. "
Expand Down Expand Up @@ -296,22 +260,14 @@ JANET_CORE_FN(cfun_io_fflush,
}

#ifdef JANET_WINDOWS
#define pclose _pclose
#define WEXITSTATUS(x) x
#endif

/* For closing files from C API */
int janet_file_close(JanetFile *file) {
int ret = 0;
if (!(file->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
#ifndef JANET_NO_PROCESSES
if (file->flags & JANET_FILE_PIPED) {
ret = pclose(file->file);
} else
#endif
{
ret = fclose(file->file);
}
ret = fclose(file->file);
file->flags |= JANET_FILE_CLOSED;
return ret;
}
Expand All @@ -331,30 +287,18 @@ JANET_CORE_FN(cfun_io_fclose,
"(file/close f)",
"Close a file and release all related resources. When you are "
"done reading a file, close it to prevent a resource leak and let "
"other processes read the file. If the file is the result of a file/popen "
"call, close waits for and returns the process exit status.") {
"other processes read the file.") {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
return janet_wrap_nil();
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
janet_panic("file not closable");
if (iof->flags & JANET_FILE_PIPED) {
#ifndef JANET_NO_PROCESSES
int status = pclose(iof->file);
iof->flags |= JANET_FILE_CLOSED;
if (status == -1) janet_panic("could not close file");
return janet_wrap_integer(WEXITSTATUS(status));
#else
return janet_wrap_nil();
#endif
} else {
if (fclose(iof->file)) {
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
janet_panic("could not close file");
}
iof->flags |= JANET_FILE_CLOSED;
if (fclose(iof->file)) {
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
janet_panic("could not close file");
}
iof->flags |= JANET_FILE_CLOSED;
return janet_wrap_nil();
}

Expand Down Expand Up @@ -546,43 +490,43 @@ JANET_CORE_FN(cfun_io_print,
"(print & xs)",
"Print values to the console (standard out). Value are converted "
"to strings if they are not already. After printing all values, a "
"newline character is printed. Use the value of (dyn :out stdout) to determine "
"what to push characters to. Expects (dyn :out stdout) to be either a core/file or "
"newline character is printed. Use the value of `(dyn :out stdout)` to determine "
"what to push characters to. Expects `(dyn :out stdout)` to be either a core/file or "
"a buffer. Returns nil.") {
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
}

JANET_CORE_FN(cfun_io_prin,
"(prin & xs)",
"Same as print, but does not add trailing newline.") {
"Same as `print`, but does not add trailing newline.") {
return cfun_io_print_impl(argc, argv, 0, "out", stdout);
}

JANET_CORE_FN(cfun_io_eprint,
"(eprint & xs)",
"Same as print, but uses (dyn :err stderr) instead of (dyn :out stdout).") {
"Same as `print`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
return cfun_io_print_impl(argc, argv, 1, "err", stderr);
}

JANET_CORE_FN(cfun_io_eprin,
"(eprin & xs)",
"Same as prin, but uses (dyn :err stderr) instead of (dyn :out stdout).") {
"Same as `prin`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
}

JANET_CORE_FN(cfun_io_xprint,
"(xprint to & xs)",
"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.") {
"to is the first argument, and is otherwise the same as `print`. Returns nil.") {
janet_arity(argc, 1, -1);
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}

JANET_CORE_FN(cfun_io_xprin,
"(xprin to & xs)",
"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.") {
"to is the first argument, and is otherwise the same as `prin`. Returns nil.") {
janet_arity(argc, 1, -1);
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
Expand Down Expand Up @@ -640,38 +584,38 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,

JANET_CORE_FN(cfun_io_printf,
"(printf fmt & xs)",
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :out stdout) with a trailing newline.") {
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :out stdout)` with a trailing newline.") {
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
}

JANET_CORE_FN(cfun_io_prinf,
"(prinf fmt & xs)",
"Like printf but with no trailing newline.") {
"Like `printf` but with no trailing newline.") {
return cfun_io_printf_impl(argc, argv, 0, "out", stdout);
}

JANET_CORE_FN(cfun_io_eprintf,
"(eprintf fmt & xs)",
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :err stderr) with a trailing newline.") {
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :err stderr)` with a trailing newline.") {
return cfun_io_printf_impl(argc, argv, 1, "err", stderr);
}

JANET_CORE_FN(cfun_io_eprinf,
"(eprinf fmt & xs)",
"Like eprintf but with no trailing newline.") {
"Like `eprintf` but with no trailing newline.") {
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
}

JANET_CORE_FN(cfun_io_xprintf,
"(xprintf to fmt & xs)",
"Like printf but prints to an explicit file or value to. Returns nil.") {
"Like `printf` but prints to an explicit file or value `to`. Returns nil.") {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}

JANET_CORE_FN(cfun_io_xprinf,
"(xprinf to fmt & xs)",
"Like prinf but prints to an explicit file or value to. Returns nil.") {
"Like `prinf` but prints to an explicit file or value `to`. Returns nil.") {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
Expand All @@ -696,7 +640,7 @@ static void janet_flusher(const char *name, FILE *dflt_file) {

JANET_CORE_FN(cfun_io_flush,
"(flush)",
"Flush (dyn :out stdout) if it is a file, otherwise do nothing.") {
"Flush `(dyn :out stdout)` if it is a file, otherwise do nothing.") {
janet_fixarity(argc, 0);
(void) argv;
janet_flusher("out", stdout);
Expand All @@ -705,7 +649,7 @@ JANET_CORE_FN(cfun_io_flush,

JANET_CORE_FN(cfun_io_eflush,
"(eflush)",
"Flush (dyn :err stderr) if it is a file, otherwise do nothing.") {
"Flush `(dyn :err stderr)` if it is a file, otherwise do nothing.") {
janet_fixarity(argc, 0);
(void) argv;
janet_flusher("err", stderr);
Expand Down Expand Up @@ -802,9 +746,6 @@ void janet_lib_io(JanetTable *env) {
JANET_CORE_REG("file/write", cfun_io_fwrite),
JANET_CORE_REG("file/flush", cfun_io_fflush),
JANET_CORE_REG("file/seek", cfun_io_fseek),
#ifndef JANET_NO_PROCESSES
JANET_CORE_REG("file/popen", cfun_io_popen),
#endif
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, io_cfuns);
Expand Down
6 changes: 3 additions & 3 deletions src/core/math.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ static Janet janet_rng_next(void *p, Janet key) {
/* Get a random number */
JANET_CORE_FN(janet_rand,
"(math/random)",
"Returns a uniformly distributed random number between 0 and 1") {
"Returns a uniformly distributed random number between 0 and 1.") {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_number(janet_rng_double(&janet_vm.rng));
Expand All @@ -240,7 +240,7 @@ JANET_CORE_FN(janet_rand,
/* Seed the random number generator */
JANET_CORE_FN(janet_srand,
"(math/seedrandom seed)",
"Set the seed for the random number generator. seed should be "
"Set the seed for the random number generator. `seed` should be "
"an integer or a buffer."
) {
janet_fixarity(argc, 1);
Expand All @@ -261,7 +261,7 @@ JANET_CORE_FN(janet_##name, "(math/" #name " x)", doc) {\
return janet_wrap_number(fop(x)); \
}

JANET_DEFINE_MATHOP(acos, acos, "Returns the arccosize of x.")
JANET_DEFINE_MATHOP(acos, acos, "Returns the arccosine of x.")
JANET_DEFINE_MATHOP(asin, asin, "Returns the arcsin of x.")
JANET_DEFINE_MATHOP(atan, atan, "Returns the arctangent of x.")
JANET_DEFINE_MATHOP(cos, cos, "Returns the cosine of x.")
Expand Down
69 changes: 34 additions & 35 deletions src/core/os.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ typedef struct {
static JanetEVGenericMessage janet_proc_wait_subr(JanetEVGenericMessage args) {
JanetProc *proc = (JanetProc *) args.argp;
WaitForSingleObject(proc->pHandle, INFINITE);
GetExitCodeProcess(proc->pHandle, &args.argi);
GetExitCodeProcess(proc->pHandle, &args.tag);
return args;
}

Expand Down Expand Up @@ -550,8 +550,8 @@ JANET_CORE_FN(os_proc_wait,
JANET_CORE_FN(os_proc_kill,
"(os/proc-kill proc &opt wait)",
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
"handle on windows. If wait is truthy, will wait for the process to finish and "
"returns the exit code. Otherwise, returns proc.") {
"handle on windows. If `wait` is truthy, will wait for the process to finish and "
"returns the exit code. Otherwise, returns `proc`.") {
janet_arity(argc, 1, 2);
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
if (proc->flags & JANET_PROC_WAITED) {
Expand Down Expand Up @@ -836,19 +836,19 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
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"));
if (janet_keyeq(maybe_stdin, "pipe")) {
if (is_spawn && janet_keyeq(maybe_stdin, "pipe")) {
new_in = make_pipes(&pipe_in, 1, &pipe_errflag);
pipe_owner_flags |= JANET_PROC_OWNS_STDIN;
} else if (!janet_checktype(maybe_stdin, JANET_NIL)) {
new_in = janet_getjstream(&maybe_stdin, 0, &orig_in);
}
if (janet_keyeq(maybe_stdout, "pipe")) {
if (is_spawn && janet_keyeq(maybe_stdout, "pipe")) {
new_out = make_pipes(&pipe_out, 0, &pipe_errflag);
pipe_owner_flags |= JANET_PROC_OWNS_STDOUT;
} else if (!janet_checktype(maybe_stdout, JANET_NIL)) {
new_out = janet_getjstream(&maybe_stdout, 0, &orig_out);
}
if (janet_keyeq(maybe_stderr, "pipe")) {
if (is_spawn && janet_keyeq(maybe_stderr, "pipe")) {
new_err = make_pipes(&pipe_err, 0, &pipe_errflag);
pipe_owner_flags |= JANET_PROC_OWNS_STDERR;
} else if (!janet_checktype(maybe_stderr, JANET_NIL)) {
Expand Down Expand Up @@ -1063,21 +1063,20 @@ JANET_CORE_FN(os_execute,
"`env` is a table or struct mapping environment variables to values. It can also "
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
"These arguments should be core/file values. "
"One can also pass in the :pipe keyword "
"for these arguments to create files that will read (for :err and :out) or write (for :in) "
"to the file descriptor of the subprocess. This is only useful in `os/spawn`, which takes "
"the same parameters as `os/execute`, but will return an object that contains references to these "
"files via (return-value :in), (return-value :out), and (return-value :err). "
"Returns the exit status of the program.") {
return os_execute_impl(argc, argv, 0);
}

JANET_CORE_FN(os_spawn,
"(os/spawn args &opt flags env)",
"Execute a program on the system and return a handle to the process. Otherwise, the "
"same arguments as os/execute. Does not wait for the process. "
"The returned value has the fields :in, :out, :err, :return-code and "
"the additional field :pid on unix like platforms.") {
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
"same arguments as `os/execute`. Does not wait for the process. "
"For each of the :in, :out, and :err keys to the `env` argument, one "
"can also pass in the keyword `:pipe`"
"to get streams for standard IO of the subprocess that can be read from and written to."
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
"subprocess or `(os/proc-kill proc)`.") {
return os_execute_impl(argc, argv, 1);
}

Expand Down Expand Up @@ -1117,7 +1116,7 @@ JANET_CORE_FN(os_shell,

JANET_CORE_FN(os_environ,
"(os/environ)",
"Get a copy of the os environment table.") {
"Get a copy of the OS environment table.") {
(void) argv;
janet_fixarity(argc, 0);
int32_t nenv = 0;
Expand Down Expand Up @@ -1198,7 +1197,7 @@ JANET_CORE_FN(os_time,
JANET_CORE_FN(os_clock,
"(os/clock)",
"Return the number of whole + fractional seconds since some fixed point in time. The clock "
"is guaranteed to be non decreasing in real time.") {
"is guaranteed to be non-decreasing in real time.") {
janet_fixarity(argc, 0);
(void) argv;
struct timespec tv;
Expand All @@ -1209,7 +1208,7 @@ JANET_CORE_FN(os_clock,

JANET_CORE_FN(os_sleep,
"(os/sleep n)",
"Suspend the program for n seconds. 'nsec' can be a real number. Returns "
"Suspend the program for `n` seconds. `n` can be a real number. Returns "
"nil.") {
janet_fixarity(argc, 1);
double delay = janet_getnumber(argv, 0);
Expand Down Expand Up @@ -1246,7 +1245,7 @@ JANET_CORE_FN(os_cwd,

JANET_CORE_FN(os_cryptorand,
"(os/cryptorand n &opt buf)",
"Get or append n bytes of good quality random data provided by the OS. Returns a new buffer or buf.") {
"Get or append `n` bytes of good quality random data provided by the OS. Returns a new buffer or `buf`.") {
JanetBuffer *buffer;
janet_arity(argc, 1, 2);
int32_t offset;
Expand Down Expand Up @@ -1383,9 +1382,9 @@ static timeint_t entry_getint(Janet env_entry, char *field) {
JANET_CORE_FN(os_mktime,
"(os/mktime date-struct &opt local)",
"Get the broken down date-struct time expressed as the number "
" of seconds since January 1, 1970, the Unix epoch. "
"of seconds since January 1, 1970, the Unix epoch. "
"Returns a real number. "
"Date is given in UTC unless local is truthy, in which case the "
"Date is given in UTC unless `local` is truthy, in which case the "
"date is computed for the local timezone.\n\n"
"Inverse function to os/date.") {
janet_arity(argc, 1, 2);
Expand Down Expand Up @@ -1456,7 +1455,7 @@ JANET_CORE_FN(os_link,

JANET_CORE_FN(os_symlink,
"(os/symlink oldpath newpath)",
"Create a symlink from oldpath to newpath, returning nil. Same as (os/link oldpath newpath true).") {
"Create a symlink from oldpath to newpath, returning nil. Same as `(os/link oldpath newpath true)`.") {
janet_fixarity(argc, 2);
#ifdef JANET_WINDOWS
(void) argc;
Expand Down Expand Up @@ -1831,10 +1830,10 @@ JANET_CORE_FN(os_stat,
"* :uid - File uid\n\n"
"* :gid - File gid\n\n"
"* :nlink - number of links to file\n\n"
"* :rdev - Real device of file. 0 on windows.\n\n"
"* :rdev - Real device of file. 0 on Windows\n\n"
"* :size - size of file in bytes\n\n"
"* :blocks - number of blocks in file. 0 on windows\n\n"
"* :blocksize - size of blocks in file. 0 on windows\n\n"
"* :blocks - number of blocks in file. 0 on Windows\n\n"
"* :blocksize - size of blocks in file. 0 on Windows\n\n"
"* :accessed - timestamp when file last accessed\n\n"
"* :changed - timestamp when file last changed (permissions changed)\n\n"
"* :modified - timestamp when file last modified (content changed)\n") {
Expand All @@ -1849,9 +1848,9 @@ JANET_CORE_FN(os_lstat,

JANET_CORE_FN(os_chmod,
"(os/chmod path mode)",
"Change file permissions, where mode is a permission string as returned by "
"os/perm-string, or an integer as returned by os/perm-int. "
"When mode is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
"Change file permissions, where `mode` is a permission string as returned by "
"`os/perm-string`, or an integer as returned by `os/perm-int`. "
"When `mode` is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
"8r666 or 8r400. Windows will not differentiate between user, group, and other permissions, and thus will combine all of these permissions. Returns nil.") {
janet_fixarity(argc, 2);
const char *path = janet_getcstring(argv, 0);
Expand Down Expand Up @@ -1953,17 +1952,17 @@ JANET_CORE_FN(os_realpath,

JANET_CORE_FN(os_permission_string,
"(os/perm-string int)",
"Convert a Unix octal permission value from a permission integer as returned by os/stat "
"Convert a Unix octal permission value from a permission integer as returned by `os/stat` "
"to a human readable string, that follows the formatting "
"of unix tools like ls. Returns the string as a 9 character string of r, w, x and - characters. Does not "
"of Unix tools like `ls`. Returns the string as a 9-character string of r, w, x and - characters. Does not "
"include the file/directory/symlink character as rendered by `ls`.") {
janet_fixarity(argc, 1);
return os_make_permstring(os_get_unix_mode(argv, 0));
}

JANET_CORE_FN(os_permission_int,
"(os/perm-int bytes)",
"Parse a 9 character permission string and return an integer that can be used by chmod.") {
"Parse a 9-character permission string and return an integer that can be used by chmod.") {
janet_fixarity(argc, 1);
return janet_wrap_integer(os_get_unix_mode(argv, 0));
}
Expand All @@ -1982,19 +1981,19 @@ static jmode_t os_optmode(int32_t argc, const Janet *argv, int32_t n, int32_t df
JANET_CORE_FN(os_open,
"(os/open path &opt flags mode)",
"Create a stream from a file, like the POSIX open system call. Returns a new stream. "
"mode should be a file mode as passed to os/chmod, but only if the create flag is given. "
"`mode` should be a file mode as passed to `os/chmod`, but only if the create flag is given. "
"The default mode is 8r666. "
"Allowed flags are as follows:\n\n"
" * :r - open this file for reading\n"
" * :w - open this file for writing\n"
" * :c - create a new file (O_CREATE)\n"
" * :e - fail if the file exists (O_EXCL)\n"
" * :t - shorten an existing file to length 0 (O_TRUNC)\n\n"
"Posix only flags:\n\n"
"Posix-only flags:\n\n"
" * :a - append to a file (O_APPEND)\n"
" * :x - O_SYNC\n"
" * :C - O_NOCTTY\n\n"
"Windows only flags:\n\n"
"Windows-only flags:\n\n"
" * :R - share reads (FILE_SHARE_READ)\n"
" * :W - share writes (FILE_SHARE_WRITE)\n"
" * :D - share deletes (FILE_SHARE_DELETE)\n"
Expand Down Expand Up @@ -2147,7 +2146,7 @@ JANET_CORE_FN(os_open,

JANET_CORE_FN(os_pipe,
"(os/pipe)",
"Create a readable stream and a writable stream that are connected. Returns a two element "
"Create a readable stream and a writable stream that are connected. Returns a two-element "
"tuple where the first element is a readable stream and the second element is the writable "
"stream.") {
(void) argv;
Expand Down
10 changes: 5 additions & 5 deletions src/core/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ const JanetAbstractType janet_parser_type = {
JANET_CORE_FN(cfun_parse_parser,
"(parser/new)",
"Creates and returns a new parser object. Parsers are state machines "
"that can receive bytes, and generate a stream of values.") {
"that can receive bytes and generate a stream of values.") {
(void) argv;
janet_fixarity(argc, 0);
JanetParser *p = janet_abstract(&janet_parser_type, sizeof(JanetParser));
Expand All @@ -894,7 +894,7 @@ JANET_CORE_FN(cfun_parse_parser,
JANET_CORE_FN(cfun_parse_consume,
"(parser/consume parser bytes &opt index)",
"Input bytes into the parser and parse them. Will not throw errors "
"if there is a parse error. Starts at the byte index given by index. Returns "
"if there is a parse error. Starts at the byte index given by `index`. Returns "
"the number of bytes read.") {
janet_arity(argc, 2, 3);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
Expand Down Expand Up @@ -922,7 +922,7 @@ JANET_CORE_FN(cfun_parse_consume,

JANET_CORE_FN(cfun_parse_eof,
"(parser/eof parser)",
"Indicate that the end of file was reached to the parser. This puts the parser in the :dead state.") {
"Indicate to the parser that the end of file was reached. This puts the parser in the :dead state.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
janet_parser_eof(p);
Expand Down Expand Up @@ -982,7 +982,7 @@ JANET_CORE_FN(cfun_parse_has_more,

JANET_CORE_FN(cfun_parse_byte,
"(parser/byte parser b)",
"Input a single byte into the parser byte stream. Returns the parser.") {
"Input a single byte `b` into the parser byte stream. Returns the parser.") {
janet_fixarity(argc, 2);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
int32_t i = janet_getinteger(argv, 1);
Expand Down Expand Up @@ -1022,7 +1022,7 @@ JANET_CORE_FN(cfun_parse_error,
"If the parser is in the error state, returns the message associated with "
"that error. Otherwise, returns nil. Also flushes the parser state and parser "
"queue, so be sure to handle everything in the queue before calling "
"parser/error.") {
"`parser/error`.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
const char *err = janet_parser_error(p);
Expand Down
1 change: 1 addition & 0 deletions src/core/peg.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ static const uint8_t *peg_rule(
if (rule[0] == RULE_TO) cap_load(s, cs2);
break;
}
cap_load(s, cs2);
text++;
}
up1(s);
Expand Down
9 changes: 7 additions & 2 deletions src/core/specials.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv)
for (i = 1; i < argn - 1; i++) {
Janet attr = argv[i];
switch (janet_type(attr)) {
case JANET_TUPLE:
janetc_cerror(c, "unexpected form - did you intend to use defn?");
break;
default:
janetc_cerror(c, "could not add metadata to binding");
break;
Expand Down Expand Up @@ -390,10 +393,11 @@ static int varleaf(
static JanetSlot janetc_var(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
Janet head;
JanetTable *attr_table = handleattr(c, argn, argv);
JanetSlot ret = dohead(c, opts, &head, argn, argv);
if (c->result.status == JANET_COMPILE_ERROR)
return janetc_cslot(janet_wrap_nil());
destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv));
destructure(c, argv[0], ret, varleaf, attr_table);
return ret;
}

Expand Down Expand Up @@ -439,10 +443,11 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
Janet head;
opts.flags &= ~JANET_FOPTS_HINT;
JanetTable *attr_table = handleattr(c, argn, argv);
JanetSlot ret = dohead(c, opts, &head, argn, argv);
if (c->result.status == JANET_COMPILE_ERROR)
return janetc_cslot(janet_wrap_nil());
destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv));
destructure(c, argv[0], ret, defleaf, attr_table);
return ret;
}

Expand Down
60 changes: 30 additions & 30 deletions src/core/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,34 +173,34 @@ static int32_t kmp_next(struct kmp_state *state) {
JANET_CORE_FN(cfun_string_slice,
"(string/slice bytes &opt start end)",
"Returns a substring from a byte sequence. The substring is from "
"index start inclusive to index end exclusive. All indexing "
"is from 0. 'start' and 'end' can also be negative to indicate indexing "
"index `start` inclusive to index `end`, exclusive. All indexing "
"is from 0. `start` and `end` can also be negative to indicate indexing "
"from the end of the string. Note that index -1 is synonymous with "
"index (length bytes) to allow a full negative slice range. ") {
"index `(length bytes)` to allow a full negative slice range. ") {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
return janet_stringv(view.bytes + range.start, range.end - range.start);
}

JANET_CORE_FN(cfun_symbol_slice,
"(symbol/slice bytes &opt start end)",
"Same a string/slice, but returns a symbol.") {
"Same as string/slice, but returns a symbol.") {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
return janet_symbolv(view.bytes + range.start, range.end - range.start);
}

JANET_CORE_FN(cfun_keyword_slice,
"(keyword/slice bytes &opt start end)",
"Same a string/slice, but returns a keyword.") {
"Same as string/slice, but returns a keyword.") {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
return janet_keywordv(view.bytes + range.start, range.end - range.start);
}

JANET_CORE_FN(cfun_string_repeat,
"(string/repeat bytes n)",
"Returns a string that is n copies of bytes concatenated.") {
"Returns a string that is `n` copies of `bytes` concatenated.") {
janet_fixarity(argc, 2);
JanetByteView view = janet_getbytes(argv, 0);
int32_t rep = janet_getinteger(argv, 1);
Expand Down Expand Up @@ -282,7 +282,7 @@ JANET_CORE_FN(cfun_string_asciiupper,

JANET_CORE_FN(cfun_string_reverse,
"(string/reverse str)",
"Returns a string that is the reversed version of str.") {
"Returns a string that is the reversed version of `str`.") {
janet_fixarity(argc, 1);
JanetByteView view = janet_getbytes(argv, 0);
uint8_t *buf = janet_string_begin(view.len);
Expand All @@ -308,8 +308,8 @@ static void findsetup(int32_t argc, Janet *argv, struct kmp_state *s, int32_t ex

JANET_CORE_FN(cfun_string_find,
"(string/find patt str &opt start-index)",
"Searches for the first instance of pattern patt in string "
"str. Returns the index of the first character in patt if found, "
"Searches for the first instance of pattern `patt` in string "
"`str`. Returns the index of the first character in `patt` if found, "
"otherwise returns nil.") {
int32_t result;
struct kmp_state state;
Expand All @@ -323,7 +323,7 @@ JANET_CORE_FN(cfun_string_find,

JANET_CORE_FN(cfun_string_hasprefix,
"(string/has-prefix? pfx str)",
"Tests whether str starts with pfx.") {
"Tests whether `str` starts with `pfx`.") {
janet_fixarity(argc, 2);
JanetByteView prefix = janet_getbytes(argv, 0);
JanetByteView str = janet_getbytes(argv, 1);
Expand All @@ -334,7 +334,7 @@ JANET_CORE_FN(cfun_string_hasprefix,

JANET_CORE_FN(cfun_string_hassuffix,
"(string/has-suffix? sfx str)",
"Tests whether str ends with sfx.") {
"Tests whether `str` ends with `sfx`.") {
janet_fixarity(argc, 2);
JanetByteView suffix = janet_getbytes(argv, 0);
JanetByteView str = janet_getbytes(argv, 1);
Expand All @@ -347,9 +347,9 @@ JANET_CORE_FN(cfun_string_hassuffix,

JANET_CORE_FN(cfun_string_findall,
"(string/find-all patt str &opt start-index)",
"Searches for all instances of pattern patt in string "
"str. Returns an array of all indices of found patterns. Overlapping "
"instances of the pattern are counted individually, meaning a byte in str "
"Searches for all instances of pattern `patt` in string "
"`str`. Returns an array of all indices of found patterns. Overlapping "
"instances of the pattern are counted individually, meaning a byte in `str` "
"may contribute to multiple found patterns.") {
int32_t result;
struct kmp_state state;
Expand Down Expand Up @@ -386,8 +386,8 @@ static void replacesetup(int32_t argc, Janet *argv, struct replace_state *s) {

JANET_CORE_FN(cfun_string_replace,
"(string/replace patt subst str)",
"Replace the first occurrence of patt with subst in the string str. "
"Will return the new string if patt is found, otherwise returns str.") {
"Replace the first occurrence of `patt` with `subst` in the string `str`. "
"Will return the new string if `patt` is found, otherwise returns `str`.") {
int32_t result;
struct replace_state s;
uint8_t *buf;
Expand All @@ -409,9 +409,9 @@ JANET_CORE_FN(cfun_string_replace,

JANET_CORE_FN(cfun_string_replaceall,
"(string/replace-all patt subst str)",
"Replace all instances of patt with subst in the string str. Overlapping "
"Replace all instances of `patt` with `subst` in the string `str`. Overlapping "
"matches will not be counted, only the first match in such a span will be replaced. "
"Will return the new string if patt is found, otherwise returns str.") {
"Will return the new string if `patt` is found, otherwise returns `str`.") {
int32_t result;
struct replace_state s;
JanetBuffer b;
Expand All @@ -433,11 +433,11 @@ JANET_CORE_FN(cfun_string_replaceall,

JANET_CORE_FN(cfun_string_split,
"(string/split delim str &opt start limit)",
"Splits a string str with delimiter delim and returns an array of "
"substrings. The substrings will not contain the delimiter delim. If delim "
"Splits a string `str` with delimiter `delim` and returns an array of "
"substrings. The substrings will not contain the delimiter `delim`. If `delim` "
"is not found, the returned array will have one element. Will start searching "
"for delim at the index start (if provided), and return up to a maximum "
"of limit results (if provided).") {
"for `delim` at the index `start` (if provided), and return up to a maximum "
"of `limit` results (if provided).") {
int32_t result;
JanetArray *array;
struct kmp_state state;
Expand All @@ -461,9 +461,9 @@ JANET_CORE_FN(cfun_string_split,

JANET_CORE_FN(cfun_string_checkset,
"(string/check-set set str)",
"Checks that the string str only contains bytes that appear in the string set. "
"Returns true if all bytes in str appear in set, false if some bytes in str do "
"not appear in set.") {
"Checks that the string `str` only contains bytes that appear in the string `set`. "
"Returns true if all bytes in `str` appear in `set`, false if some bytes in `str` do "
"not appear in `set`.") {
uint32_t bitset[8] = {0, 0, 0, 0, 0, 0, 0, 0};
janet_fixarity(argc, 2);
JanetByteView set = janet_getbytes(argv, 0);
Expand All @@ -488,7 +488,7 @@ JANET_CORE_FN(cfun_string_checkset,
JANET_CORE_FN(cfun_string_join,
"(string/join parts &opt sep)",
"Joins an array of strings into one string, optionally separated by "
"a separator string sep.") {
"a separator string `sep`.") {
janet_arity(argc, 1, 2);
JanetView parts = janet_getindexed(argv, 0);
JanetByteView joiner;
Expand Down Expand Up @@ -530,7 +530,7 @@ JANET_CORE_FN(cfun_string_join,

JANET_CORE_FN(cfun_string_format,
"(string/format format & values)",
"Similar to snprintf, but specialized for operating with Janet values. Returns "
"Similar to `snprintf`, but specialized for operating with Janet values. Returns "
"a new string.") {
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_buffer(0);
Expand Down Expand Up @@ -574,7 +574,7 @@ static void trim_help_args(int32_t argc, Janet *argv, JanetByteView *str, JanetB
JANET_CORE_FN(cfun_string_trim,
"(string/trim str &opt set)",
"Trim leading and trailing whitespace from a byte sequence. If the argument "
"set is provided, consider only characters in set to be whitespace.") {
"`set` is provided, consider only characters in `set` to be whitespace.") {
JanetByteView str, set;
trim_help_args(argc, argv, &str, &set);
int32_t left_edge = trim_help_leftedge(str, set);
Expand All @@ -587,7 +587,7 @@ JANET_CORE_FN(cfun_string_trim,
JANET_CORE_FN(cfun_string_triml,
"(string/triml str &opt set)",
"Trim leading whitespace from a byte sequence. If the argument "
"set is provided, consider only characters in set to be whitespace.") {
"`set` is provided, consider only characters in `set` to be whitespace.") {
JanetByteView str, set;
trim_help_args(argc, argv, &str, &set);
int32_t left_edge = trim_help_leftedge(str, set);
Expand All @@ -597,7 +597,7 @@ JANET_CORE_FN(cfun_string_triml,
JANET_CORE_FN(cfun_string_trimr,
"(string/trimr str &opt set)",
"Trim trailing whitespace from a byte sequence. If the argument "
"set is provided, consider only characters in set to be whitespace.") {
"`set` is provided, consider only characters in `set` to be whitespace.") {
JanetByteView str, set;
trim_help_args(argc, argv, &str, &set);
int32_t right_edge = trim_help_rightedge(str, set);
Expand Down
14 changes: 7 additions & 7 deletions src/core/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,17 +296,17 @@ JanetTable *janet_table_proto_flatten(JanetTable *t) {
JANET_CORE_FN(cfun_table_new,
"(table/new capacity)",
"Creates a new empty table with pre-allocated memory "
"for capacity entries. This means that if one knows the number of "
"entries going to go in a table on creation, extra memory allocation "
"for `capacity` entries. This means that if one knows the number of "
"entries going into a table on creation, extra memory allocation "
"can be avoided. Returns the new table.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
int32_t cap = janet_getnat(argv, 0);
return janet_wrap_table(janet_table(cap));
}

JANET_CORE_FN(cfun_table_getproto,
"(table/getproto tab)",
"Get the prototype table of a table. Returns nil if a table "
"Get the prototype table of a table. Returns nil if the table "
"has no prototype, otherwise returns the prototype.") {
janet_fixarity(argc, 1);
JanetTable *t = janet_gettable(argv, 0);
Expand All @@ -317,7 +317,7 @@ JANET_CORE_FN(cfun_table_getproto,

JANET_CORE_FN(cfun_table_setproto,
"(table/setproto tab proto)",
"Set the prototype of a table. Returns the original table tab.") {
"Set the prototype of a table. Returns the original table `tab`.") {
janet_fixarity(argc, 2);
JanetTable *table = janet_gettable(argv, 0);
JanetTable *proto = NULL;
Expand All @@ -339,8 +339,8 @@ JANET_CORE_FN(cfun_table_tostruct,

JANET_CORE_FN(cfun_table_rawget,
"(table/rawget tab key)",
"Gets a value from a table without looking at the prototype table. "
"If a table tab does not contain t directly, the function will return "
"Gets a value from a table `tab` without looking at the prototype table. "
"If `tab` does not contain the key directly, the function will return "
"nil without checking the prototype. Returns the value in the table.") {
janet_fixarity(argc, 2);
JanetTable *table = janet_gettable(argv, 0);
Expand Down
12 changes: 6 additions & 6 deletions src/core/tuple.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ JANET_CORE_FN(cfun_tuple_brackets,

JANET_CORE_FN(cfun_tuple_slice,
"(tuple/slice arrtup [,start=0 [,end=(length arrtup)]])",
"Take a sub sequence of an array or tuple from index start "
"inclusive to index end exclusive. If start or end are not provided, "
"they default to 0 and the length of arrtup respectively. "
"'start' and 'end' can also be negative to indicate indexing "
"Take a sub-sequence of an array or tuple from index `start` "
"inclusive to index `end` exclusive. If `start` or `end` are not provided, "
"they default to 0 and the length of `arrtup`, respectively. "
"`start` and `end` can also be negative to indicate indexing "
"from the end of the input. Note that index -1 is synonymous with "
"index '(length arrtup)' to allow a full negative slice range. "
"index `(length arrtup)` to allow a full negative slice range. "
"Returns the new tuple.") {
JanetView view = janet_getindexed(argv, 0);
JanetRange range = janet_getslice(argc, argv);
Expand All @@ -96,7 +96,7 @@ JANET_CORE_FN(cfun_tuple_type,
JANET_CORE_FN(cfun_tuple_sourcemap,
"(tuple/sourcemap tup)",
"Returns the sourcemap metadata attached to a tuple, "
" which is another tuple (line, column).") {
"which is another tuple (line, column).") {
janet_fixarity(argc, 1);
const Janet *tup = janet_gettuple(argv, 0);
Janet contents[2];
Expand Down
1 change: 1 addition & 0 deletions src/core/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ int32_t janet_kv_calchash(const JanetKV *kvs, int32_t len) {
/* Calculate next power of 2. May overflow. If n is 0,
* will return 0. */
int32_t janet_tablen(int32_t n) {
if (n < 0) return 0;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
Expand Down
1 change: 0 additions & 1 deletion src/include/janet.h
Original file line number Diff line number Diff line change
Expand Up @@ -1972,7 +1972,6 @@ extern JANET_API const JanetAbstractType janet_file_type;
#define JANET_FILE_CLOSED 32
#define JANET_FILE_BINARY 64
#define JANET_FILE_SERIALIZABLE 128
#define JANET_FILE_PIPED 256
#define JANET_FILE_NONIL 512

JANET_API Janet janet_makefile(FILE *f, int32_t flags);
Expand Down
30 changes: 30 additions & 0 deletions test/suite0011.janet
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,35 @@

(assert (= (hash 0) (hash (* -1 0))) "hash -0 same as hash 0")

# os/execute regressions
(for i 0 10
(assert (= i (os/execute [(dyn :executable) "-e" (string/format "(os/exit %d)" i)] :p)) (string "os/execute " i)))

# to/thru bug
(def pattern
(peg/compile
'{:dd (sequence :d :d)
:sep (set "/-")
:date (sequence :dd :sep :dd)
:wsep (some (set " \t"))
:entry (group (sequence (capture :date) :wsep (capture :date)))
:main (some (thru :entry))}))

(def alt-pattern
(peg/compile
'{:dd (sequence :d :d)
:sep (set "/-")
:date (sequence :dd :sep :dd)
:wsep (some (set " \t"))
:entry (group (sequence (capture :date) :wsep (capture :date)))
:main (some (choice :entry 1))}))

(def text "1800-10-818-9-818 16/12\n17/12 19/12\n20/12 11/01")
(assert (deep= (peg/match pattern text) (peg/match alt-pattern text)) "to/thru bug #971")

(assert-error
"table rawget regression"
(table/new -1))

(end-suite)

Empty file modified tools/format.sh
100755 → 100644
Empty file.