diff --git a/CHANGELOG.md b/CHANGELOG.md index d47c0e12..a17ed803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/boot/boot.c b/src/boot/boot.c index 3a3c502b..abda24ca 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -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(); diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 7b080632..4179e06a 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -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)) diff --git a/src/boot/tests.h b/src/boot/tests.h index 65e40433..10b0ca91 100644 --- a/src/boot/tests.h +++ b/src/boot/tests.h @@ -1,6 +1,12 @@ #ifndef TESTS_H_DNMBUYYL #define TESTS_H_DNMBUYYL +#include +#include + +/* Copy of util.h */ +extern int64_t total_instruction_count; + /* Tests */ extern int array_test(); extern int buffer_test(); diff --git a/src/core/array.c b/src/core/array.c index c8ebcc58..789b7363 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -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; diff --git a/src/core/buffer.c b/src/core/buffer.c index 5a1e08b2..83389e9b 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -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); diff --git a/src/core/bytecode.c b/src/core/bytecode.c index f1fbbe1d..af43388d 100644 --- a/src/core/bytecode.c +++ b/src/core/bytecode.c @@ -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); diff --git a/src/core/compile.c b/src/core/compile.c index 1ded7d26..a9607a66 100644 --- a/src/core/compile.c +++ b/src/core/compile.c @@ -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; } diff --git a/src/core/compile.h b/src/core/compile.h index 9f120013..6983dd83 100644 --- a/src/core/compile.h +++ b/src/core/compile.h @@ -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 diff --git a/src/core/corelib.c b/src/core/corelib.c index 541587bc..a375b8ae 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -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 */ diff --git a/src/core/ffi.c b/src/core/ffi.c index d638e896..6801023f 100644 --- a/src/core/ffi.c +++ b/src/core/ffi.c @@ -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)); diff --git a/src/core/filewatch.c b/src/core/filewatch.c index aee6b17e..f652ab47 100644 --- a/src/core/filewatch.c +++ b/src/core/filewatch.c @@ -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 ):\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 ). 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 ``):\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 " + "``). 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); diff --git a/src/core/io.c b/src/core/io.c index 61488cb8..b54849bb 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -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 (, 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()` (``, 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]; diff --git a/src/core/marsh.c b/src/core/marsh.c index 043fa8c1..07288a55 100644 --- a/src/core/marsh.c +++ b/src/core/marsh.c @@ -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); } diff --git a/src/core/net.c b/src/core/net.c index d0fc3c24..7c2e0061 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -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()); } diff --git a/src/core/os.c b/src/core/os.c index c46f05e5..85a6ae30 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -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() or _tzset() 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()` (``) or " + "`_tzset()` (``) 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() or _tzset() 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()` (``) or `_tzset()`(``) 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"); diff --git a/src/core/specials.c b/src/core/specials.c index 1f154d8b..102ba5dc 100644 --- a/src/core/specials.c +++ b/src/core/specials.c @@ -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); } } diff --git a/src/core/util.c b/src/core/util.c index 1156081e..c678703d 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -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 } diff --git a/src/core/util.h b/src/core/util.h index 101fc27d..50177bff 100644 --- a/src/core/util.h +++ b/src/core/util.h @@ -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) diff --git a/test/suite-io.janet b/test/suite-io.janet index 23672f62..6062b518 100644 --- a/test/suite-io.janet +++ b/test/suite-io.janet @@ -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 @""]