Merge branch 'master' into better-loopback-determination

This commit is contained in:
Calvin Rose
2026-09-12 11:33:04 -05:00
20 changed files with 473 additions and 230 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.42.1 - ???
## 1.42.1 - 2026-09-10
- More changes to documentation.
- Correct SONAME in Makefile
## 1.42.0 - 2026-08-31
+2
View File
@@ -107,6 +107,8 @@ int main(int argc, const char **argv) {
status = janet_dobytes(env, boot_buffer, (int32_t) boot_size, boot_filename, NULL);
janet_free(boot_buffer);
fprintf(stderr, "total bytecode instructions created: %" PRIi64 "\n", total_instruction_count);
/* Deinitialize vm */
janet_deinit();
+33 -22
View File
@@ -49,10 +49,12 @@
(apply defn name :macro more))
(defmacro as-macro
``Use a function or macro literal `f` as a macro. This lets
any function be used as a macro. Inside a quasiquote, the
idiom `(as-macro ,my-custom-macro arg1 arg2...)` can be used
to avoid unwanted variable capture of `my-custom-macro`.``
``
Use a function or macro literal `f` as a macro. This allows any
function to be used as a macro. Inside a quasiquote, the idiom
`(as-macro ,my-custom-macro arg1 arg2...)` can be used to avoid
unwanted variable capture of `my-custom-macro`.
``
[f & args]
(f ;args))
@@ -137,11 +139,11 @@
(defn dec "Returns x - 1." [x] (- x 1))
(defmacro ++ "Increments the var x by 1." [x] ~(set ,x (,+ ,x ,1)))
(defmacro -- "Decrements the var x by 1." [x] ~(set ,x (,- ,x ,1)))
(defmacro += "Increments the var x by n." [x & ns] ~(set ,x (,+ ,x ,;ns)))
(defmacro -= "Decrements the var x by n." [x & ns] ~(set ,x (,- ,x ,;ns)))
(defmacro *= "Shorthand for (set x (\\* x n))." [x & ns] ~(set ,x (,* ,x ,;ns)))
(defmacro /= "Shorthand for (set x (/ x n))." [x & ns] ~(set ,x (,/ ,x ,;ns)))
(defmacro %= "Shorthand for (set x (% x n))." [x & ns] ~(set ,x (,% ,x ,;ns)))
(defmacro += "Shorthand for (set x (+ x ;ns))." [x & ns] ~(set ,x (,+ ,x ,;ns)))
(defmacro -= "Shorthand for (set x (- x ;ns))." [x & ns] ~(set ,x (,- ,x ,;ns)))
(defmacro *= "Shorthand for (set x (* x ;ns))." [x & ns] ~(set ,x (,* ,x ,;ns)))
(defmacro /= "Shorthand for (set x (/ x ;ns))." [x & ns] ~(set ,x (,/ ,x ,;ns)))
(defmacro %= "Shorthand for (set x (% x ;ns))." [x & ns] ~(set ,x (,% ,x ,;ns)))
(defmacro assert :flycheck # should top level assert flycheck?
"Throw an error if x is not truthy. Will not evaluate `err` if x is truthy."
@@ -177,7 +179,7 @@
"The current lint error level. The error level is the lint level at which compilation will exit with an error and not continue.")
(defdyn *lint-warn*
"The current lint warning level. The warning level is the lint level at which and error will be printed but compilation will continue as normal.")
"The current lint warning level. The warning level is the lint level at which an error will be printed but compilation will continue as normal.")
(defdyn *lint-levels*
"A table of keyword alias to numbers denoting a lint level. Can be used to provided custom aliases for numeric lint levels.")
@@ -1788,8 +1790,14 @@
ret)
(defn zipcoll
`Creates a table from two arrays/tuples.
Returns a new table.`
``
Creates a table from `ks` and `vs` by pairing values at the same
index from each. If `ks` or `vs` has more values than the other, the
extra values are ignored. Returns a new table.
`ks` and `vs` can by bytes, indexed, fibers, or abstract types with
suitable `get` and `next` methods.
``
[ks vs]
(def res @{})
(var kk nil)
@@ -3920,12 +3928,15 @@
(print-index identity)))
(defmacro doc
``Shows documentation for the given symbol, or can show a list of available bindings.
If `sym` is a symbol, will look for documentation for that symbol. If `sym` is a string
or is not provided, will show all lexical and dynamic bindings in the current environment
containing that string (all bindings will be shown if no string is given).``
[&opt sym]
~(,doc* ',sym))
``
Shows documentation for `what` or lists binding names. If `what` is
a symbol, shows documentation for that symbol. If `what` is a
string, shows all lexical and dynamic binding names in the current
environment containing the string. If `what` is not provided, shows
all binding names.
``
[&opt what]
~(,doc* ',what))
(defn doc-of
`Searches all loaded modules in module/cache for a given binding and prints out its documentation.
@@ -4180,7 +4191,7 @@
(defmacro ev/spawn
``
Run some code in a new task fiber. This is shorthand for
`(ev/go (fn [] ;body))`."
`(ev/go (fn [] ;body))`.
``
[& body]
~(,ev/go (fn :spawn [&] ,;body)))
@@ -4322,7 +4333,7 @@
(compwhen (dyn 'ffi/native)
(defdyn *ffi-context* " Current native library for ffi/bind and other settings")
(defdyn *ffi-context* "Current native library for `ffi/defbind` and other settings")
(defn- default-mangle
[name &]
@@ -4344,8 +4355,8 @@
(defmacro ffi/defbind-alias :flycheck
"Generate bindings for native functions in a convenient manner.
Similar to defbind but allows for the janet function name to be
different than the FFI function."
Similar to `ffi/defbind` but allows for the janet function name
to be different than the FFI function."
[name alias ret-type & body]
(def real-ret-type (eval ret-type))
(def meta (slice body 0 -2))
+6
View File
@@ -1,6 +1,12 @@
#ifndef TESTS_H_DNMBUYYL
#define TESTS_H_DNMBUYYL
#include <stdint.h>
#include <inttypes.h>
/* Copy of util.h */
extern int64_t total_instruction_count;
/* Tests */
extern int array_test();
extern int buffer_test();
+46 -34
View File
@@ -135,8 +135,9 @@ 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.") {
"Creates and returns a new empty array with a pre-allocated "
"capacity. The same as `array` but can be more efficient if "
"the maximum size is known.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array(cap);
@@ -145,7 +146,9 @@ JANET_CORE_FN(cfun_array_new,
JANET_CORE_FN(cfun_array_weak,
"(array/weak capacity)",
"Creates a new empty array with a pre-allocated capacity and support for weak references. Similar to `array/new`.") {
"Creates and returns a new empty array with a pre-allocated "
"capacity and support for weak references. Similar to "
"`array/new`.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array_weak(cap);
@@ -153,8 +156,9 @@ JANET_CORE_FN(cfun_array_weak,
}
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.") {
"(array/new-filled n &opt val)",
"Creates and returns a new array of `n` values, all set to "
"`val`, which defaults to nil.") {
janet_arity(argc, 1, 2);
int32_t count = janet_getnat(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
@@ -167,9 +171,10 @@ JANET_CORE_FN(cfun_array_new_filled,
}
JANET_CORE_FN(cfun_array_fill,
"(array/fill arr &opt value)",
"Replace all elements of an array with `value` (defaulting to nil) without changing the length of the array. "
"Returns the modified array.") {
"(array/fill arr &opt val)",
"Replace all values of an array `arr` with `val` "
"(defaulting to nil) without changing the length of `arr`. "
"Returns `arr`.") {
janet_arity(argc, 1, 2);
JanetArray *array = janet_getarray(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
@@ -181,8 +186,8 @@ JANET_CORE_FN(cfun_array_fill,
JANET_CORE_FN(cfun_array_pop,
"(array/pop arr)",
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
"the input array.") {
"Remove and return the last value of an array `arr`. If "
"`arr` is empty, returns nil. Modifies `arr`.") {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
return janet_array_pop(array);
@@ -190,7 +195,8 @@ JANET_CORE_FN(cfun_array_pop,
JANET_CORE_FN(cfun_array_peek,
"(array/peek arr)",
"Returns the last element of the array. Does not modify the array.") {
"Returns the last value of an array `arr`. Does not modify "
"`arr`.") {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
return janet_array_peek(array);
@@ -198,7 +204,8 @@ JANET_CORE_FN(cfun_array_peek,
JANET_CORE_FN(cfun_array_push,
"(array/push arr & xs)",
"Push all the elements of xs to the end of an array. Modifies the input array and returns it.") {
"Push all the values of `xs` to the end of an array `arr`. "
"Returns `arr`.") {
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
if (INT32_MAX - argc + 1 <= array->count) {
@@ -213,10 +220,12 @@ 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. "
"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.") {
"Ensures that the memory backing the array `arr` is large "
"enough for `capacity` items at the given rate `growth`. "
"`capacity` and `growth` must be integers. If the backing "
"capacity is already enough, then there is no change. "
"Otherwise, the backing memory will be reallocated so that "
"there is enough space. Returns `arr`.") {
janet_fixarity(argc, 3);
JanetArray *array = janet_getarray(argv, 0);
int32_t newcount = janet_getinteger(argv, 1);
@@ -244,10 +253,11 @@ JANET_CORE_FN(cfun_array_slice,
JANET_CORE_FN(cfun_array_concat,
"(array/concat arr & parts)",
"Concatenates a variable number of arrays (and tuples) into the first argument, "
"which must be an array. If any of the parts are arrays or tuples, their elements will "
"be inserted into the array. Otherwise, each part in `parts` will be appended to `arr` in order. "
"Return the modified array `arr`.") {
"Concatenates `parts`, a variable number of arrays and "
"tuples, into the first argument `arr` which must be an "
"array. If any of `parts` are arrays or tuples, their values "
"are inserted into `arr`. Otherwise, each value in `parts` "
"will be appended to `arr` in order. Returns `arr`.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
@@ -277,9 +287,9 @@ JANET_CORE_FN(cfun_array_concat,
JANET_CORE_FN(cfun_array_join,
"(array/join arr & parts)",
"Join a variable number of arrays and tuples into the first argument, "
"which must be an array. "
"Return the modified array `arr`.") {
"Join `parts`, a variable number of arrays and tuples, into "
"the first argument `arr` which must be an array. Returns "
"`arr`.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
@@ -302,10 +312,11 @@ JANET_CORE_FN(cfun_array_join,
JANET_CORE_FN(cfun_array_insert,
"(array/insert arr at & xs)",
"Insert all `xs` into array `arr` at index `at`. `at` should be an integer between "
"0 and the length of the array. A negative value for `at` will index backwards from "
"the end of the array, inserting after the index such that inserting at -1 appends to "
"the array. Returns the array.") {
"Insert all `xs` into array `arr` at index `at`. `at` can be "
"an integer between 0 and the length of `arr`. If `at` is "
"negative, will index backwards from the end of `arr`, "
"inserting after the index such that inserting at -1 appends "
"to `arr`. Returns `arr`.") {
size_t chunksize, restsize;
janet_arity(argc, 2, -1);
JanetArray *array = janet_getarray(argv, 0);
@@ -333,10 +344,10 @@ JANET_CORE_FN(cfun_array_insert,
JANET_CORE_FN(cfun_array_remove,
"(array/remove arr at &opt n)",
"Remove up to `n` elements starting at index `at` in array `arr`. `at` can index from "
"the end of the array with a negative index, and `n` must be a non-negative integer. "
"By default, `n` is 1. "
"Returns the array.") {
"Remove up to `n` values starting at index `at` in array "
"`arr`. `at` can index from the end of the array with a "
"negative index, and `n` must be a non-negative integer. "
"By default `n` is 1. Returns `arr`.") {
janet_arity(argc, 2, 3);
JanetArray *array = janet_getarray(argv, 0);
int32_t at = janet_getinteger(argv, 1);
@@ -363,7 +374,8 @@ JANET_CORE_FN(cfun_array_remove,
JANET_CORE_FN(cfun_array_trim,
"(array/trim arr)",
"Set the backing capacity of an array to its current length. Returns the modified array.") {
"Set the backing capacity of an array `arr` to its current "
"length. Returns `arr`.") {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
if (array->count) {
@@ -385,8 +397,8 @@ JANET_CORE_FN(cfun_array_trim,
JANET_CORE_FN(cfun_array_clear,
"(array/clear arr)",
"Empties an array, setting it's count to 0 but does not free the backing capacity. "
"Returns the modified array.") {
"Empties an array `arr`, setting its count to 0 but does not "
"free the backing capacity. Returns `arr`.") {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
array->count = 0;
+5 -5
View File
@@ -368,7 +368,7 @@ static void reverse_u64(uint8_t bytes[8]) {
JANET_CORE_FN(cfun_buffer_push_uint16,
"(buffer/push-uint16 buffer order data)",
"Push a 16 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer."
"Returns the modified buffer. "
"Expands the buffer as necessary. Throws an error if size limit is exceeded.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@@ -388,7 +388,7 @@ JANET_CORE_FN(cfun_buffer_push_uint16,
JANET_CORE_FN(cfun_buffer_push_uint32,
"(buffer/push-uint32 buffer order data)",
"Push a 32 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer."
"Returns the modified buffer. "
"Expands the buffer as necessary. Throws an error if size limit is exceeded.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@@ -405,7 +405,7 @@ JANET_CORE_FN(cfun_buffer_push_uint32,
JANET_CORE_FN(cfun_buffer_push_uint64,
"(buffer/push-uint64 buffer order data)",
"Push a 64 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer."
"Returns the modified buffer. "
"Expands the buffer as necessary. Throws an error if size limit is exceeded.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@@ -422,7 +422,7 @@ JANET_CORE_FN(cfun_buffer_push_uint64,
JANET_CORE_FN(cfun_buffer_push_float32,
"(buffer/push-float32 buffer order data)",
"Push the underlying bytes of a 32 bit float data onto the end of the buffer. "
"Returns the modified buffer."
"Returns the modified buffer. "
"Expands the buffer as necessary. Throws an error if size limit is exceeded.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@@ -439,7 +439,7 @@ JANET_CORE_FN(cfun_buffer_push_float32,
JANET_CORE_FN(cfun_buffer_push_float64,
"(buffer/push-float64 buffer order data)",
"Push the underlying bytes of a 64 bit float data onto the end of the buffer. "
"Returns the modified buffer."
"Returns the modified buffer. "
"Expands the buffer as necessary. Throws an error if size limit is exceeded.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
+161 -8
View File
@@ -26,6 +26,7 @@
#include "gc.h"
#include "util.h"
#include "regalloc.h"
#include "vector.h"
#endif
/* Look up table for instructions */
@@ -109,6 +110,83 @@ const enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_SSS /* JOP_CANCEL, */
};
/* Keep track of how large corelib is. Useful
* for minimizing code bloat. */
#ifdef JANET_BOOTSTRAP
int64_t total_instruction_count = 0;
#endif
/* Traverse bytecode and remove unreachable code my marking it as a noop. */
void janet_bytecode_dead_code(JanetFuncDef *def) {
int32_t *pcstack = NULL;
uint32_t *code = def->bytecode;
int32_t *codes = (int32_t *)code;
int32_t len = def->bytecode_length;
int32_t words = (len + 31) / 32;
uint32_t *visited_bitmap = array_allocate(sizeof(uint32_t), words);
memset(visited_bitmap, 0, words * sizeof(uint32_t));
janet_v_push(pcstack, 0);
while (janet_v_count(pcstack)) {
int32_t pc = janet_v_last(pcstack);
janet_v_pop(pcstack);
while (pc < len) {
int32_t index = pc >> 5;
int32_t mask = 1 << (pc & 0x1F);
if (visited_bitmap[index] & mask) break;
visited_bitmap[index] |= mask;
switch (code[pc] & 0x7F) {
default:
pc++;
continue;
case JOP_RETURN_NIL:
case JOP_RETURN:
case JOP_ERROR:
case JOP_TAILCALL:
pc = len;
continue;
case JOP_JUMP:
janet_v_push(pcstack, pc + (codes[pc] >> 8));
pc = len;
continue;
case JOP_JUMP_IF:
case JOP_JUMP_IF_NIL:
case JOP_JUMP_IF_NOT:
case JOP_JUMP_IF_NOT_NIL:
janet_v_push(pcstack, pc + (codes[pc] >> 16));
pc++;
continue;
}
}
}
for (int32_t pc = 0; pc < len; pc++) {
if (!(visited_bitmap[pc >> 5] & (1 << (pc & 0x1F)))) {
code[pc] = JOP_NOOP;
}
}
janet_free(visited_bitmap);
janet_v_free(pcstack);
}
/* Handle remapping symbols when bytecode changes */
static void rewrite_symbolmap(JanetFuncDef *def, uint32_t *pc_map) {
int32_t smout = 0;
for (int32_t i = 0; i < def->symbolmap_length; i++) {
JanetSymbolMap *sm = def->symbolmap + i;
int keep = 1;
/* Don't rewrite upvalue mappings */
if (sm->birth_pc < UINT32_MAX) {
sm->birth_pc = pc_map[sm->birth_pc];
sm->death_pc = pc_map[sm->death_pc];
/* entirely dead symbols can be removed from the symbol map. This can happen if a symbol is in dead code. */
if (sm->death_pc > (uint32_t) def->bytecode_length) sm->death_pc = (uint32_t) def->bytecode_length;
if (sm->birth_pc >= sm->death_pc) keep = 0;
}
/* Now shift if needed */
if (keep) def->symbolmap[smout++] = *sm;
}
def->symbolmap_length = smout;
}
/* Remove all noops while preserving jumps and debugging information.
* Useful as part of a filtering compiler pass. */
void janet_bytecode_remove_noops(JanetFuncDef *def) {
@@ -166,23 +244,73 @@ void janet_bytecode_remove_noops(JanetFuncDef *def) {
}
/* Rewrite symbolmap */
for (int32_t i = 0; i < def->symbolmap_length; i++) {
JanetSymbolMap *sm = def->symbolmap + i;
/* Don't rewrite upvalue mappings */
if (sm->birth_pc < UINT32_MAX) {
sm->birth_pc = pc_map[sm->birth_pc];
sm->death_pc = pc_map[sm->death_pc];
}
}
rewrite_symbolmap(def, pc_map);
def->bytecode_length = new_bytecode_length;
def->bytecode = janet_realloc(def->bytecode, def->bytecode_length * sizeof(uint32_t));
janet_sfree(pc_map);
}
/* Simple Jump threading. Traverse basic blocks instead?
* jump instructions are always last instruction in basic block. */
void janet_bytecode_jump_threading(JanetFuncDef *def) {
int32_t blen = def->bytecode_length;
uint32_t *code = def->bytecode;
int32_t *codes = (int32_t *)code;
int recur = 1;
while (recur) {
recur = 0;
for (int32_t i = 0; i < blen; i++) {
int32_t target;
int is_branch = 0;
switch (code[i] & 0x7F) {
default:
continue;
case JOP_JUMP:
target = i + (codes[i] >> 8);
break;
case JOP_JUMP_IF:
case JOP_JUMP_IF_NOT:
case JOP_JUMP_IF_NIL:
case JOP_JUMP_IF_NOT_NIL:
is_branch = 1;
target = i + (codes[i] >> 16);
break;
}
if (target == i) continue; /* infinite loop */
if (target == i + 1) {
code[i] = JOP_NOOP;
recur = 1;
continue;
}
while ((code[target] & 0x7F) == JOP_NOOP) { /* Skip noops */
target++;
}
if ((code[target] & 0x7F) == JOP_RETURN_NIL && !is_branch) {
code[i] = JOP_RETURN_NIL;
recur = 1;
continue;
}
/* update target */
if ((code[target] & 0x7F) == JOP_JUMP) {
target += (codes[target] >> 8);
}
uint32_t newcode;
if (is_branch) {
newcode = (code[i] & 0xFFFF) | ((uint32_t)(target - i) << 16);
} else {
newcode = (code[i] & 0xFF) | ((uint32_t)(target - i) << 8);
}
if (newcode != code[i]) recur = 1;
code[i] = newcode;
}
}
}
/* Remove redundant loads, moves and other instructions if possible and convert them to
* noops. Input is assumed valid bytecode. */
void janet_bytecode_movopt(JanetFuncDef *def) {
JanetcRegisterAllocator ra;
int recur = 1;
@@ -357,6 +485,8 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
case JOP_LOAD_TRUE:
case JOP_LOAD_FALSE:
case JOP_LOAD_SELF:
case JOP_MAKE_STRING:
case JOP_MAKE_TABLE:
case JOP_MAKE_ARRAY:
case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE: {
@@ -401,6 +531,29 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
}
}
/* Entry point for optimization */
void janet_bytecode_optimize(JanetFuncDef *def) {
int32_t delta;
do { // Fixpoint for instruction removal
int32_t before = def->bytecode_length;
janet_bytecode_jump_threading(def);
janet_bytecode_movopt(def);
janet_bytecode_dead_code(def);
janet_bytecode_remove_noops(def);
delta = def->bytecode_length - before;
} while (delta < 0);
#ifdef JANET_BOOTSTRAP
total_instruction_count += def->bytecode_length;
#endif
}
/* TODO - type and error analysis */
/*
void janet_bytecode_analyze(JanetFuncDef *def) {
janet_panic("NYI");
}
*/
/* Verify some bytecode */
int janet_verify(JanetFuncDef *def) {
int vargs = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG);
+1 -2
View File
@@ -1131,8 +1131,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
janetc_popscope(c);
/* Do basic optimization */
janet_bytecode_movopt(def);
janet_bytecode_remove_noops(def);
janet_bytecode_optimize(def);
return def;
}
+1 -2
View File
@@ -288,7 +288,6 @@ JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
Shadowing janetc_shadowcheck(JanetCompiler *c, const uint8_t *sym);
/* Bytecode optimization */
void janet_bytecode_movopt(JanetFuncDef *def);
void janet_bytecode_remove_noops(JanetFuncDef *def);
void janet_bytecode_optimize(JanetFuncDef *def);
#endif
+1 -1
View File
@@ -1358,7 +1358,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
janet_def(env, "janet/build", janet_cstringv(JANET_BUILD),
JDOC("The build identifier of the running janet program."));
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
JDOC("The flag set of config options from janetconf.h which is used to check "
JDOC("The flag set of config options from `janetconf.h` which is used to check "
"if native modules are compatible with the host program."));
/* Allow references to the environment */
+9 -6
View File
@@ -1739,12 +1739,15 @@ JANET_CORE_FN(cfun_ffi_buffer_read,
JANET_CORE_FN(cfun_ffi_get_callback_trampoline,
"(ffi/trampoline cc)",
"Get a native function pointer that can be used as a callback and passed to C libraries. "
"This callback trampoline has the signature `void trampoline(void \\*ctx, void \\*userdata)` in "
"the given calling convention. This is the only function signature supported. "
"It is up to the programmer to ensure that the `userdata` argument contains a janet function "
"the will be called with one argument, `ctx` which is an opaque pointer. This pointer can "
"be further inspected with `ffi/read`.") {
"Get a native function pointer that can be used as a callback "
"and passed to C libraries. This callback trampoline has the "
"signature `void trampoline(void *ctx, void *userdata)` in "
"the given calling convention. This is the only function "
"signature supported. It is up to the programmer to ensure "
"that the `userdata` argument contains a janet function that "
"will be called with one argument, `ctx` which is an opaque "
"pointer. This pointer can be further inspected with "
"`ffi/read`.") {
janet_arity(argc, 0, 1);
JanetFFICallingConvention cc = JANET_FFI_CC_DEFAULT;
if (argc >= 1) cc = decode_ffi_cc(janet_getkeyword(argv, 0));
+102 -68
View File
@@ -835,20 +835,38 @@ static const JanetAbstractType janet_filewatch_at = {
};
JANET_CORE_FN(cfun_filewatch_make,
"(filewatch/new channel & default-flags)",
"Create a new filewatcher that will give events to a channel channel. See `filewatch/add` for available flags.\n\n"
"When an event is triggered by the filewatcher, a struct containing information will be given to channel as with `ev/give`. "
"The contents of the channel depend on the OS, but will contain some common keys:\n\n"
"* `:type` -- the type of the event that was raised.\n\n"
"* `:file-name` -- the base file name of the file that triggered the event.\n\n"
"* `:dir-name` -- the directory name of the file that triggered the event.\n\n"
"Events also will contain keys specific to the host OS.\n\n"
"Windows has no extra properties on events.\n\n"
"Linux and the BSDs have the following extra properties on events:\n\n"
"* `:wd` -- the integer key returned by `filewatch/add` for the path that triggered this. This is a file descriptor integer on BSD and macos.\n\n"
"* `:wd-path` -- the string path for watched directory of file. For files, will be the same as `:file-name`, and for directories, will be the same as `:dir-name`.\n\n"
"* `:cookie` -- a semi-randomized integer used to associate related events, such as :moved-from and :moved-to events.\n\n"
"") {
"(filewatch/new chan & default-flags)",
"Create a new filewatcher that will give events to a channel "
"`chan`. See `filewatch/add` for available flags.\n"
"\n"
"When an event is triggered by the filewatcher, a struct "
"containing information will be given to `chan` as with "
"`ev/give`. The contents of `chan` depend on the OS, but will "
"contain some common keys:\n"
"\n"
"* `:type` - type of the event that was raised\n"
"* `:file-name` - base file name of file that triggered the "
"event\n"
"* `:dir-name` - directory name of file that triggered the "
"event\n"
"\n"
"Events will also contain keys specific to the host OS.\n"
"\n"
"Windows has no extra properties on events.\n"
"\n"
"Linux and BSDs have the following extra properties on "
"events:\n"
"\n"
"* `:wd` - integer key returned by `filewatch/add` for path "
"that triggered this. This is a file descriptor integer on "
"BSD and macos.\n"
"\n"
"* `:wd-path` - string path for watched directory of file. "
"For files, same as `:file-name`, and for directories, same "
"as `:dir-name`.\n"
"\n"
"* `:cookie` - a semi-randomized integer used to associate "
"related events, such as `:moved-from` and `:moved-to`.") {
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
janet_arity(argc, 1, -1);
JanetChannel *channel = janet_getchannel(argv, 0);
@@ -859,60 +877,76 @@ JANET_CORE_FN(cfun_filewatch_make,
}
JANET_CORE_FN(cfun_filewatch_add,
"(filewatch/add watcher path flag & more-flags)",
"Add a path to the watcher. Available flags depend on the current OS, and are as follows:\n\n"
"Windows/MINGW (flags correspond to `FILE_NOTIFY_CHANGE_*` flags in win32 documentation):\n\n"
"FLAGS\n\n"
"* `:all` - trigger an event for all of the below triggers.\n\n"
"* `:attributes` - `FILE_NOTIFY_CHANGE_ATTRIBUTES`\n\n"
"* `:creation` - `FILE_NOTIFY_CHANGE_CREATION`\n\n"
"* `:dir-name` - `FILE_NOTIFY_CHANGE_DIR_NAME`\n\n"
"* `:last-access` - `FILE_NOTIFY_CHANGE_LAST_ACCESS`\n\n"
"* `:last-write` - `FILE_NOTIFY_CHANGE_LAST_WRITE`\n\n"
"* `:security` - `FILE_NOTIFY_CHANGE_SECURITY`\n\n"
"* `:size` - `FILE_NOTIFY_CHANGE_SIZE`\n\n"
"* `:recursive` - watch subdirectories recursively\n\n"
"Linux (flags correspond to `IN_*` flags from <sys/inotify.h>):\n\n"
"* `:access` - `IN_ACCESS`\n\n"
"* `:all` - `IN_ALL_EVENTS`\n\n"
"* `:attrib` - `IN_ATTRIB`\n\n"
"* `:close-nowrite` - `IN_CLOSE_NOWRITE`\n\n"
"* `:close-write` - `IN_CLOSE_WRITE`\n\n"
"* `:create` - `IN_CREATE`\n\n"
"* `:delete` - `IN_DELETE`\n\n"
"* `:delete-self` - `IN_DELETE_SELF`\n\n"
"* `:ignored` - `IN_IGNORED`\n\n"
"* `:modify` - `IN_MODIFY`\n\n"
"* `:move-self` - `IN_MOVE_SELF`\n\n"
"* `:moved-from` - `IN_MOVED_FROM`\n\n"
"* `:moved-to` - `IN_MOVED_TO`\n\n"
"* `:open` - `IN_OPEN`\n\n"
"* `:q-overflow` - `IN_Q_OVERFLOW`\n\n"
"* `:unmount` - `IN_UNMOUNT`\n\n\n"
"BSDs and macos (flags correspond to `NOTE_*` flags from <sys/event.h>). Not all flags are available on all systems:\n\n"
"* `:all` - `All available NOTE_* flags on the current platform`\n\n"
"* `:attrib` - `NOTE_ATTRIB`\n\n"
"* `:close-write` - `NOTE_CLOSE_WRITE`\n\n"
"* `:close` - `NOTE_CLOSE`\n\n"
"* `:delete` - `NOTE_DELETE`\n\n"
"* `:extend` - `NOTE_EXTEND`\n\n"
"* `:funlock` - `NOTE_FUNLOCK`\n\n"
"* `:link` - `NOTE_LINK`\n\n"
"* `:open` - `NOTE_OPEN`\n\n"
"* `:read` - `NOTE_READ`\n\n"
"* `:rename` - `NOTE_RENAME`\n\n"
"* `:revoke` - `NOTE_REVOKE`\n\n"
"* `:truncate` - `NOTE_TRUNCATE`\n\n"
"* `:write` - `NOTE_WRITE`\n\n\n"
"EVENT TYPES\n\n"
"On Windows, events will have the following possible types:\n\n"
"* `:unknown`\n\n"
"* `:added`\n\n"
"* `:removed`\n\n"
"* `:modified`\n\n"
"* `:renamed-old`\n\n"
"* `:renamed-new`\n\n"
"On Linux and BSDs, events will have a `:type` corresponding to the possible flags, excluding `:all`.\n"
"(filewatch/add watcher path flags & more-flags)",
"Add a path to the watcher. Available flags and event types "
"depend on the current OS, and are as follows.\n"
"\n"
"Flags\n"
"\n"
"Windows/MINGW (correspond to `FILE_NOTIFY_CHANGE_*` flags in "
"win32 documentation):\n"
"\n"
"* `:all` - trigger an event for all of the below triggers.\n"
"* `:attributes` - `FILE_NOTIFY_CHANGE_ATTRIBUTES`\n"
"* `:creation` - `FILE_NOTIFY_CHANGE_CREATION`\n"
"* `:dir-name` - `FILE_NOTIFY_CHANGE_DIR_NAME`\n"
"* `:last-access` - `FILE_NOTIFY_CHANGE_LAST_ACCESS`\n"
"* `:last-write` - `FILE_NOTIFY_CHANGE_LAST_WRITE`\n"
"* `:security` - `FILE_NOTIFY_CHANGE_SECURITY`\n"
"* `:size` - `FILE_NOTIFY_CHANGE_SIZE`\n"
"* `:recursive` - watch subdirectories recursively\n"
"\n"
"Linux (correspond to `IN_*` flags from `<sys/inotify.h>`):\n"
"\n"
"* `:access` - `IN_ACCESS`\n"
"* `:all` - `IN_ALL_EVENTS`\n"
"* `:attrib` - `IN_ATTRIB`\n"
"* `:close-nowrite` - `IN_CLOSE_NOWRITE`\n"
"* `:close-write` - `IN_CLOSE_WRITE`\n"
"* `:create` - `IN_CREATE`\n"
"* `:delete` - `IN_DELETE`\n"
"* `:delete-self` - `IN_DELETE_SELF`\n"
"* `:ignored` - `IN_IGNORED`\n"
"* `:modify` - `IN_MODIFY`\n"
"* `:move-self` - `IN_MOVE_SELF`\n"
"* `:moved-from` - `IN_MOVED_FROM`\n"
"* `:moved-to` - `IN_MOVED_TO`\n"
"* `:open` - `IN_OPEN`\n"
"* `:q-overflow` - `IN_Q_OVERFLOW`\n"
"* `:unmount` - `IN_UNMOUNT`\n"
"\n"
"BSDs and macos (correspond to `NOTE_*` flags from "
"`<sys/event.h>`). Not all flags are available on all "
"systems:\n"
"\n"
"* `:all` - All available `NOTE_*` flags on the current platform\n"
"* `:attrib` - `NOTE_ATTRIB`\n"
"* `:close-write` - `NOTE_CLOSE_WRITE`\n"
"* `:close` - `NOTE_CLOSE`\n"
"* `:delete` - `NOTE_DELETE`\n"
"* `:extend` - `NOTE_EXTEND`\n"
"* `:funlock` - `NOTE_FUNLOCK`\n"
"* `:link` - `NOTE_LINK`\n"
"* `:open` - `NOTE_OPEN`\n"
"* `:read` - `NOTE_READ`\n"
"* `:rename` - `NOTE_RENAME`\n"
"* `:revoke` - `NOTE_REVOKE`\n"
"* `:truncate` - `NOTE_TRUNCATE`\n"
"* `:write` - `NOTE_WRITE`\n"
"\n"
"Event Types\n"
"\n"
"On Windows, events will have the following possible types:\n"
"\n"
"* `:unknown`\n"
"* `:added`\n"
"* `:removed`\n"
"* `:modified`\n"
"* `:renamed-old`\n"
"* `:renamed-new`\n"
"\n"
"On Linux and BSDs, events will have a `:type` corresponding "
"to the possible flags, excluding `:all`.\n"
"") {
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
janet_arity(argc, 2, -1);
+31 -28
View File
@@ -141,18 +141,23 @@ JANET_CORE_FN(cfun_io_temp,
JANET_CORE_FN(cfun_io_fopen,
"(file/open path &opt mode buffer-size)",
"Open a file. `path` is an absolute or relative path, and "
"`mode` is a set of flags indicating the mode to open the file in. "
"`mode` is a keyword where each character represents a flag. If the file "
"cannot be opened, returns nil, otherwise returns the new file handle. "
"Mode flags:\n\n"
"* r - allow reading from the file\n\n"
"* w - allow writing to the file\n\n"
"* a - append to the file\n\n"
"Following one of the initial flags, 0 or more of the following flags can be appended:\n\n"
"* b - open the file in binary mode (rather than text mode)\n\n"
"* + - append to the file instead of overwriting it\n\n"
"* n - error if the file cannot be opened instead of returning nil\n\n"
"See fopen (<stdio.h>, C99) for further details.") {
"`mode` is a set of flags indicating the mode to open the "
"file in. `mode` is a keyword where each character represents "
"a flag. If the file cannot be opened, returns nil, otherwise "
"returns the new file handle. Mode flags:\n"
"\n"
"* `r` - allow reading from file\n"
"* `w` - allow writing to file\n"
"* `a` - append to file\n"
"\n"
"After one of the initial flags, 0 or more of the following "
"flags can be appended:\n"
"\n"
"* `b` - open file in binary mode (rather than text mode)\n"
"* `+` - open file for both reading and writing\n"
"* `n` - error if file cannot be opened instead of returning nil\n"
"\n"
"See `fopen()` (`<stdio.h>`, C99) for further details.") {
janet_arity(argc, 1, 3);
const uint8_t *fname = janet_getstring(argv, 0);
const uint8_t *fmode;
@@ -342,12 +347,12 @@ JANET_CORE_FN(cfun_io_fclose,
/* Seek a file */
JANET_CORE_FN(cfun_io_fseek,
"(file/seek f &opt whence n)",
"(file/seek f whence &opt n)",
"Jump to a relative location in the file `f`. `whence` must be one of:\n\n"
"* :cur - jump relative to the current file location\n\n"
"* :set - jump relative to the beginning of the file\n\n"
"* :end - jump relative to the end of the file\n\n"
"By default, `whence` is :cur. Optionally a value `n` may be passed "
"By default, `n` is 0. Optionally a value `n` may be passed "
"for the relative number of bytes to seek in the file. `n` may be a real "
"number to handle large files of more than 4GB. Returns the file handle.") {
janet_arity(argc, 2, 3);
@@ -356,20 +361,18 @@ JANET_CORE_FN(cfun_io_fseek,
janet_panic("file is closed");
int64_t offset = 0;
int whence = SEEK_CUR;
if (argc >= 2) {
const uint8_t *whence_sym = janet_getkeyword(argv, 1);
if (!janet_cstrcmp(whence_sym, "cur")) {
whence = SEEK_CUR;
} else if (!janet_cstrcmp(whence_sym, "set")) {
whence = SEEK_SET;
} else if (!janet_cstrcmp(whence_sym, "end")) {
whence = SEEK_END;
} else {
janet_panicf("expected one of :cur, :set, :end, got %v", argv[1]);
}
if (argc == 3) {
offset = (int64_t) janet_getinteger64(argv, 2);
}
const uint8_t *whence_sym = janet_getkeyword(argv, 1);
if (!janet_cstrcmp(whence_sym, "cur")) {
whence = SEEK_CUR;
} else if (!janet_cstrcmp(whence_sym, "set")) {
whence = SEEK_SET;
} else if (!janet_cstrcmp(whence_sym, "end")) {
whence = SEEK_END;
} else {
janet_panicf("expected one of :cur, :set, :end, got %v", argv[1]);
}
if (argc == 3) {
offset = (int64_t) janet_getinteger64(argv, 2);
}
if (fseek(iof->file, offset, whence)) janet_panic("error seeking file");
return argv[0];
+1 -1
View File
@@ -1484,7 +1484,7 @@ static const uint8_t *unmarshal_one(
/* Tuple */
Janet *tup = janet_tuple_begin(len);
int32_t flag = readint(st, &data);
janet_tuple_flag(tup) |= (int32_t) (((uint32_t) flag) << 16); /* Avoid left shift of negative value */
janet_tuple_flag(tup) |= (int32_t)(((uint32_t) flag) << 16); /* Avoid left shift of negative value */
for (int32_t i = 0; i < len; i++) {
data = unmarshal_one(st, data, tup + i, flags + 1);
}
+2 -4
View File
@@ -953,9 +953,8 @@ JANET_CORE_FN(cfun_net_getsockname,
janet_fixarity(argc, 1);
JanetStream *js = janet_getabstract(argv, 0, &janet_stream_type);
if (js->flags & JANET_STREAM_CLOSED) janet_panic("stream closed");
char ss[sizeof(struct sockaddr_storage) + 64]; /* extra space */
struct sockaddr_storage ss = { 0 };
socklen_t slen = sizeof(ss);
memset(&ss, 0, slen);
if (getsockname((JSock)js->handle, (struct sockaddr *) &ss, &slen)) {
janet_panicf("Failed to get localname on %v: %V", argv[0], janet_ev_lasterr());
}
@@ -969,9 +968,8 @@ JANET_CORE_FN(cfun_net_getpeername,
janet_fixarity(argc, 1);
JanetStream *js = janet_getabstract(argv, 0, &janet_stream_type);
if (js->flags & JANET_STREAM_CLOSED) janet_panic("stream closed");
char ss[sizeof(struct sockaddr_storage) + 64]; /* extra space */
struct sockaddr_storage ss = { 0 };
socklen_t slen = sizeof(ss);
memset(&ss, 0, slen);
if (getpeername((JSock)js->handle, (struct sockaddr *)&ss, &slen)) {
janet_panicf("Failed to get peername on %v: %V", argv[0], janet_ev_lasterr());
}
+58 -43
View File
@@ -1916,20 +1916,25 @@ static struct tm *time_to_tm(const Janet *argv, int32_t argc, int32_t n, struct
JANET_CORE_FN(os_date,
"(os/date &opt time local)",
"Returns the given time as a date struct, or the current time if `time` is not given. "
"Date is given in UTC unless `local` is truthy, in which case the date is formatted for "
"the local timezone. Returns a struct with following key values. Note that all numbers are 0-indexed.\n\n"
"* :seconds - number of seconds [0-61]\n\n"
"* :minutes - number of minutes [0-59]\n\n"
"* :hours - number of hours [0-23]\n\n"
"* :month-day - day of month [0-30]\n\n"
"* :month - month of year [0, 11]\n\n"
"* :year - years since year 0 (e.g. 2019)\n\n"
"* :week-day - day of the week [0-6]\n\n"
"* :year-day - day of the year [0-365]\n\n"
"* :dst - if Day Light Savings is in effect\n\n"
"You can set local timezone by setting TZ environment variable. "
"See tzset(<time.h>) or _tzset(<time.h>) for further details.") {
"Returns the given time as a date struct, or the current time "
"if `time` is not given. Date is given in UTC unless `local` "
"is truthy, in which case the date is formatted for the local "
"timezone. Returns a struct with following key-value pairs. "
"Note that all numbers are 0-indexed.\n"
"\n"
"* `:seconds` - number of seconds [0-61]\n"
"* `:minutes` - number of minutes [0-59]\n"
"* `:hours` - number of hours [0-23]\n"
"* `:month-day` - day of month [0-30]\n"
"* `:month` - month of year [0, 11]\n"
"* `:year` - years since year 0 (e.g. 2019)\n"
"* `:week-day` - day of the week [0-6]\n"
"* `:year-day` - day of the year [0-365]\n"
"* `:dst` - if Day Light Savings is in effect\n"
"\n"
"The local timezone can be set by setting the `TZ` "
"environment variable. See `tzset()` (`<time.h>`) or "
"`_tzset()` (`<time.h>`) for further details.") {
janet_arity(argc, 0, 2);
(void) argv;
struct tm t_infos;
@@ -1951,11 +1956,14 @@ JANET_CORE_FN(os_date,
JANET_CORE_FN(os_strftime,
"(os/strftime fmt &opt time local)",
"Format the given time as a string, or the current time if `time` is not given. "
"The time is formatted according to the same rules as the ISO C89 function strftime(). "
"The time is formatted in UTC unless `local` is truthy, in which case the date is formatted for "
"the local timezone. You can set local timezone by setting TZ environment variable. "
"See tzset(<time.h>) or _tzset(<time.h>) for further details.") {
"Format the given time as a string, or the current time if "
"`time` is not given. The time is formatted according to the "
"same rules as the ISO C89 function `strftime()`. The time is "
"formatted in UTC unless `local` is truthy, in which case the "
"date is formatted for the local timezone. The local timezone "
"can be set by setting the `TZ` environment variable. See "
"`tzset()` (`<time.h>`) or `_tzset()`(`<time.h>`) for further "
"details.") {
janet_arity(argc, 1, 3);
const char *fmt = janet_getcstring(argv, 0);
/* ANSI X3.159-1989, section 4.12.3.5 "The strftime function" */
@@ -2715,32 +2723,39 @@ 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. "
"The default mode is 8r666. "
"Allowed flags are as follows:\n\n"
"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. The default mode is 8r666.\n"
"\n"
"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"
" * :a - append to a file (O\\_APPEND on posix, FILE_APPEND_DATA on windows)\n"
"Posix-only flags:\n\n"
" * :x - O\\_SYNC\n"
" * :C - O\\_NOCTTY\n\n"
" * :N - Turn off O\\_NONBLOCK and disable ev reading/writing\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"
" * :H - FILE\\_ATTRIBUTE\\_HIDDEN\n"
" * :O - FILE\\_ATTRIBUTE\\_READONLY\n"
" * :F - FILE\\_ATTRIBUTE\\_OFFLINE\n"
" * :T - FILE\\_ATTRIBUTE\\_TEMPORARY\n"
" * :d - FILE\\_FLAG\\_DELETE\\_ON\\_CLOSE\n"
" * :V - Turn off FILE\\_FLAG\\_OVERLAPPED and disable ev reading/writing\n"
" * :I - set bInheritHandle on the created file so it can be passed to other processes.\n"
" * :b - FILE\\_FLAG\\_NO\\_BUFFERING\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"
" * :a - append to a file (`O_APPEND` on posix, `FILE_APPEND_DATA` on windows)\n"
"\n"
"Posix-only flags:\n"
"\n"
" * :x - `O_SYNC`\n"
" * :C - `O_NOCTTY`\n"
" * :N - Turn off `O_NONBLOCK` and disable ev reading/writing\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"
" * :H - `FILE_ATTRIBUTE_HIDDEN`\n"
" * :O - `FILE_ATTRIBUTE_READONLY`\n"
" * :F - `FILE_ATTRIBUTE_OFFLINE`\n"
" * :T - `FILE_ATTRIBUTE_TEMPORARY`\n"
" * :d - `FILE_FLAG_DELETE_ON_CLOSE`\n"
" * :V - Turn off `FILE_FLAG_OVERLAPPED` and disable ev reading/writing\n"
" * :I - set `bInheritHandle` on the created file so it can be passed to other processes.\n"
" * :b - `FILE_FLAG_NO_BUFFERING`\n") {
janet_arity(argc, 1, 3);
const char *path = janet_getcstring(argv, 0);
const uint8_t *opt_flags = janet_optkeyword(argv, argc, 1, (const uint8_t *) "r");
+3 -3
View File
@@ -734,10 +734,10 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
labeld = janet_v_count(c->buffer);
if (labeljr < labeld) {
check_16bit_jump(c, labeljr, labelr);
c->buffer[labeljr] |= (uint32_t) (labelr - labeljr) << 16;
c->buffer[labeljr] |= (uint32_t)(labelr - labeljr) << 16;
if (!tail && labeljd < labeld) {
check_24bit_jump(c, labeljd, labeld);
c->buffer[labeljd] |= (uint32_t) (labeld - labeljd) << 8;
c->buffer[labeljd] |= (uint32_t)(labeld - labeljd) << 8;
}
}
@@ -991,7 +991,7 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
for (int32_t i = labelwt; i < labeld; i++) {
if (c->buffer[i] == (0x80 | JOP_JUMP)) {
check_24bit_jump(c, i, labeld);
c->buffer[i] = JOP_JUMP | ((uint32_t) (labeld - i) << 8);
c->buffer[i] = JOP_JUMP | ((uint32_t)(labeld - i) << 8);
}
}
+1 -1
View File
@@ -584,7 +584,7 @@ static void janet_check_pointer_align(void *p) {
uintptr_t u;
} un;
un.p = p;
janet_assert(!(un.u & (uintptr_t) ((1 << JANET_NANBOX_64_POINTER_SHIFT) - 1)),
janet_assert(!(un.u & (uintptr_t)((1 << JANET_NANBOX_64_POINTER_SHIFT) - 1)),
"unaligned pointer wrap - cfunction pointers and abstract types must be aligned with this nanboxing configuration.");
#endif
}
+4
View File
@@ -167,6 +167,10 @@ enum JanetTimeSource {
int janet_gettime(struct timespec *spec, enum JanetTimeSource source);
#endif
#ifdef JANET_BOOTSTRAP
extern int64_t total_instruction_count;
#endif
/* strdup */
#ifdef JANET_WINDOWS
#define strdup(x) _strdup(x)
+4 -1
View File
@@ -55,7 +55,10 @@
(file/flush f)
(file/seek f :set 0)
(assert (= 0 (file/tell f)) "start of file again")
(assert (= (string (file/read f :all)) "foo\n") "temp files work"))
(assert (= (string (file/read f :all)) "foo\n") "temp files work")
(file/seek f :set)
(assert (= 0 (file/tell f)) "start of file again 2")
(assert (= (string (file/read f :all)) "foo\n") "temp files work 2"))
# issue #1055 - 2c927ea76
(let [b @""]