mirror of
https://github.com/janet-lang/janet
synced 2026-10-09 17:21:41 +00:00
Merge branch 'master' into better-loopback-determination
This commit is contained in:
+2
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 @""]
|
||||
|
||||
Reference in New Issue
Block a user