mirror of https://github.com/janet-lang/janet
Compare commits
34 Commits
Author | SHA1 | Date |
---|---|---|
Calvin Rose | 91a583db27 | |
znley | c1647a74c5 | |
Calvin Rose | 721f280966 | |
Calvin Rose | e914eaf055 | |
Calvin Rose | fe54013679 | |
Calvin Rose | fdaf2e1594 | |
Calvin Rose | 9946f3bdf4 | |
Calvin Rose | c747e8d16c | |
Calvin Rose | 3e402d397e | |
Calvin Rose | 0350834cd3 | |
Calvin Rose | 60e22d9703 | |
John W Higgins | ee7362e847 | |
Calvin Rose | 369f96b80e | |
Calvin Rose | 7c5ed04ab1 | |
Calvin Rose | 4779a445e0 | |
Calvin Rose | f0f1b7ce9e | |
Calvin Rose | 7c9157a0ed | |
Calvin Rose | 522a6cb435 | |
Gautham | d0d551d739 | |
Gautham | 71a123fef7 | |
Gautham | 3f40c8d7fb | |
Gautham | 983c2e5499 | |
Gautham | eebb4c3ade | |
Gautham | 50425eac72 | |
Gautham | 382ff77bbe | |
Gautham | bf680fb5d3 | |
Gautham | 4ed7db4f91 | |
Calvin Rose | bf19920d65 | |
Gautham | 174b5f6686 | |
Gautham | 4173645b81 | |
Gautham | af511f1f55 | |
Gautham | 83c6080380 | |
Calvin Rose | 2f0c789ea1 | |
Calvin Rose | a9b8f8e8a9 |
|
@ -1,4 +1,4 @@
|
|||
image: openbsd/latest
|
||||
image: openbsd/7.4
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
COSMO_DIR="/sc/cosmocc"
|
||||
|
||||
# build x86_64
|
||||
X86_64_CC="/sc/cosmocc/bin/x86_64-unknown-cosmo-cc"
|
||||
X86_64_AR="/sc/cosmocc/bin/x86_64-unknown-cosmo-ar"
|
||||
mkdir -p /sc/cosmocc/x86_64
|
||||
make -j CC="$X86_64_CC" AR="$X86_64_AR" HAS_SHARED=0 JANET_NO_AMALG=1
|
||||
cp build/janet /sc/cosmocc/x86_64/janet
|
||||
make clean
|
||||
|
||||
# build aarch64
|
||||
AARCH64_CC="/sc/cosmocc/bin/aarch64-unknown-cosmo-cc"
|
||||
AARCH64_AR="/sc/cosmocc/bin/aarch64-unknown-cosmo-ar"
|
||||
mkdir -p /sc/cosmocc/aarch64
|
||||
make -j CC="$AARCH64_CC" AR="$AARCH64_AR" HAS_SHARED=0 JANET_NO_AMALG=1
|
||||
cp build/janet /sc/cosmocc/aarch64/janet
|
||||
make clean
|
||||
|
||||
# fat binary
|
||||
apefat () {
|
||||
OUTPUT="$1"
|
||||
OLDNAME_X86_64="$(basename -- "$2")"
|
||||
OLDNAME_AARCH64="$(basename -- "$3")"
|
||||
TARG_FOLD="$(dirname "$OUTPUT")"
|
||||
"$COSMO_DIR/bin/apelink" -l "$COSMO_DIR/bin/ape-x86_64.elf" \
|
||||
-l "$COSMO_DIR/bin/ape-aarch64.elf" \
|
||||
-M "$COSMO_DIR/bin/ape-m1.c" \
|
||||
-o "$OUTPUT" \
|
||||
"$2" \
|
||||
"$3"
|
||||
cp "$2" "$TARG_FOLD/$OLDNAME_X86_64.x86_64"
|
||||
cp "$3" "$TARG_FOLD/$OLDNAME_AARCH64.aarch64"
|
||||
}
|
||||
|
||||
apefat /sc/cosmocc/janet.com /sc/cosmocc/x86_64/janet /sc/cosmocc/aarch64/janet
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
sudo apt update
|
||||
sudo apt-get install -y ca-certificates libssl-dev\
|
||||
qemu qemu-utils qemu-user-static\
|
||||
texinfo groff\
|
||||
cmake ninja-build bison zip\
|
||||
pkg-config build-essential autoconf re2c
|
||||
|
||||
# download cosmocc
|
||||
cd /sc
|
||||
wget https://github.com/jart/cosmopolitan/releases/download/3.3.3/cosmocc-3.3.3.zip
|
||||
mkdir -p cosmocc
|
||||
cd cosmocc
|
||||
unzip ../cosmocc-3.3.3.zip
|
||||
|
||||
# register
|
||||
cd /sc/cosmocc
|
||||
sudo cp ./bin/ape-x86_64.elf /usr/bin/ape
|
||||
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
|
@ -60,3 +60,30 @@ jobs:
|
|||
./dist/*.zip
|
||||
./*.zip
|
||||
./*.msi
|
||||
|
||||
release-cosmo:
|
||||
permissions:
|
||||
contents: write # for softprops/action-gh-release to create GitHub release
|
||||
name: Build release binaries for Cosmo
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: create build folder
|
||||
run: |
|
||||
sudo mkdir -p /sc
|
||||
sudo chmod -R 0777 /sc
|
||||
- name: setup Cosmopolitan Libc
|
||||
run: bash ./.github/cosmo/setup
|
||||
- name: Set the version
|
||||
run: echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
|
||||
- name: Set the platform
|
||||
run: echo "platform=cosmo" >> $GITHUB_ENV
|
||||
- name: build Janet APE binary
|
||||
run: bash ./.github/cosmo/build
|
||||
- name: push binary to github
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
/sc/cosmocc/janet.com
|
||||
|
|
|
@ -134,6 +134,9 @@ Module.symvers
|
|||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Coverage files
|
||||
*.cov
|
||||
|
||||
# End of https://www.gitignore.io/api/c
|
||||
|
||||
# Created by https://www.gitignore.io/api/cmake
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased - ???
|
||||
- Add `with-env`
|
||||
- Add *module-make-env* dynamic binding
|
||||
- Add buffer/format-at
|
||||
- Add long form command line options for readable CLI usage
|
||||
- Fix bug with `net/accept-loop` that would sometimes miss connections.
|
||||
|
||||
## 1.34.0 - 2024-03-22
|
||||
- Add a new (split) PEG special by @ianthehenry
|
||||
- Add buffer/push-* sized int and float by @pnelson
|
||||
|
|
|
@ -315,8 +315,7 @@ See the [Embedding Section](https://janet-lang.org/capi/embedding.html) on the w
|
|||
|
||||
## Discussion
|
||||
|
||||
Feel free to ask questions and join the discussion on the [Janet Gitter channel](https://gitter.im/janet-language/community).
|
||||
Gitter provides Matrix and IRC bridges as well.
|
||||
Feel free to ask questions and join the discussion on the [Janet Zulip Instance](https://janet.zulipchat.com/)
|
||||
|
||||
## FAQ
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
(ffi/defbind sixints-fn six-ints [])
|
||||
(ffi/defbind sixints-fn-2 :int [x :int s six-ints])
|
||||
(ffi/defbind sixints-fn-3 :int [s six-ints x :int])
|
||||
(ffi/defbind-alias int-fn int-fn-aliased :int [a :int b :int])
|
||||
|
||||
#
|
||||
# Struct reading and writing
|
||||
|
@ -119,6 +120,7 @@
|
|||
(tracev (return-struct 42))
|
||||
(tracev (double-lots 1 2 3 4 5 6 700 800 9 10))
|
||||
(tracev (struct-big 11 99.5))
|
||||
(tracev (int-fn-aliased 10 20))
|
||||
|
||||
(assert (= [10 10 12 12] (split-ret-fn 10 12)))
|
||||
(assert (= [12 12 10 10] (split-flip-ret-fn 10 12)))
|
||||
|
|
|
@ -1423,6 +1423,11 @@
|
|||
~(setdyn ,(bindings i) ,(bindings (+ i 1)))))
|
||||
~(,resume (,fiber/new (fn [] ,;dyn-forms ,;body) :p)))
|
||||
|
||||
(defmacro with-env
|
||||
`Run a block of code with a given environment table`
|
||||
[env & body]
|
||||
~(,resume (,fiber/new (fn [] ,;body) : ,env)))
|
||||
|
||||
(defmacro with-vars
|
||||
``Evaluates `body` with each var in `vars` temporarily bound. Similar signature to
|
||||
`let`, but each binding must be a var.``
|
||||
|
@ -2767,10 +2772,11 @@
|
|||
(defn- check-is-dep [x] (unless (or (string/has-prefix? "/" x) (string/has-prefix? "@" x) (string/has-prefix? "." x)) x))
|
||||
(defn- check-project-relative [x] (if (string/has-prefix? "/" x) x))
|
||||
|
||||
(defdyn *module/cache* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module/paths* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module/loading* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module/loaders* "Dynamic binding for overriding `module/loaders`")
|
||||
(defdyn *module-cache* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module-paths* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module-loading* "Dynamic binding for overriding `module/cache`")
|
||||
(defdyn *module-loaders* "Dynamic binding for overriding `module/loaders`")
|
||||
(defdyn *module-make-env* "Dynamic binding for creating new environments for `import`, `require`, and `dofile`. Overrides `make-env`.")
|
||||
|
||||
(def module/cache
|
||||
"A table, mapping loaded module identifiers to their environments."
|
||||
|
@ -2800,7 +2806,7 @@
|
|||
keyword name of a loader in `module/loaders`. Returns the modified `module/paths`.
|
||||
```
|
||||
[ext loader]
|
||||
(def mp (dyn *module/paths* module/paths))
|
||||
(def mp (dyn *module-paths* module/paths))
|
||||
(defn- find-prefix
|
||||
[pre]
|
||||
(or (find-index |(and (string? ($ 0)) (string/has-prefix? pre ($ 0))) mp) 0))
|
||||
|
@ -2818,7 +2824,7 @@
|
|||
(module/add-paths "/init.janet" :source)
|
||||
(module/add-paths ".janet" :source)
|
||||
(module/add-paths ".jimage" :image)
|
||||
(array/insert module/paths 0 [(fn is-cached [path] (if (in (dyn *module/cache* module/cache) path) path)) :preload check-not-relative])
|
||||
(array/insert module/paths 0 [(fn is-cached [path] (if (in (dyn *module-cache* module/cache) path) path)) :preload check-not-relative])
|
||||
|
||||
# Version of fexists that works even with a reduced OS
|
||||
(defn- fexists
|
||||
|
@ -2848,7 +2854,7 @@
|
|||
```
|
||||
[path]
|
||||
(var ret nil)
|
||||
(def mp (dyn *module/paths* module/paths))
|
||||
(def mp (dyn *module-paths* module/paths))
|
||||
(each [p mod-kind checker] mp
|
||||
(when (mod-filter checker path)
|
||||
(if (function? p)
|
||||
|
@ -2958,7 +2964,7 @@
|
|||
:core/stream path
|
||||
(file/open path :rb)))
|
||||
(def path-is-file (= f path))
|
||||
(default env (make-env))
|
||||
(default env ((dyn *module-make-env* make-env)))
|
||||
(def spath (string path))
|
||||
(put env :source (or source (if-not path-is-file spath path)))
|
||||
(var exit-error nil)
|
||||
|
@ -3020,12 +3026,12 @@
|
|||
of files as modules.``
|
||||
@{:native (fn native-loader [path &] (native path (make-env)))
|
||||
:source (fn source-loader [path args]
|
||||
(def ml (dyn *module/loading* module/loading))
|
||||
(def ml (dyn *module-loading* module/loading))
|
||||
(put ml path true)
|
||||
(defer (put ml path nil)
|
||||
(dofile path ;args)))
|
||||
:preload (fn preload-loader [path & args]
|
||||
(def mc (dyn *module/cache* module/cache))
|
||||
(def mc (dyn *module-cache* module/cache))
|
||||
(when-let [m (in mc path)]
|
||||
(if (function? m)
|
||||
(set (mc path) (m path ;args))
|
||||
|
@ -3036,9 +3042,9 @@
|
|||
[path args kargs]
|
||||
(def [fullpath mod-kind] (module/find path))
|
||||
(unless fullpath (error mod-kind))
|
||||
(def mc (dyn *module/cache* module/cache))
|
||||
(def ml (dyn *module/loading* module/loading))
|
||||
(def mls (dyn *module/loaders* module/loaders))
|
||||
(def mc (dyn *module-cache* module/cache))
|
||||
(def ml (dyn *module-loading* module/loading))
|
||||
(def mls (dyn *module-loaders* module/loaders))
|
||||
(if-let [check (if-not (kargs :fresh) (in mc fullpath))]
|
||||
check
|
||||
(if (ml fullpath)
|
||||
|
@ -3444,9 +3450,9 @@
|
|||
(defn- print-special-form-entry
|
||||
[x]
|
||||
(print "\n\n"
|
||||
(string " special form\n\n")
|
||||
(string " (" x " ...)\n\n")
|
||||
(string " See https://janet-lang.org/docs/specials.html\n\n")))
|
||||
" special form\n\n"
|
||||
" (" x " ...)\n\n"
|
||||
" See https://janet-lang.org/docs/specials.html\n\n"))
|
||||
|
||||
(defn doc*
|
||||
"Get the documentation for a symbol in a given environment. Function form of `doc`."
|
||||
|
@ -3853,9 +3859,11 @@
|
|||
:lazy lazy
|
||||
:map-symbols map-symbols}))
|
||||
|
||||
(defmacro ffi/defbind
|
||||
"Generate bindings for native functions in a convenient manner."
|
||||
[name ret-type & body]
|
||||
(defmacro ffi/defbind-alias
|
||||
"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."
|
||||
[name alias ret-type & body]
|
||||
(def real-ret-type (eval ret-type))
|
||||
(def meta (slice body 0 -2))
|
||||
(def arg-pairs (partition 2 (last body)))
|
||||
|
@ -3872,11 +3880,16 @@
|
|||
(defn make-ptr []
|
||||
(assert (ffi/lookup (if lazy (llib) lib) raw-symbol) (string "failed to find ffi symbol " raw-symbol)))
|
||||
(if lazy
|
||||
~(defn ,name ,;meta [,;formal-args]
|
||||
~(defn ,alias ,;meta [,;formal-args]
|
||||
(,ffi/call (,(delay (make-ptr))) (,(delay (make-sig))) ,;formal-args))
|
||||
~(defn ,name ,;meta [,;formal-args]
|
||||
~(defn ,alias ,;meta [,;formal-args]
|
||||
(,ffi/call ,(make-ptr) ,(make-sig) ,;formal-args)))))
|
||||
|
||||
(defmacro ffi/defbind
|
||||
"Generate bindings for native functions in a convenient manner."
|
||||
[name ret-type & body]
|
||||
~(ffi/defbind-alias ,name ,name ,ret-type ,;body))
|
||||
|
||||
###
|
||||
###
|
||||
### Flychecking
|
||||
|
@ -4020,6 +4033,28 @@
|
|||
(def x (in args (+ i 1)))
|
||||
(or (scan-number x) (keyword x)))
|
||||
|
||||
(def- long-to-short
|
||||
"map long options to short options"
|
||||
{"-help" "h"
|
||||
"-version" "v"
|
||||
"-stdin" "s"
|
||||
"-eval" "e"
|
||||
"-expression" "E"
|
||||
"-debug" "d"
|
||||
"-repl" "r"
|
||||
"-noprofile" "R"
|
||||
"-persistent" "p"
|
||||
"-quiet" "q"
|
||||
"-flycheck" "k"
|
||||
"-syspath" "m"
|
||||
"-compile" "c"
|
||||
"-image" "i"
|
||||
"-nocolor" "n"
|
||||
"-color" "N"
|
||||
"-library" "l"
|
||||
"-lint-warn" "w"
|
||||
"-lint-error" "x"})
|
||||
|
||||
# Flag handlers
|
||||
(def handlers
|
||||
{"h" (fn [&]
|
||||
|
@ -4027,26 +4062,26 @@
|
|||
(print
|
||||
```
|
||||
Options are:
|
||||
-h : Show this help
|
||||
-v : Print the version string
|
||||
-s : Use raw stdin instead of getline like functionality
|
||||
-e code : Execute a string of janet
|
||||
-E code arguments... : Evaluate an expression as a short-fn with arguments
|
||||
-d : Set the debug flag in the REPL
|
||||
-r : Enter the REPL after running all scripts
|
||||
-R : Disables loading profile.janet when JANET_PROFILE is present
|
||||
-p : Keep on executing if there is a top-level error (persistent)
|
||||
-q : Hide logo (quiet)
|
||||
-k : Compile scripts but do not execute (flycheck)
|
||||
-m syspath : Set system path for loading global modules
|
||||
-c source output : Compile janet source code into an image
|
||||
-i : Load the script argument as an image file instead of source code
|
||||
-n : Disable ANSI color output in the REPL
|
||||
-N : Enable ANSI color output in the REPL
|
||||
-l lib : Use a module before processing more arguments
|
||||
-w level : Set the lint warning level - default is "normal"
|
||||
-x level : Set the lint error level - default is "none"
|
||||
-- : Stop handling options
|
||||
--help (-h) : Show this help
|
||||
--version (-v) : Print the version string
|
||||
--stdin (-s) : Use raw stdin instead of getline like functionality
|
||||
--eval (-e) code : Execute a string of janet
|
||||
--expression (-E) code arguments... : Evaluate an expression as a short-fn with arguments
|
||||
--debug (-d) : Set the debug flag in the REPL
|
||||
--repl (-r) : Enter the REPL after running all scripts
|
||||
--noprofile (-R) : Disables loading profile.janet when JANET_PROFILE is present
|
||||
--persistent (-p) : Keep on executing if there is a top-level error (persistent)
|
||||
--quiet (-q) : Hide logo (quiet)
|
||||
--flycheck (-k) : Compile scripts but do not execute (flycheck)
|
||||
--syspath (-m) syspath : Set system path for loading global modules
|
||||
--compile (-c) source output : Compile janet source code into an image
|
||||
--image (-i) : Load the script argument as an image file instead of source code
|
||||
--nocolor (-n) : Disable ANSI color output in the REPL
|
||||
--color (-N) : Enable ANSI color output in the REPL
|
||||
--library (-l) lib : Use a module before processing more arguments
|
||||
--lint-warn (-w) level : Set the lint warning level - default is "normal"
|
||||
--lint-error (-x) level : Set the lint error level - default is "none"
|
||||
-- : Stop handling options
|
||||
```)
|
||||
(os/exit 0)
|
||||
1)
|
||||
|
@ -4090,8 +4125,8 @@
|
|||
"R" (fn [&] (setdyn *profilepath* nil) 1)})
|
||||
|
||||
(defn- dohandler [n i &]
|
||||
(def h (in handlers n))
|
||||
(if h (h i) (do (print "unknown flag -" n) ((in handlers "h")))))
|
||||
(def h (in handlers (get long-to-short n n)))
|
||||
(if h (h i handlers) (do (print "unknown flag -" n) ((in handlers "h")))))
|
||||
|
||||
# Process arguments
|
||||
(var i 0)
|
||||
|
|
|
@ -655,6 +655,27 @@ JANET_CORE_FN(cfun_buffer_format,
|
|||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_format_at,
|
||||
"(buffer/format-at buffer at format & args)",
|
||||
"Snprintf like functionality for printing values into a buffer. Returns "
|
||||
"the modified buffer.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t at = janet_getinteger(argv, 1);
|
||||
if (at < 0) {
|
||||
at += buffer->count + 1;
|
||||
}
|
||||
if (at > buffer->count || at < 0) janet_panicf("expected index at to be in range [0, %d), got %d", buffer->count, at);
|
||||
int32_t oldcount = buffer->count;
|
||||
buffer->count = at;
|
||||
const char *strfrmt = (const char *) janet_getstring(argv, 2);
|
||||
janet_buffer_format(buffer, strfrmt, 2, argc, argv);
|
||||
if (buffer->count < oldcount) {
|
||||
buffer->count = oldcount;
|
||||
}
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
void janet_lib_buffer(JanetTable *env) {
|
||||
JanetRegExt buffer_cfuns[] = {
|
||||
JANET_CORE_REG("buffer/new", cfun_buffer_new),
|
||||
|
@ -681,6 +702,7 @@ void janet_lib_buffer(JanetTable *env) {
|
|||
JANET_CORE_REG("buffer/bit-toggle", cfun_buffer_bittoggle),
|
||||
JANET_CORE_REG("buffer/blit", cfun_buffer_blit),
|
||||
JANET_CORE_REG("buffer/format", cfun_buffer_format),
|
||||
JANET_CORE_REG("buffer/format-at", cfun_buffer_format_at),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, buffer_cfuns);
|
||||
|
|
|
@ -69,15 +69,15 @@ JanetModule janet_native(const char *name, const uint8_t **error) {
|
|||
host.minor < modconf.minor ||
|
||||
host.bits != modconf.bits) {
|
||||
char errbuf[128];
|
||||
sprintf(errbuf, "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
|
||||
host.major,
|
||||
host.minor,
|
||||
host.patch,
|
||||
host.bits,
|
||||
modconf.major,
|
||||
modconf.minor,
|
||||
modconf.patch,
|
||||
modconf.bits);
|
||||
snprintf(errbuf, sizeof(errbuf), "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
|
||||
host.major,
|
||||
host.minor,
|
||||
host.patch,
|
||||
host.bits,
|
||||
modconf.major,
|
||||
modconf.minor,
|
||||
modconf.patch,
|
||||
modconf.bits);
|
||||
*error = janet_cstring(errbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -279,8 +279,16 @@ void janet_async_in_flight(JanetFiber *fiber) {
|
|||
void janet_async_start(JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, void *state) {
|
||||
JanetFiber *fiber = janet_vm.root_fiber;
|
||||
janet_assert(!fiber->ev_callback, "double async on fiber");
|
||||
if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber;
|
||||
if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber;
|
||||
if (mode & JANET_ASYNC_LISTEN_READ) {
|
||||
stream->read_fiber = fiber;
|
||||
} else {
|
||||
stream->read_fiber = NULL;
|
||||
}
|
||||
if (mode & JANET_ASYNC_LISTEN_WRITE) {
|
||||
stream->write_fiber = fiber;
|
||||
} else {
|
||||
stream->write_fiber = NULL;
|
||||
}
|
||||
fiber->ev_callback = callback;
|
||||
fiber->ev_stream = stream;
|
||||
janet_ev_inc_refcount();
|
||||
|
@ -462,6 +470,12 @@ static Janet janet_stream_next(void *p, Janet key) {
|
|||
return janet_nextmethod(stream->methods, key);
|
||||
}
|
||||
|
||||
static void janet_stream_tostring(void *p, JanetBuffer *buffer) {
|
||||
JanetStream *stream = p;
|
||||
/* Let user print the file descriptor for debugging */
|
||||
janet_formatb(buffer, "<core/stream handle=%d>", stream->handle);
|
||||
}
|
||||
|
||||
const JanetAbstractType janet_stream_type = {
|
||||
"core/stream",
|
||||
janet_stream_gc,
|
||||
|
@ -470,7 +484,7 @@ const JanetAbstractType janet_stream_type = {
|
|||
NULL,
|
||||
janet_stream_marshal,
|
||||
janet_stream_unmarshal,
|
||||
NULL,
|
||||
janet_stream_tostring,
|
||||
NULL,
|
||||
NULL,
|
||||
janet_stream_next,
|
||||
|
@ -1516,6 +1530,14 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
|||
}
|
||||
}
|
||||
|
||||
void janet_stream_edge_triggered(JanetStream *stream) {
|
||||
(void) stream;
|
||||
}
|
||||
|
||||
void janet_stream_level_triggered(JanetStream *stream) {
|
||||
(void) stream;
|
||||
}
|
||||
|
||||
#elif defined(JANET_EV_EPOLL)
|
||||
|
||||
static JanetTimestamp ts_now(void) {
|
||||
|
@ -1527,15 +1549,15 @@ static JanetTimestamp ts_now(void) {
|
|||
}
|
||||
|
||||
/* Wait for the next event */
|
||||
static void janet_register_stream(JanetStream *stream) {
|
||||
static void janet_register_stream_impl(JanetStream *stream, int mod, int edge_trigger) {
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLET;
|
||||
ev.events = edge_trigger ? EPOLLET : 0;
|
||||
if (stream->flags & (JANET_STREAM_READABLE | JANET_STREAM_ACCEPTABLE)) ev.events |= EPOLLIN;
|
||||
if (stream->flags & JANET_STREAM_WRITABLE) ev.events |= EPOLLOUT;
|
||||
ev.data.ptr = stream;
|
||||
int status;
|
||||
do {
|
||||
status = epoll_ctl(janet_vm.epoll, EPOLL_CTL_ADD, stream->handle, &ev);
|
||||
status = epoll_ctl(janet_vm.epoll, mod ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, stream->handle, &ev);
|
||||
} while (status == -1 && errno == EINTR);
|
||||
if (status == -1) {
|
||||
if (errno == EPERM) {
|
||||
|
@ -1549,6 +1571,18 @@ static void janet_register_stream(JanetStream *stream) {
|
|||
}
|
||||
}
|
||||
|
||||
static void janet_register_stream(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 0, 1);
|
||||
}
|
||||
|
||||
void janet_stream_edge_triggered(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 1, 1);
|
||||
}
|
||||
|
||||
void janet_stream_level_triggered(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 1, 0);
|
||||
}
|
||||
|
||||
#define JANET_EPOLL_MAX_EVENTS 64
|
||||
void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
struct itimerspec its;
|
||||
|
@ -1678,14 +1712,15 @@ static void timestamp2timespec(struct timespec *t, JanetTimestamp ts) {
|
|||
t->tv_nsec = ts == 0 ? 0 : (ts % 1000) * 1000000;
|
||||
}
|
||||
|
||||
void janet_register_stream(JanetStream *stream) {
|
||||
void janet_register_stream_impl(JanetStream *stream, int edge_trigger) {
|
||||
struct kevent kevs[2];
|
||||
int length = 0;
|
||||
int clear = edge_trigger ? EV_CLEAR : 0;
|
||||
if (stream->flags & (JANET_STREAM_READABLE | JANET_STREAM_ACCEPTABLE)) {
|
||||
EV_SETx(&kevs[length++], stream->handle, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, stream);
|
||||
EV_SETx(&kevs[length++], stream->handle, EVFILT_READ, EV_ADD | EV_ENABLE | clear, 0, 0, stream);
|
||||
}
|
||||
if (stream->flags & JANET_STREAM_WRITABLE) {
|
||||
EV_SETx(&kevs[length++], stream->handle, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, stream);
|
||||
EV_SETx(&kevs[length++], stream->handle, EVFILT_WRITE, EV_ADD | EV_ENABLE | clear, 0, 0, stream);
|
||||
}
|
||||
int status;
|
||||
do {
|
||||
|
@ -1696,6 +1731,18 @@ void janet_register_stream(JanetStream *stream) {
|
|||
}
|
||||
}
|
||||
|
||||
void janet_register_stream(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 1);
|
||||
}
|
||||
|
||||
void janet_stream_edge_triggered(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 1);
|
||||
}
|
||||
|
||||
void janet_stream_level_triggered(JanetStream *stream) {
|
||||
janet_register_stream_impl(stream, 0);
|
||||
}
|
||||
|
||||
#define JANET_KQUEUE_MAX_EVENTS 64
|
||||
|
||||
void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
|
@ -1818,15 +1865,30 @@ void janet_register_stream(JanetStream *stream) {
|
|||
janet_vm.stream_count = new_count;
|
||||
}
|
||||
|
||||
void janet_stream_edge_triggered(JanetStream *stream) {
|
||||
(void) stream;
|
||||
}
|
||||
|
||||
void janet_stream_level_triggered(JanetStream *stream) {
|
||||
(void) stream;
|
||||
}
|
||||
|
||||
void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
|
||||
/* set event flags */
|
||||
for (size_t i = 0; i < janet_vm.stream_count; i++) {
|
||||
JanetStream *stream = janet_vm.streams[i];
|
||||
janet_vm.fds[i + 1].events = 0;
|
||||
janet_vm.fds[i + 1].revents = 0;
|
||||
if (stream->read_fiber && stream->read_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLIN;
|
||||
if (stream->write_fiber && stream->write_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLOUT;
|
||||
struct pollfd *pfd = janet_vm.fds + i + 1;
|
||||
pfd->events = 0;
|
||||
pfd->revents = 0;
|
||||
JanetFiber *rf = stream->read_fiber;
|
||||
JanetFiber *wf = stream->write_fiber;
|
||||
if (rf && rf->ev_callback) pfd->events |= POLLIN;
|
||||
if (wf && wf->ev_callback) pfd->events |= POLLOUT;
|
||||
/* Hack to ignore a file descriptor - make file descriptor negative if we want to ignore */
|
||||
if (!pfd->events) {
|
||||
pfd->fd = -pfd->fd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Poll for events */
|
||||
|
@ -1843,6 +1905,14 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
|||
JANET_EXIT("failed to poll events");
|
||||
}
|
||||
|
||||
/* Undo negative hack */
|
||||
for (size_t i = 0; i < janet_vm.stream_count; i++) {
|
||||
struct pollfd *pfd = janet_vm.fds + i + 1;
|
||||
if (pfd->fd < 0) {
|
||||
pfd->fd = -pfd->fd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check selfpipe */
|
||||
if (janet_vm.fds[0].revents & POLLIN) {
|
||||
janet_vm.fds[0].revents = 0;
|
||||
|
|
|
@ -73,13 +73,13 @@ static void *int64_unmarshal(JanetMarshalContext *ctx) {
|
|||
|
||||
static void it_s64_tostring(void *p, JanetBuffer *buffer) {
|
||||
char str[32];
|
||||
sprintf(str, "%" PRId64, *((int64_t *)p));
|
||||
snprintf(str, sizeof(str), "%" PRId64, *((int64_t *)p));
|
||||
janet_buffer_push_cstring(buffer, str);
|
||||
}
|
||||
|
||||
static void it_u64_tostring(void *p, JanetBuffer *buffer) {
|
||||
char str[32];
|
||||
sprintf(str, "%" PRIu64, *((uint64_t *)p));
|
||||
snprintf(str, sizeof(str), "%" PRIu64, *((uint64_t *)p));
|
||||
janet_buffer_push_cstring(buffer, str);
|
||||
}
|
||||
|
||||
|
|
|
@ -319,6 +319,7 @@ JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunctio
|
|||
NetStateAccept *state = janet_malloc(sizeof(NetStateAccept));
|
||||
memset(state, 0, sizeof(NetStateAccept));
|
||||
state->function = fun;
|
||||
if (fun) janet_stream_level_triggered(stream);
|
||||
janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state);
|
||||
}
|
||||
|
||||
|
|
|
@ -1597,13 +1597,13 @@ JANET_CORE_FN(os_clock,
|
|||
|
||||
JanetKeyword formatstr = janet_optkeyword(argv, argc, 1, (const uint8_t *) "double");
|
||||
if (janet_cstrcmp(formatstr, "double") == 0) {
|
||||
double dtime = tv.tv_sec + (tv.tv_nsec / 1E9);
|
||||
double dtime = (double)(tv.tv_sec + (tv.tv_nsec / 1E9));
|
||||
return janet_wrap_number(dtime);
|
||||
} else if (janet_cstrcmp(formatstr, "int") == 0) {
|
||||
return janet_wrap_number(tv.tv_sec);
|
||||
return janet_wrap_number((double)(tv.tv_sec));
|
||||
} else if (janet_cstrcmp(formatstr, "tuple") == 0) {
|
||||
Janet tup[2] = {janet_wrap_integer(tv.tv_sec),
|
||||
janet_wrap_integer(tv.tv_nsec)
|
||||
Janet tup[2] = {janet_wrap_number((double)tv.tv_sec),
|
||||
janet_wrap_number((double)tv.tv_nsec)
|
||||
};
|
||||
return janet_wrap_tuple(janet_tuple_n(tup, 2));
|
||||
} else {
|
||||
|
|
|
@ -830,7 +830,7 @@ static const char *scanformat(
|
|||
if (loc != NULL && *loc != '\0') {
|
||||
const char *mapping = get_fmt_mapping(*p2++);
|
||||
size_t len = strlen(mapping);
|
||||
strcpy(form, mapping);
|
||||
memcpy(form, mapping, len);
|
||||
form += len;
|
||||
} else {
|
||||
*(form++) = *(p2++);
|
||||
|
|
|
@ -112,7 +112,8 @@ extern "C" {
|
|||
|| defined(__s390x__) /* S390 64-bit (BE) */ \
|
||||
|| (defined(__ppc64__) || defined(__PPC64__)) \
|
||||
|| defined(__aarch64__) /* ARM 64-bit */ \
|
||||
|| (defined(__riscv) && (__riscv_xlen == 64)) /* RISC-V 64-bit */
|
||||
|| (defined(__riscv) && (__riscv_xlen == 64)) /* RISC-V 64-bit */ \
|
||||
|| defined(__loongarch64) /* LoongArch64 64-bit */
|
||||
#define JANET_64 1
|
||||
#else
|
||||
#define JANET_32 1
|
||||
|
@ -636,6 +637,12 @@ JANET_API void janet_async_end(JanetFiber *fiber);
|
|||
/* Needed for windows to mark a fiber as waiting for an IOCP completion event. Noop on other platforms. */
|
||||
JANET_API void janet_async_in_flight(JanetFiber *fiber);
|
||||
|
||||
/* On some platforms, it is important to be able to control if a stream is edge-trigger or level triggered.
|
||||
* For example, a server that is accepting connections might want to be level triggered or edge-triggered
|
||||
* depending on expected service. */
|
||||
JANET_API void janet_stream_edge_triggered(JanetStream *stream);
|
||||
JANET_API void janet_stream_level_triggered(JanetStream *stream);
|
||||
|
||||
#endif
|
||||
|
||||
/* Janet uses atomic integers in several places for synchronization between threads and
|
||||
|
|
|
@ -976,4 +976,7 @@
|
|||
(assert (= () '() (macex '())) "macex ()")
|
||||
(assert (= '[] (macex '[])) "macex []")
|
||||
|
||||
(assert (= :a (with-env @{:b :a} (dyn :b))) "with-env dyn")
|
||||
(assert-error "unknown symbol +" (with-env @{} (eval '(+ 1 2))))
|
||||
|
||||
(end-suite)
|
||||
|
|
|
@ -162,5 +162,20 @@
|
|||
(assert (deep= @"abc423" (buffer/push-at @"abc123" 3 "4"))
|
||||
"buffer/push-at 3")
|
||||
|
||||
# buffer/format-at
|
||||
(def start-buf (buffer/new-filled 100 (chr "x")))
|
||||
(buffer/format-at start-buf 50 "aa%dbb" 32)
|
||||
(assert (= (string start-buf) (string (string/repeat "x" 50) "aa32bb" (string/repeat "x" 44)))
|
||||
"buffer/format-at 1")
|
||||
(assert
|
||||
(deep=
|
||||
(buffer/format @"" "%j" [1 2 3 :a :b :c])
|
||||
(buffer/format-at @"" 0 "%j" [1 2 3 :a :b :c]))
|
||||
"buffer/format-at empty buffer")
|
||||
(def buf @"xxxyyy")
|
||||
(buffer/format-at buf -4 "xxx")
|
||||
(assert (= (string buf) "xxxxxx") "buffer/format-at negative index")
|
||||
(assert-error "expected index at to be in range [0, 0), got 1" (buffer/format-at @"" 1 "abc"))
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
|
Loading…
Reference in New Issue