mirror of
https://github.com/janet-lang/janet
synced 2025-10-29 06:37:41 +00:00
Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fda0a081f5 | ||
|
|
94b7a69741 | ||
|
|
6518257129 | ||
|
|
dc325188d0 | ||
|
|
0b51ab157d | ||
|
|
f95de25b15 | ||
|
|
f424f2936b | ||
|
|
2d6c2ee7c0 | ||
|
|
7cd106a10c | ||
|
|
0d9e999113 | ||
|
|
75710ccabd | ||
|
|
0f60115f27 | ||
|
|
16a3c85baa | ||
|
|
92ff1d3be4 | ||
|
|
58441dc49f | ||
|
|
dbc5d688e2 | ||
|
|
e2a8951f68 | ||
|
|
f0f03ad519 | ||
|
|
e37575e763 | ||
|
|
f4fd481415 | ||
|
|
8fca6b7af4 | ||
|
|
600e822933 | ||
|
|
2028ac8a20 | ||
|
|
7bae7d9efd | ||
|
|
cb54fb02c1 | ||
|
|
7529abb542 | ||
|
|
16ac681ed9 | ||
|
|
74560ff805 | ||
|
|
fe348187cc | ||
|
|
fd5315793c | ||
|
|
87db463f4e | ||
|
|
1225cd31c8 | ||
|
|
6998865d7b | ||
|
|
b8aec50763 | ||
|
|
7efb39d608 | ||
|
|
f7c90bc1ff | ||
|
|
aee077c1bd | ||
|
|
6968275ddf | ||
|
|
074ae4fc0d | ||
|
|
6cd35ed9c8 | ||
|
|
7911e74222 | ||
|
|
2fafe2b5d1 | ||
|
|
de977819ce | ||
|
|
1844beecc3 | ||
|
|
cb529bbd63 | ||
|
|
25990867e2 | ||
|
|
4fbc71c70d | ||
|
|
eb21d4fff4 | ||
|
|
6d5fc1d743 | ||
|
|
e88042b2fa | ||
|
|
750b448f75 | ||
|
|
14d1dc8749 | ||
|
|
8e0340252b | ||
|
|
641a16c133 | ||
|
|
533d78bffe | ||
|
|
ae2c5820a1 | ||
|
|
8334504f4e | ||
|
|
2260a593bd | ||
|
|
7d8af2f99a | ||
|
|
46bdcece4d | ||
|
|
7387a1d91e | ||
|
|
ae4b8078df | ||
|
|
60e0c8ea92 | ||
|
|
7d3acc0ed6 | ||
|
|
2637b33957 | ||
|
|
58ccb66659 | ||
|
|
634429cf61 | ||
|
|
6ac65e603d | ||
|
|
03166a745a | ||
|
|
4d61ba20ce | ||
|
|
751ff677fe | ||
|
|
ace60e1898 | ||
|
|
876b7f106f | ||
|
|
809b6589a1 | ||
|
|
02f53ca014 | ||
|
|
0b03ddb21b | ||
|
|
ea5d4fd3af | ||
|
|
e6b73f8cd1 | ||
|
|
af232ef729 | ||
|
|
2e2f8abfc0 | ||
|
|
91a583db27 | ||
|
|
dc5cc630ff | ||
|
|
c1647a74c5 | ||
|
|
721f280966 | ||
|
|
258ebb9145 | ||
|
|
e914eaf055 | ||
|
|
fe54013679 | ||
|
|
fdaf2e1594 | ||
|
|
f0092ef69b | ||
|
|
a88ae7e1d9 | ||
|
|
9946f3bdf4 | ||
|
|
c747e8d16c | ||
|
|
3e402d397e | ||
|
|
0350834cd3 | ||
|
|
980981c9ee | ||
|
|
3c8346f24e | ||
|
|
42bd27c24b | ||
|
|
4a0f67f3bd | ||
|
|
09b6fc4670 | ||
|
|
4d9bcd6bcc | ||
|
|
cd34b89977 | ||
|
|
3151fa3988 | ||
|
|
5e58110e19 | ||
|
|
e1cdd0f8cc | ||
|
|
1f39a0f180 | ||
|
|
367c4b14f5 | ||
|
|
9c437796d3 | ||
|
|
60e22d9703 | ||
|
|
ee7362e847 | ||
|
|
369f96b80e | ||
|
|
7c5ed04ab1 | ||
|
|
4779a445e0 | ||
|
|
f0f1b7ce9e | ||
|
|
7c9157a0ed | ||
|
|
522a6cb435 | ||
|
|
d0d551d739 | ||
|
|
71a123fef7 | ||
|
|
3f40c8d7fb | ||
|
|
983c2e5499 | ||
|
|
eebb4c3ade | ||
|
|
50425eac72 | ||
|
|
382ff77bbe | ||
|
|
bf680fb5d3 | ||
|
|
4ed7db4f91 | ||
|
|
bf19920d65 | ||
|
|
174b5f6686 | ||
|
|
4173645b81 | ||
|
|
af511f1f55 | ||
|
|
83c6080380 | ||
|
|
2f0c789ea1 | ||
|
|
a9b8f8e8a9 | ||
|
|
f92f3eb6fa | ||
|
|
89e74dca3e | ||
|
|
f2e86d2f8d | ||
|
|
623da131e5 | ||
|
|
e89ec31ae5 | ||
|
|
68a6ed208e | ||
|
|
c01b32c4f3 | ||
|
|
ee11ff9da9 | ||
|
|
ed56d5d6ff | ||
|
|
b317ab755c | ||
|
|
9819994999 | ||
|
|
e9dbaa81d2 | ||
|
|
9f9146ffae | ||
|
|
9d9732af97 | ||
|
|
ebb8fa9787 | ||
|
|
9e6abbf4d4 | ||
|
|
6032a6d658 | ||
|
|
c29ab22e6d | ||
|
|
592ac4904c | ||
|
|
03ae2ec153 | ||
|
|
3bc42d0d37 | ||
|
|
12630d3e54 | ||
|
|
c9897f99c3 | ||
|
|
e66dc14b3a | ||
|
|
7a2868c147 | ||
|
|
9e0daaee09 | ||
|
|
c293c7de93 | ||
|
|
49eb5f8563 | ||
|
|
674b375b2c | ||
|
|
7e94c091eb | ||
|
|
5885ccba61 | ||
|
|
431ecd3d1a | ||
|
|
f6df8ff935 | ||
|
|
3fd70f0951 | ||
|
|
bebb635d4f | ||
|
|
354896bc4b | ||
|
|
5ddefff27e | ||
|
|
91827eef4f | ||
|
|
9c14c09962 | ||
|
|
e85a84171f | ||
|
|
3a4f86c3d7 | ||
|
|
5e75963312 | ||
|
|
184d9289b5 | ||
|
|
b7ff9577c0 | ||
|
|
942a1aaac6 | ||
|
|
69f0fe004d | ||
|
|
2a04347a42 | ||
|
|
1394f1a5c0 | ||
|
|
cf4d19a8ea | ||
|
|
23b0fe9f8e | ||
|
|
1ba718b15e | ||
|
|
df5f79ff35 | ||
|
|
6d7e8528ea | ||
|
|
197bb73a62 | ||
|
|
61f38fab37 |
@@ -1,4 +1,4 @@
|
||||
image: freebsd/12.x
|
||||
image: freebsd/14.x
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
image: openbsd/latest
|
||||
image: openbsd/7.4
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
|
||||
38
.github/cosmo/build
vendored
Normal file
38
.github/cosmo/build
vendored
Normal file
@@ -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
|
||||
21
.github/cosmo/setup
vendored
Normal file
21
.github/cosmo/setup
vendored
Normal file
@@ -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"
|
||||
27
.github/workflows/release.yml
vendored
27
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: Compile the project
|
||||
run: make clean && make CC=x86_64-w64-mingw32-gcc LD=x86_64-w64-mingw32-gcc UNAME=MINGW RUN=wine
|
||||
- name: Test the project
|
||||
run: make test UNAME=MINGW RUN=wine
|
||||
run: make test UNAME=MINGW RUN=wine VERBOSE=1
|
||||
|
||||
test-arm-linux:
|
||||
name: Build and test ARM32 cross compilation
|
||||
@@ -88,4 +88,4 @@ jobs:
|
||||
- name: Compile the project
|
||||
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-gcc
|
||||
- name: Test the project
|
||||
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" SUBRUN="qemu-arm -L /usr/arm-linux-gnueabi/" test
|
||||
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" SUBRUN="qemu-arm -L /usr/arm-linux-gnueabi/" test VERBOSE=1
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -48,6 +48,8 @@ janet.wasm
|
||||
# Generated files
|
||||
*.gen.h
|
||||
*.gen.c
|
||||
*.tmp
|
||||
temp.*
|
||||
|
||||
# Generate test files
|
||||
*.out
|
||||
@@ -126,6 +128,9 @@ vgcore.*
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# GGov
|
||||
*.gcov
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
@@ -134,6 +139,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
|
||||
|
||||
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,7 +1,39 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.33.0 - 2023-01-07
|
||||
## 1.35.2 - 2024-06-16
|
||||
- Fix some documentation typos.
|
||||
- Allow using `:only` in import without quoting.
|
||||
|
||||
## 1.35.0 - 2024-06-15
|
||||
- Add `:only` argument to `import` to allow for easier control over imported bindings.
|
||||
- Add extra optional `env` argument to `eval` and `eval-string`.
|
||||
- Allow naming function literals with a keyword. This allows better stacktraces for macros without
|
||||
accidentally adding new bindings.
|
||||
- Add `bundle/` module for managing packages within Janet. This should replace the jpm packaging
|
||||
format eventually and is much simpler and amenable to more complicated builds.
|
||||
- Add macros `ev/with-lock`, `ev/with-rlock`, and `ev/with-wlock` for using mutexes and rwlocks.
|
||||
- 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
|
||||
- Documentation improvements: @amano-kenji, @llmII, @MaxGyver83, @pepe, @sogaiu.
|
||||
- Expose _exit to skip certain cleanup with os/exit.
|
||||
- Swap set / body order for each by @sogaiu.
|
||||
- Abort on assert failure instead of exit.
|
||||
- Fix: os/proc-wait by @llmII.
|
||||
- Fix macex1 to keep syntax location for all tuples.
|
||||
- Restore if-let tail calls.
|
||||
- Don't try and resume fibers that can't be resumed.
|
||||
- Register stream on unmarshal.
|
||||
- Fix asm roundtrip issue.
|
||||
|
||||
## 1.33.0 - 2024-01-07
|
||||
- Add more + and * keywords to default-peg-grammar by @sogaiu.
|
||||
- Use libc strlen in janet_buffer_push_cstring by @williewillus.
|
||||
- Be a bit safer with reference counting.
|
||||
@@ -86,7 +118,7 @@ All notable changes to this project will be documented in this file.
|
||||
See http://no-color.org/
|
||||
- Disallow using `(splice x)` in contexts where it doesn't make sense rather than silently coercing to `x`.
|
||||
Instead, raise a compiler error.
|
||||
- Change the names of `:user8` and `:user9` sigals to `:interrupt` and `:await`
|
||||
- Change the names of `:user8` and `:user9` signals to `:interrupt` and `:await`
|
||||
- Change the names of `:user8` and `:user9` fiber statuses to `:interrupted` and `:suspended`.
|
||||
- Add `ev/all-tasks` to see all currently suspended fibers.
|
||||
- Add `keep-syntax` and `keep-syntax!` functions to make writing macros easier.
|
||||
@@ -257,7 +289,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Add the ability to close channels with `ev/chan-close` (or `:close`).
|
||||
- Add threaded channels with `ev/thread-chan`.
|
||||
- Add `JANET_FN` and `JANET_REG` macros to more easily define C functions that export their source mapping information.
|
||||
- Add `janet_interpreter_interupt` and `janet_loop1_interrupt` to interrupt the interpreter while running.
|
||||
- Add `janet_interpreter_interrupt` and `janet_loop1_interrupt` to interrupt the interpreter while running.
|
||||
- Add `table/clear`
|
||||
- Add build option to disable the threading library without disabling all threads.
|
||||
- Remove JPM from the main Janet distribution. Instead, JPM must be installed
|
||||
@@ -311,7 +343,7 @@ saving and restoring the entire VM state.
|
||||
- Sort keys in pretty printing output.
|
||||
|
||||
## 1.15.3 - 2021-02-28
|
||||
- Fix a fiber bug that occured in deeply nested fibers
|
||||
- Fix a fiber bug that occurred in deeply nested fibers
|
||||
- Add `unref` combinator to pegs.
|
||||
- Small docstring changes.
|
||||
|
||||
@@ -461,13 +493,13 @@ saving and restoring the entire VM state.
|
||||
- Add `symbol/slice`
|
||||
- Add `keyword/slice`
|
||||
- Allow cross compilation with Makefile.
|
||||
- Change `compare-primitve` to `cmp` and make it more efficient.
|
||||
- Change `compare-primitive` to `cmp` and make it more efficient.
|
||||
- Add `reverse!` for reversing an array or buffer in place.
|
||||
- `janet_dobytes` and `janet_dostring` return parse errors in \*out
|
||||
- Add `repeat` macro for iterating something n times.
|
||||
- Add `eachy` (each yield) macro for iterating a fiber.
|
||||
- Fix `:generate` verb in loop macro to accept non symbols as bindings.
|
||||
- Add `:h`, `:h+`, and `:h*` in `default-peg-grammar` for hexidecimal digits.
|
||||
- Add `:h`, `:h+`, and `:h*` in `default-peg-grammar` for hexadecimal digits.
|
||||
- Fix `%j` formatter to print numbers precisely (using the `%.17g` format string to printf).
|
||||
|
||||
## 1.10.1 - 2020-06-18
|
||||
|
||||
4
Makefile
4
Makefile
@@ -204,9 +204,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
|
||||
########################
|
||||
|
||||
ifeq ($(UNAME), Darwin)
|
||||
SONAME=libjanet.1.33.dylib
|
||||
SONAME=libjanet.1.35.dylib
|
||||
else
|
||||
SONAME=libjanet.so.1.33
|
||||
SONAME=libjanet.so.1.35
|
||||
endif
|
||||
|
||||
build/c/shell.c: src/mainclient/shell.c
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -91,7 +91,9 @@ exit /b 0
|
||||
:CLEAN
|
||||
del *.exe *.lib *.exp
|
||||
rd /s /q build
|
||||
rd /s /q dist
|
||||
if exist dist (
|
||||
rd /s /q dist
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
@rem Run tests
|
||||
|
||||
@@ -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)))
|
||||
|
||||
4
examples/sample-bundle/bundle/info.jdn
Normal file
4
examples/sample-bundle/bundle/info.jdn
Normal file
@@ -0,0 +1,4 @@
|
||||
@{
|
||||
:name "sample-bundle"
|
||||
:dependencies ["sample-dep1" "sample-dep2"]
|
||||
}
|
||||
3
examples/sample-bundle/bundle/init.janet
Normal file
3
examples/sample-bundle/bundle/init.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(defn install
|
||||
[manifest &]
|
||||
(bundle/add-file manifest "mymod.janet"))
|
||||
7
examples/sample-bundle/mymod.janet
Normal file
7
examples/sample-bundle/mymod.janet
Normal file
@@ -0,0 +1,7 @@
|
||||
(import dep1)
|
||||
(import dep2)
|
||||
|
||||
(defn myfn
|
||||
[x]
|
||||
(def y (dep2/function x))
|
||||
(dep1/function y))
|
||||
4
examples/sample-dep1/bundle/info.jdn
Normal file
4
examples/sample-dep1/bundle/info.jdn
Normal file
@@ -0,0 +1,4 @@
|
||||
@{
|
||||
:name "sample-dep1"
|
||||
:dependencies ["sample-dep2"]
|
||||
}
|
||||
3
examples/sample-dep1/bundle/init.janet
Normal file
3
examples/sample-dep1/bundle/init.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(defn install
|
||||
[manifest &]
|
||||
(bundle/add-file manifest "dep1.janet"))
|
||||
3
examples/sample-dep1/dep1.janet
Normal file
3
examples/sample-dep1/dep1.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(defn function
|
||||
[x]
|
||||
(+ x x))
|
||||
3
examples/sample-dep2/bundle/info.jdn
Normal file
3
examples/sample-dep2/bundle/info.jdn
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
:name "sample-dep2"
|
||||
}
|
||||
3
examples/sample-dep2/bundle/init.janet
Normal file
3
examples/sample-dep2/bundle/init.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(defn install
|
||||
[manifest &]
|
||||
(bundle/add-file manifest "dep2.janet"))
|
||||
3
examples/sample-dep2/dep2.janet
Normal file
3
examples/sample-dep2/dep2.janet
Normal file
@@ -0,0 +1,3 @@
|
||||
(defn function
|
||||
[x]
|
||||
(* x x))
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
project('janet', 'c',
|
||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.33.0')
|
||||
version : '1.35.2')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
@@ -249,6 +249,7 @@ test_files = [
|
||||
'test/suite-asm.janet',
|
||||
'test/suite-boot.janet',
|
||||
'test/suite-buffer.janet',
|
||||
'test/suite-bundle.janet',
|
||||
'test/suite-capi.janet',
|
||||
'test/suite-cfuns.janet',
|
||||
'test/suite-compile.janet',
|
||||
|
||||
@@ -17,8 +17,8 @@ option('processes', type : 'boolean', value : true)
|
||||
option('umask', type : 'boolean', value : true)
|
||||
option('realpath', type : 'boolean', value : true)
|
||||
option('simple_getline', type : 'boolean', value : false)
|
||||
option('epoll', type : 'boolean', value : false)
|
||||
option('kqueue', type : 'boolean', value : false)
|
||||
option('epoll', type : 'boolean', value : true)
|
||||
option('kqueue', type : 'boolean', value : true)
|
||||
option('interpreter_interrupt', type : 'boolean', value : true)
|
||||
option('ffi', type : 'boolean', value : true)
|
||||
option('ffi_jit', type : 'boolean', value : true)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,10 @@
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 33
|
||||
#define JANET_VERSION_PATCH 0
|
||||
#define JANET_VERSION_MINOR 35
|
||||
#define JANET_VERSION_PATCH 2
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.33.0"
|
||||
#define JANET_VERSION "1.35.2"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
/* #define JANET_NO_INTERPRETER_INTERRUPT */
|
||||
/* #define JANET_NO_IPV6 */
|
||||
/* #define JANET_NO_CRYPTORAND */
|
||||
/* #define JANET_USE_STDATOMIC */
|
||||
|
||||
/* Custom vm allocator support */
|
||||
/* #include <mimalloc.h> */
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#ifdef JANET_EV
|
||||
#ifdef JANET_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -560,6 +560,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
||||
x = janet_get1(s, janet_ckeywordv("vararg"));
|
||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
||||
|
||||
/* Initialize slotcount */
|
||||
def->slotcount = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG) + def->arity;
|
||||
|
||||
/* Check structarg */
|
||||
x = janet_get1(s, janet_ckeywordv("structarg"));
|
||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
@@ -784,8 +787,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
||||
}
|
||||
|
||||
/* Verify the func def */
|
||||
if (janet_verify(def)) {
|
||||
janet_asm_error(&a, "invalid assembly");
|
||||
int verify_status = janet_verify(def);
|
||||
if (verify_status) {
|
||||
janet_asm_errorv(&a, janet_formatc("invalid assembly (%d)", verify_status));
|
||||
}
|
||||
|
||||
/* Add final flags */
|
||||
|
||||
@@ -320,6 +320,143 @@ JANET_CORE_FN(cfun_buffer_chars,
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int should_reverse_bytes(const Janet *argv, int32_t argc) {
|
||||
JanetKeyword order_kw = janet_getkeyword(argv, argc);
|
||||
if (!janet_cstrcmp(order_kw, "le")) {
|
||||
#if JANET_BIG_ENDIAN
|
||||
return 1;
|
||||
#endif
|
||||
} else if (!janet_cstrcmp(order_kw, "be")) {
|
||||
#if JANET_LITTLE_ENDIAN
|
||||
return 1;
|
||||
#endif
|
||||
} else if (!janet_cstrcmp(order_kw, "native")) {
|
||||
return 0;
|
||||
} else {
|
||||
janet_panicf("expected endianness :le, :be or :native, got %v", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reverse_u32(uint8_t bytes[4]) {
|
||||
uint8_t temp;
|
||||
temp = bytes[3];
|
||||
bytes[3] = bytes[0];
|
||||
bytes[0] = temp;
|
||||
temp = bytes[2];
|
||||
bytes[2] = bytes[1];
|
||||
bytes[1] = temp;
|
||||
}
|
||||
|
||||
static void reverse_u64(uint8_t bytes[8]) {
|
||||
uint8_t temp;
|
||||
temp = bytes[7];
|
||||
bytes[7] = bytes[0];
|
||||
bytes[0] = temp;
|
||||
temp = bytes[6];
|
||||
bytes[6] = bytes[1];
|
||||
bytes[1] = temp;
|
||||
temp = bytes[5];
|
||||
bytes[5] = bytes[2];
|
||||
bytes[2] = temp;
|
||||
temp = bytes[4];
|
||||
bytes[4] = bytes[3];
|
||||
bytes[3] = temp;
|
||||
}
|
||||
|
||||
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.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int reverse = should_reverse_bytes(argv, 1);
|
||||
union {
|
||||
uint16_t data;
|
||||
uint8_t bytes[2];
|
||||
} u;
|
||||
u.data = janet_getuinteger16(argv, 2);
|
||||
if (reverse) {
|
||||
uint8_t temp = u.bytes[1];
|
||||
u.bytes[1] = u.bytes[0];
|
||||
u.bytes[0] = temp;
|
||||
}
|
||||
janet_buffer_push_u16(buffer, *(uint16_t *) u.bytes);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
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.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int reverse = should_reverse_bytes(argv, 1);
|
||||
union {
|
||||
uint32_t data;
|
||||
uint8_t bytes[4];
|
||||
} u;
|
||||
u.data = janet_getuinteger(argv, 2);
|
||||
if (reverse)
|
||||
reverse_u32(u.bytes);
|
||||
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
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.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int reverse = should_reverse_bytes(argv, 1);
|
||||
union {
|
||||
uint64_t data;
|
||||
uint8_t bytes[8];
|
||||
} u;
|
||||
u.data = janet_getuinteger64(argv, 2);
|
||||
if (reverse)
|
||||
reverse_u64(u.bytes);
|
||||
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
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.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int reverse = should_reverse_bytes(argv, 1);
|
||||
union {
|
||||
float data;
|
||||
uint8_t bytes[4];
|
||||
} u;
|
||||
u.data = (float) janet_getnumber(argv, 2);
|
||||
if (reverse)
|
||||
reverse_u32(u.bytes);
|
||||
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
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.") {
|
||||
janet_fixarity(argc, 3);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int reverse = should_reverse_bytes(argv, 1);
|
||||
union {
|
||||
double data;
|
||||
uint8_t bytes[8];
|
||||
} u;
|
||||
u.data = janet_getnumber(argv, 2);
|
||||
if (reverse)
|
||||
reverse_u64(u.bytes);
|
||||
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) {
|
||||
for (int32_t i = argc_offset; i < argc; i++) {
|
||||
if (janet_checktype(argv[i], JANET_NUMBER)) {
|
||||
@@ -518,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),
|
||||
@@ -528,6 +686,11 @@ void janet_lib_buffer(JanetTable *env) {
|
||||
JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8),
|
||||
JANET_CORE_REG("buffer/push-word", cfun_buffer_word),
|
||||
JANET_CORE_REG("buffer/push-string", cfun_buffer_chars),
|
||||
JANET_CORE_REG("buffer/push-uint16", cfun_buffer_push_uint16),
|
||||
JANET_CORE_REG("buffer/push-uint32", cfun_buffer_push_uint32),
|
||||
JANET_CORE_REG("buffer/push-uint64", cfun_buffer_push_uint64),
|
||||
JANET_CORE_REG("buffer/push-float32", cfun_buffer_push_float32),
|
||||
JANET_CORE_REG("buffer/push-float64", cfun_buffer_push_float64),
|
||||
JANET_CORE_REG("buffer/push", cfun_buffer_push),
|
||||
JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at),
|
||||
JANET_CORE_REG("buffer/popn", cfun_buffer_popn),
|
||||
@@ -539,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);
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JANET_USE_STDATOMIC
|
||||
#include <stdatomic.h>
|
||||
/* We don't need stdatomic on most compilers since we use compiler builtins for atomic operations.
|
||||
* Some (TCC), explicitly require using stdatomic.h and don't have any exposed builtins (that I know of).
|
||||
* For TCC and similar compilers, one would need -std=c11 or similar then to get access. */
|
||||
#endif
|
||||
|
||||
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
|
||||
#ifdef JANET_TOP_LEVEL_SIGNAL
|
||||
JANET_TOP_LEVEL_SIGNAL(msg);
|
||||
@@ -296,11 +303,28 @@ int32_t janet_getinteger(const Janet *argv, int32_t n) {
|
||||
uint32_t janet_getuinteger(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkuint(x)) {
|
||||
janet_panicf("bad slot #%d, expected 32 bit signed integer, got %v", n, x);
|
||||
janet_panicf("bad slot #%d, expected 32 bit unsigned integer, got %v", n, x);
|
||||
}
|
||||
return janet_unwrap_integer(x);
|
||||
return (uint32_t) janet_unwrap_number(x);
|
||||
}
|
||||
|
||||
int16_t janet_getinteger16(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint16(x)) {
|
||||
janet_panicf("bad slot #%d, expected 16 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return (int16_t) janet_unwrap_number(x);
|
||||
}
|
||||
|
||||
uint16_t janet_getuinteger16(const Janet *argv, int32_t n) {
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkuint16(x)) {
|
||||
janet_panicf("bad slot #%d, expected 16 bit unsigned integer, got %v", n, x);
|
||||
}
|
||||
return (uint16_t) janet_unwrap_number(x);
|
||||
}
|
||||
|
||||
|
||||
int64_t janet_getinteger64(const Janet *argv, int32_t n) {
|
||||
#ifdef JANET_INT_TYPES
|
||||
return janet_unwrap_s64(argv[n]);
|
||||
@@ -496,6 +520,8 @@ void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetA
|
||||
JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
|
||||
#ifdef JANET_WINDOWS
|
||||
return InterlockedIncrement(x);
|
||||
#elif defined(JANET_USE_STDATOMIC)
|
||||
return atomic_fetch_add_explicit(x, 1, memory_order_relaxed) + 1;
|
||||
#else
|
||||
return __atomic_add_fetch(x, 1, __ATOMIC_RELAXED);
|
||||
#endif
|
||||
@@ -504,6 +530,8 @@ JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
|
||||
JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
|
||||
#ifdef JANET_WINDOWS
|
||||
return InterlockedDecrement(x);
|
||||
#elif defined(JANET_USE_STDATOMIC)
|
||||
return atomic_fetch_add_explicit(x, -1, memory_order_acq_rel) - 1;
|
||||
#else
|
||||
return __atomic_add_fetch(x, -1, __ATOMIC_ACQ_REL);
|
||||
#endif
|
||||
@@ -512,6 +540,8 @@ JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
|
||||
JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x) {
|
||||
#ifdef JANET_WINDOWS
|
||||
return InterlockedOr(x, 0);
|
||||
#elif defined(JANET_USE_STDATOMIC)
|
||||
return atomic_load_explicit(x, memory_order_acquire);
|
||||
#else
|
||||
return __atomic_load_n(x, __ATOMIC_ACQUIRE);
|
||||
#endif
|
||||
|
||||
@@ -934,7 +934,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
||||
int32_t slotchunks = (def->slotcount + 31) >> 5;
|
||||
/* numchunks is min of slotchunks and scope->ua.count */
|
||||
int32_t numchunks = slotchunks > scope->ua.count ? scope->ua.count : slotchunks;
|
||||
uint32_t *chunks = janet_calloc(sizeof(uint32_t), slotchunks);
|
||||
uint32_t *chunks = janet_calloc(slotchunks, sizeof(uint32_t));
|
||||
if (NULL == chunks) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -1056,7 +1056,7 @@ JanetCompileResult janet_compile_lint(Janet source,
|
||||
|
||||
if (c.result.status == JANET_COMPILE_OK) {
|
||||
JanetFuncDef *def = janetc_pop_funcdef(&c);
|
||||
def->name = janet_cstring("_thunk");
|
||||
def->name = janet_cstring("thunk");
|
||||
janet_def_addflags(def);
|
||||
c.result.funcdef = def;
|
||||
} else {
|
||||
|
||||
@@ -262,7 +262,7 @@ void janetc_popscope(JanetCompiler *c);
|
||||
void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot);
|
||||
JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c);
|
||||
|
||||
/* Create a destory slots */
|
||||
/* Create a destroy slot */
|
||||
JanetSlot janetc_cslot(Janet x);
|
||||
|
||||
/* Search for a symbol */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -110,14 +110,14 @@ JANET_CORE_FN(janet_core_expand_path,
|
||||
"(module/expand-path path template)",
|
||||
"Expands a path template as found in `module/paths` for `module/find`. "
|
||||
"This takes in a path (the argument to require) and a template string, "
|
||||
"to expand the path to a path that can be "
|
||||
"used for importing files. The replacements are as follows:\n\n"
|
||||
"to expand the path to a path that can be used for importing files. "
|
||||
"The replacements are as follows:\n\n"
|
||||
"* :all: -- the value of path verbatim.\n\n"
|
||||
"* :@all: -- Same as :all:, but if `path` starts with the @ character,\n"
|
||||
" the first path segment is replaced with a dynamic binding\n"
|
||||
" `(dyn <first path segment as keyword>)`.\n\n"
|
||||
"* :cur: -- the current file, or (dyn :current-file)\n\n"
|
||||
"* :dir: -- the directory containing the current file\n\n"
|
||||
"* :@all: -- Same as :all:, but if `path` starts with the @ character, "
|
||||
"the first path segment is replaced with a dynamic binding "
|
||||
"`(dyn <first path segment as keyword>)`.\n\n"
|
||||
"* :cur: -- the directory portion, if any, of (dyn :current-file)\n\n"
|
||||
"* :dir: -- the directory portion, if any, of the path argument\n\n"
|
||||
"* :name: -- the name component of path, with extension if given\n\n"
|
||||
"* :native: -- the extension used to load natives, .so or .dll\n\n"
|
||||
"* :sys: -- the system path, or (dyn :syspath)") {
|
||||
@@ -976,7 +976,7 @@ static void make_apply(JanetTable *env) {
|
||||
/* Push the array */
|
||||
S(JOP_PUSH_ARRAY, 5),
|
||||
|
||||
/* Call the funciton */
|
||||
/* Call the function */
|
||||
S(JOP_TAILCALL, 0)
|
||||
};
|
||||
janet_quick_asm(env, JANET_FUN_APPLY | JANET_FUNCDEF_FLAG_VARARG,
|
||||
@@ -1150,11 +1150,14 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
janet_quick_asm(env, JANET_FUN_PROP,
|
||||
"propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm),
|
||||
JDOC("(propagate x fiber)\n\n"
|
||||
"Propagate a signal from a fiber to the current fiber. The resulting "
|
||||
"stack trace from the current fiber will include frames from fiber. If "
|
||||
"fiber is in a state that can be resumed, resuming the current fiber will "
|
||||
"first resume fiber. This function can be used to re-raise an error without "
|
||||
"losing the original stack trace."));
|
||||
"Propagate a signal from a fiber to the current fiber and "
|
||||
"set the last value of the current fiber to `x`. The signal "
|
||||
"value is then available as the status of the current fiber. "
|
||||
"The resulting stack trace from the current fiber will include "
|
||||
"frames from fiber. If fiber is in a state that can be resumed, "
|
||||
"resuming the current fiber will first resume `fiber`. "
|
||||
"This function can be used to re-raise an error without losing "
|
||||
"the original stack trace."));
|
||||
janet_quick_asm(env, JANET_FUN_DEBUG,
|
||||
"debug", 1, 0, 1, 1, debug_asm, sizeof(debug_asm),
|
||||
JDOC("(debug &opt x)\n\n"
|
||||
|
||||
@@ -102,7 +102,7 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
}
|
||||
|
||||
/* Error reporting. This can be emulated from within Janet, but for
|
||||
* consitency with the top level code it is defined once. */
|
||||
* consistency with the top level code it is defined once. */
|
||||
void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
|
||||
|
||||
int32_t fi;
|
||||
@@ -164,7 +164,7 @@ void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
|
||||
}
|
||||
}
|
||||
if (frame->flags & JANET_STACKFRAME_TAILCALL)
|
||||
janet_eprintf(" (tailcall)");
|
||||
janet_eprintf(" (tail call)");
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t)(frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
@@ -180,6 +180,11 @@ void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
|
||||
}
|
||||
}
|
||||
janet_eprintf("\n");
|
||||
/* Print fiber points optionally. Clutters traces but provides info
|
||||
if (i <= 0 && fi > 0) {
|
||||
janet_eprintf(" in parent fiber\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,8 +393,8 @@ JANET_CORE_FN(cfun_debug_stack,
|
||||
JANET_CORE_FN(cfun_debug_stacktrace,
|
||||
"(debug/stacktrace fiber &opt err prefix)",
|
||||
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
|
||||
"an error value to print the stack trace with. If `err` is nil or not "
|
||||
"provided, and no prefix is given, will skip the error line. Returns the fiber.") {
|
||||
"an error value to print the stack trace with. If `prefix` is nil or not "
|
||||
"provided, will skip the error line. Returns the fiber.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
||||
|
||||
146
src/core/ev.c
146
src/core/ev.c
@@ -279,8 +279,12 @@ 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;
|
||||
}
|
||||
if (mode & JANET_ASYNC_LISTEN_WRITE) {
|
||||
stream->write_fiber = fiber;
|
||||
}
|
||||
fiber->ev_callback = callback;
|
||||
fiber->ev_stream = stream;
|
||||
janet_ev_inc_refcount();
|
||||
@@ -429,7 +433,7 @@ static void janet_stream_marshal(void *p, JanetMarshalContext *ctx) {
|
||||
}
|
||||
janet_marshal_int64(ctx, (int64_t)(duph));
|
||||
#else
|
||||
/* Marshal after dup becuse it is easier than maintaining our own ref counting. */
|
||||
/* Marshal after dup because it is easier than maintaining our own ref counting. */
|
||||
int duph = dup(s->handle);
|
||||
if (duph < 0) janet_panicf("failed to duplicate stream handle: %V", janet_ev_lasterr());
|
||||
janet_marshal_int(ctx, (int32_t)(duph));
|
||||
@@ -450,6 +454,9 @@ static void *janet_stream_unmarshal(JanetMarshalContext *ctx) {
|
||||
p->handle = (JanetHandle) janet_unmarshal_int64(ctx);
|
||||
#else
|
||||
p->handle = (JanetHandle) janet_unmarshal_int(ctx);
|
||||
#endif
|
||||
#ifdef JANET_EV_POLL
|
||||
janet_register_stream(p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
@@ -459,6 +466,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,
|
||||
@@ -467,7 +480,7 @@ const JanetAbstractType janet_stream_type = {
|
||||
NULL,
|
||||
janet_stream_marshal,
|
||||
janet_stream_unmarshal,
|
||||
NULL,
|
||||
janet_stream_tostring,
|
||||
NULL,
|
||||
NULL,
|
||||
janet_stream_next,
|
||||
@@ -582,7 +595,7 @@ void janet_ev_deinit_common(void) {
|
||||
|
||||
/* Shorthand to yield to event loop */
|
||||
void janet_await(void) {
|
||||
/* Store the fiber in a gobal table */
|
||||
/* Store the fiber in a global table */
|
||||
janet_signalv(JANET_SIGNAL_EVENT, janet_wrap_nil());
|
||||
}
|
||||
|
||||
@@ -1166,10 +1179,12 @@ JANET_CORE_FN(cfun_channel_close,
|
||||
msg.argj = janet_wrap_nil();
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||
janet_schedule(writer.fiber, make_close_result(channel));
|
||||
} else {
|
||||
janet_schedule(writer.fiber, janet_wrap_nil());
|
||||
if (janet_fiber_can_resume(writer.fiber)) {
|
||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||
janet_schedule(writer.fiber, make_close_result(channel));
|
||||
} else {
|
||||
janet_schedule(writer.fiber, janet_wrap_nil());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1185,10 +1200,12 @@ JANET_CORE_FN(cfun_channel_close,
|
||||
msg.argj = janet_wrap_nil();
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||
janet_schedule(reader.fiber, make_close_result(channel));
|
||||
} else {
|
||||
janet_schedule(reader.fiber, janet_wrap_nil());
|
||||
if (janet_fiber_can_resume(reader.fiber)) {
|
||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||
janet_schedule(reader.fiber, make_close_result(channel));
|
||||
} else {
|
||||
janet_schedule(reader.fiber, janet_wrap_nil());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1452,7 +1469,7 @@ void janet_ev_deinit(void) {
|
||||
CloseHandle(janet_vm.iocp);
|
||||
}
|
||||
|
||||
void janet_register_stream(JanetStream *stream) {
|
||||
static void janet_register_stream(JanetStream *stream) {
|
||||
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
|
||||
janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
|
||||
}
|
||||
@@ -1460,7 +1477,7 @@ void janet_register_stream(JanetStream *stream) {
|
||||
|
||||
void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
||||
ULONG_PTR completionKey = 0;
|
||||
DWORD num_bytes_transfered = 0;
|
||||
DWORD num_bytes_transferred = 0;
|
||||
LPOVERLAPPED overlapped = NULL;
|
||||
|
||||
/* Calculate how long to wait before timeout */
|
||||
@@ -1475,7 +1492,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
||||
} else {
|
||||
waittime = INFINITE;
|
||||
}
|
||||
BOOL result = GetQueuedCompletionStatus(janet_vm.iocp, &num_bytes_transfered, &completionKey, &overlapped, (DWORD) waittime);
|
||||
BOOL result = GetQueuedCompletionStatus(janet_vm.iocp, &num_bytes_transferred, &completionKey, &overlapped, (DWORD) waittime);
|
||||
|
||||
if (result || overlapped) {
|
||||
if (0 == completionKey) {
|
||||
@@ -1498,7 +1515,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
||||
if (fiber != NULL) {
|
||||
fiber->flags &= ~JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
||||
/* System is done with this, we can reused this data */
|
||||
overlapped->InternalHigh = (ULONG_PTR) num_bytes_transfered;
|
||||
overlapped->InternalHigh = (ULONG_PTR) num_bytes_transferred;
|
||||
fiber->ev_callback(fiber, result ? JANET_ASYNC_EVENT_COMPLETE : JANET_ASYNC_EVENT_FAILED);
|
||||
} else {
|
||||
janet_free((void *) overlapped);
|
||||
@@ -1509,6 +1526,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) {
|
||||
@@ -1520,15 +1545,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) {
|
||||
@@ -1542,6 +1567,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;
|
||||
@@ -1671,14 +1708,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 {
|
||||
@@ -1689,6 +1727,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) {
|
||||
@@ -1811,15 +1861,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 */
|
||||
@@ -1836,6 +1901,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;
|
||||
@@ -2018,7 +2091,7 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar
|
||||
int err = pthread_create(&waiter_thread, &janet_vm.new_thread_attr, janet_thread_body, init);
|
||||
if (err) {
|
||||
janet_free(init);
|
||||
janet_panicf("%s", strerror(err));
|
||||
janet_panicf("%s", janet_strerror(err));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2127,7 +2200,7 @@ Janet janet_ev_lasterr(void) {
|
||||
}
|
||||
#else
|
||||
Janet janet_ev_lasterr(void) {
|
||||
return janet_cstringv(strerror(errno));
|
||||
return janet_cstringv(janet_strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2759,7 +2832,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
||||
janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
|
||||
}
|
||||
|
||||
/* Get supervsior */
|
||||
/* Get supervisor */
|
||||
if (flags & JANET_THREAD_SUPERVISOR_FLAG) {
|
||||
Janet sup =
|
||||
janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||
@@ -2945,10 +3018,15 @@ JANET_CORE_FN(cfun_ev_sleep,
|
||||
|
||||
JANET_CORE_FN(cfun_ev_deadline,
|
||||
"(ev/deadline sec &opt tocancel tocheck)",
|
||||
"Set a deadline for a fiber `tocheck`. If `tocheck` is not finished after `sec` seconds, "
|
||||
"`tocancel` will be canceled as with `ev/cancel`. "
|
||||
"If `tocancel` and `tocheck` are not given, they default to `(fiber/root)` and "
|
||||
"`(fiber/current)` respectively. Returns `tocancel`.") {
|
||||
"Schedules the event loop to try to cancel the `tocancel` "
|
||||
"task as with `ev/cancel`. After `sec` seconds, the event "
|
||||
"loop will attempt cancellation of `tocancel` if the "
|
||||
"`tocheck` fiber is resumable. `sec` is a number that can "
|
||||
"have a fractional part. `tocancel` defaults to "
|
||||
"`(fiber/root)`, but if specified, must be a task (root "
|
||||
"fiber). `tocheck` defaults to `(fiber/current)`, but if "
|
||||
"specified, should be a fiber. Returns `tocancel` "
|
||||
"immediately.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
double sec = janet_getnumber(argv, 0);
|
||||
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber);
|
||||
|
||||
@@ -76,4 +76,6 @@
|
||||
#define __BSD_VISIBLE 1
|
||||
#endif
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#endif
|
||||
|
||||
@@ -475,7 +475,7 @@ JANET_CORE_FN(cfun_ffi_align,
|
||||
static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
|
||||
switch (janet_type(argv[n])) {
|
||||
default:
|
||||
janet_panicf("bad slot #%d, expected ffi pointer convertable type, got %v", n, argv[n]);
|
||||
janet_panicf("bad slot #%d, expected ffi pointer convertible type, got %v", n, argv[n]);
|
||||
case JANET_POINTER:
|
||||
case JANET_STRING:
|
||||
case JANET_KEYWORD:
|
||||
|
||||
@@ -662,7 +662,7 @@ JANET_CORE_FN(cfun_fiber_can_resume,
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_fiber_last_value,
|
||||
"(fiber/last-value)",
|
||||
"(fiber/last-value fiber)",
|
||||
"Get the last value returned or signaled from the fiber.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
|
||||
@@ -64,7 +64,7 @@ enum JanetMemoryType {
|
||||
};
|
||||
|
||||
/* To allocate collectable memory, one must call janet_alloc, initialize the memory,
|
||||
* and then call when janet_enablegc when it is initailize and reachable by the gc (on the JANET stack) */
|
||||
* and then call when janet_enablegc when it is initialized and reachable by the gc (on the JANET stack) */
|
||||
void *janet_gcalloc(enum JanetMemoryType type, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,11 @@ static void io_file_marshal(void *p, JanetMarshalContext *ctx);
|
||||
static void *io_file_unmarshal(JanetMarshalContext *ctx);
|
||||
static Janet io_file_next(void *p, Janet key);
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#define ftell _ftelli64
|
||||
#define fseek _fseeki64
|
||||
#endif
|
||||
|
||||
const JanetAbstractType janet_file_type = {
|
||||
"core/file",
|
||||
cfun_io_gc,
|
||||
@@ -126,7 +131,7 @@ JANET_CORE_FN(cfun_io_temp,
|
||||
// XXX use mkostemp when we can to avoid CLOEXEC race.
|
||||
FILE *tmp = tmpfile();
|
||||
if (!tmp)
|
||||
janet_panicf("unable to create temporary file - %s", strerror(errno));
|
||||
janet_panicf("unable to create temporary file - %s", janet_strerror(errno));
|
||||
return janet_makefile(tmp, JANET_FILE_WRITE | JANET_FILE_READ | JANET_FILE_BINARY);
|
||||
}
|
||||
|
||||
@@ -168,7 +173,7 @@ JANET_CORE_FN(cfun_io_fopen,
|
||||
}
|
||||
}
|
||||
return f ? janet_makefile(f, flags)
|
||||
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil())
|
||||
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, janet_strerror(errno)), janet_wrap_nil())
|
||||
: janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -289,7 +294,7 @@ int janet_file_close(JanetFile *file) {
|
||||
if (!(file->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
|
||||
ret = fclose(file->file);
|
||||
file->flags |= JANET_FILE_CLOSED;
|
||||
file->file = NULL; /* NULL derefence is easier to debug then other problems */
|
||||
file->file = NULL; /* NULL dereference is easier to debug then other problems */
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
@@ -337,7 +342,7 @@ JANET_CORE_FN(cfun_io_fseek,
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
long int offset = 0;
|
||||
int64_t offset = 0;
|
||||
int whence = SEEK_CUR;
|
||||
if (argc >= 2) {
|
||||
const uint8_t *whence_sym = janet_getkeyword(argv, 1);
|
||||
@@ -351,7 +356,7 @@ JANET_CORE_FN(cfun_io_fseek,
|
||||
janet_panicf("expected one of :cur, :set, :end, got %v", argv[1]);
|
||||
}
|
||||
if (argc == 3) {
|
||||
offset = (long) janet_getinteger64(argv, 2);
|
||||
offset = (int64_t) janet_getinteger64(argv, 2);
|
||||
}
|
||||
}
|
||||
if (fseek(iof->file, offset, whence)) janet_panic("error seeking file");
|
||||
@@ -365,7 +370,7 @@ JANET_CORE_FN(cfun_io_ftell,
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
janet_panic("file is closed");
|
||||
long pos = ftell(iof->file);
|
||||
int64_t pos = ftell(iof->file);
|
||||
if (pos == -1) janet_panic("error getting position in file");
|
||||
return janet_wrap_number((double)pos);
|
||||
}
|
||||
|
||||
@@ -349,6 +349,26 @@ JANET_CORE_FN(janet_cfun_lcm, "(math/lcm x y)",
|
||||
return janet_wrap_number(janet_lcm(x, y));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_frexp, "(math/frexp x)",
|
||||
"Returns a tuple of (mantissa, exponent) from number.") {
|
||||
janet_fixarity(argc, 1);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
int exp;
|
||||
x = frexp(x, &exp);
|
||||
Janet *result = janet_tuple_begin(2);
|
||||
result[0] = janet_wrap_number(x);
|
||||
result[1] = janet_wrap_number((double) exp);
|
||||
return janet_wrap_tuple(janet_tuple_end(result));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_ldexp, "(math/ldexp m e)",
|
||||
"Creates a new number from a mantissa and an exponent.") {
|
||||
janet_fixarity(argc, 2);
|
||||
double x = janet_getnumber(argv, 0);
|
||||
int32_t y = janet_getinteger(argv, 1);
|
||||
return janet_wrap_number(ldexp(x, y));
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
void janet_lib_math(JanetTable *env) {
|
||||
JanetRegExt math_cfuns[] = {
|
||||
@@ -395,6 +415,8 @@ void janet_lib_math(JanetTable *env) {
|
||||
JANET_CORE_REG("math/next", janet_nextafter),
|
||||
JANET_CORE_REG("math/gcd", janet_cfun_gcd),
|
||||
JANET_CORE_REG("math/lcm", janet_cfun_lcm),
|
||||
JANET_CORE_REG("math/frexp", janet_cfun_frexp),
|
||||
JANET_CORE_REG("math/ldexp", janet_cfun_ldexp),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, math_cfuns);
|
||||
|
||||
@@ -152,7 +152,7 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
|
||||
if (res == 0) {
|
||||
janet_schedule(fiber, janet_wrap_abstract(stream));
|
||||
} else {
|
||||
janet_cancel(fiber, janet_cstringv(strerror(res)));
|
||||
janet_cancel(fiber, janet_cstringv(janet_strerror(res)));
|
||||
stream->flags |= JANET_STREAM_TOCLOSE;
|
||||
}
|
||||
} else {
|
||||
@@ -319,12 +319,13 @@ 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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Adress info */
|
||||
/* Address info */
|
||||
|
||||
static int janet_get_sockettype(Janet *argv, int32_t argc, int32_t n) {
|
||||
JanetKeyword stype = janet_optkeyword(argv, argc, n, NULL);
|
||||
@@ -1034,7 +1035,7 @@ JANET_CORE_FN(cfun_net_setsockopt,
|
||||
|
||||
int r = setsockopt((JSock) stream->handle, st->level, st->optname, optval, optlen);
|
||||
if (r == -1) {
|
||||
janet_panicf("setsockopt(%q): %s", argv[1], strerror(errno));
|
||||
janet_panicf("setsockopt(%q): %s", argv[1], janet_strerror(errno));
|
||||
}
|
||||
|
||||
return janet_wrap_nil();
|
||||
|
||||
208
src/core/os.c
208
src/core/os.c
@@ -38,6 +38,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#ifdef JANET_BSD
|
||||
#include <sys/sysctl.h>
|
||||
@@ -229,10 +230,11 @@ JANET_CORE_FN(os_compiler,
|
||||
#undef janet_stringify
|
||||
|
||||
JANET_CORE_FN(os_exit,
|
||||
"(os/exit &opt x)",
|
||||
"(os/exit &opt x force)",
|
||||
"Exit from janet with an exit code equal to x. If x is not an integer, "
|
||||
"the exit with status equal the hash of x.") {
|
||||
janet_arity(argc, 0, 1);
|
||||
"the exit with status equal the hash of x. If `force` is truthy will exit immediately and "
|
||||
"skip cleanup code.") {
|
||||
janet_arity(argc, 0, 2);
|
||||
int status;
|
||||
if (argc == 0) {
|
||||
status = EXIT_SUCCESS;
|
||||
@@ -242,7 +244,11 @@ JANET_CORE_FN(os_exit,
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
janet_deinit();
|
||||
exit(status);
|
||||
if (argc >= 2 && janet_truthy(argv[1])) {
|
||||
_exit(status);
|
||||
} else {
|
||||
exit(status);
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -500,8 +506,11 @@ static int proc_get_status(JanetProc *proc) {
|
||||
status = WEXITSTATUS(status);
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
status = WSTOPSIG(status) + 128;
|
||||
} else {
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
status = WTERMSIG(status) + 128;
|
||||
} else {
|
||||
/* Could possibly return -1 but for now, just panic */
|
||||
janet_panicf("Undefined status code for process termination, %d.", status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -613,7 +622,11 @@ os_proc_wait_impl(JanetProc *proc) {
|
||||
|
||||
JANET_CORE_FN(os_proc_wait,
|
||||
"(os/proc-wait proc)",
|
||||
"Block until the subprocess completes. Returns the subprocess return code.") {
|
||||
"Suspend the current fiber until the subprocess completes. Returns the subprocess return code. "
|
||||
"os/proc-wait cannot be called twice on the same process. If `ev/with-deadline` cancels `os/proc-wait` "
|
||||
"with an error or os/proc-wait is cancelled with any error caused by anything else, os/proc-wait still "
|
||||
"finishes in the background. Only after os/proc-wait finishes, a process is cleaned up by the operating "
|
||||
"system. Thus, a process becomes a zombie process if os/proc-wait is not called.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||
#ifdef JANET_EV
|
||||
@@ -724,10 +737,11 @@ static int get_signal_kw(const Janet *argv, int32_t n) {
|
||||
JANET_CORE_FN(os_proc_kill,
|
||||
"(os/proc-kill proc &opt wait signal)",
|
||||
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
|
||||
"handle on windows. If `wait` is truthy, will wait for the process to finish and "
|
||||
"returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead."
|
||||
"Signal keywords are named after their C counterparts but in lowercase with the leading "
|
||||
"`SIG` stripped. Signals are ignored on windows.") {
|
||||
"handle on windows. If os/proc-wait already finished for proc, os/proc-kill raises an error. After "
|
||||
"sending signal to proc, if `wait` is truthy, will wait for the process to finish and return the exit "
|
||||
"code by calling os/proc-wait. Otherwise, returns `proc`. If signal is specified, send it instead. "
|
||||
"Signal keywords are named after their C counterparts but in lowercase with the leading `SIG` stripped. "
|
||||
"Signals are ignored on windows.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||
if (proc->flags & JANET_PROC_WAITED) {
|
||||
@@ -748,7 +762,7 @@ JANET_CORE_FN(os_proc_kill,
|
||||
}
|
||||
int status = kill(proc->pid, signal == -1 ? SIGKILL : signal);
|
||||
if (status) {
|
||||
janet_panic(strerror(errno));
|
||||
janet_panic(janet_strerror(errno));
|
||||
}
|
||||
#endif
|
||||
/* After killing process we wait on it. */
|
||||
@@ -766,8 +780,9 @@ JANET_CORE_FN(os_proc_kill,
|
||||
|
||||
JANET_CORE_FN(os_proc_close,
|
||||
"(os/proc-close proc)",
|
||||
"Wait on a process if it has not been waited on, and close pipes created by `os/spawn` "
|
||||
"if they have not been closed. Returns nil.") {
|
||||
"Close pipes created by `os/spawn` if they have not been closed. Then, if os/proc-wait was not already "
|
||||
"called on proc, os/proc-wait is called on it, and it returns the exit code returned by os/proc-wait. "
|
||||
"Otherwise, returns nil.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||
#ifdef JANET_EV
|
||||
@@ -877,8 +892,9 @@ JANET_CORE_FN(os_sigaction,
|
||||
}
|
||||
struct sigaction action;
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
sigaddset(&mask, sig);
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_flags |= SA_RESTART;
|
||||
if (can_interrupt) {
|
||||
#ifdef JANET_NO_INTERPRETER_INTERRUPT
|
||||
janet_panic("interpreter interrupt not enabled");
|
||||
@@ -1259,7 +1275,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
status = execv(cargv[0], cargv);
|
||||
}
|
||||
} while (status == -1 && errno == EINTR);
|
||||
janet_panicf("%p: %s", cargv[0], strerror(errno ? errno : ENOENT));
|
||||
janet_panicf("%p: %s", cargv[0], janet_strerror(errno ? errno : ENOENT));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1316,7 +1332,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
os_execute_cleanup(envp, child_argv);
|
||||
if (status) {
|
||||
/* correct for macos bug where errno is not set */
|
||||
janet_panicf("%p: %s", argv[0], strerror(errno ? errno : ENOENT));
|
||||
janet_panicf("%p: %s", argv[0], janet_strerror(errno ? errno : ENOENT));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1371,28 +1387,33 @@ JANET_CORE_FN(os_execute,
|
||||
"* :d - Don't try and terminate the process on garbage collection (allow spawning zombies).\n"
|
||||
"`env` is a table or struct mapping environment variables to values. It can also "
|
||||
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
|
||||
"These arguments should be core/file values. "
|
||||
"Returns the exit status of the program.") {
|
||||
":in, :out, and :err should be core/file values or core/stream values. core/file values and core/stream "
|
||||
"values passed to :in, :out, and :err should be closed manually because os/execute doesn't close them. "
|
||||
"Returns the exit code of the program.") {
|
||||
return os_execute_impl(argc, argv, JANET_EXECUTE_EXECUTE);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_spawn,
|
||||
"(os/spawn args &opt flags env)",
|
||||
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
||||
"same arguments as `os/execute`. Does not wait for the process. "
|
||||
"For each of the :in, :out, and :err keys to the `env` argument, one "
|
||||
"can also pass in the keyword `:pipe` "
|
||||
"to get streams for standard IO of the subprocess that can be read from and written to. "
|
||||
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
|
||||
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
|
||||
"subprocess or `(os/proc-kill proc)`.") {
|
||||
"same arguments as `os/execute`. Does not wait for the process. For each of the :in, :out, and :err keys "
|
||||
"of the `env` argument, one can also pass in the keyword `:pipe` to get streams for standard IO of the "
|
||||
"subprocess that can be read from and written to. The returned value `proc` has the fields :in, :out, "
|
||||
":err, and the additional field :pid on unix-like platforms. `(os/proc-wait proc)` must be called to "
|
||||
"rejoin the subprocess. After `(os/proc-wait proc)` finishes, proc gains a new field, :return-code. "
|
||||
"If :x flag is passed to os/spawn, non-zero exit code will cause os/proc-wait to raise an error. "
|
||||
"If pipe streams created with :pipe keyword are not closed in time, janet can run out of file "
|
||||
"descriptors. They can be closed individually, or `os/proc-close` can close all pipe streams on proc. "
|
||||
"If pipe streams aren't read before `os/proc-wait` finishes, then pipe buffers become full, and the "
|
||||
"process cannot finish because the process cannot print more on pipe buffers which are already full. "
|
||||
"If the process cannot finish, os/proc-wait cannot finish, either.") {
|
||||
return os_execute_impl(argc, argv, JANET_EXECUTE_SPAWN);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_posix_exec,
|
||||
"(os/posix-exec args &opt flags env)",
|
||||
"Use the execvpe or execve system calls to replace the current process with an interface similar to os/execute. "
|
||||
"Hoever, instead of creating a subprocess, the current process is replaced. Is not supported on windows, and "
|
||||
"However, instead of creating a subprocess, the current process is replaced. Is not supported on windows, and "
|
||||
"does not allow redirection of stdio.") {
|
||||
return os_execute_impl(argc, argv, JANET_EXECUTE_EXEC);
|
||||
}
|
||||
@@ -1412,7 +1433,7 @@ JANET_CORE_FN(os_posix_fork,
|
||||
result = fork();
|
||||
} while (result == -1 && errno == EINTR);
|
||||
if (result == -1) {
|
||||
janet_panic(strerror(errno));
|
||||
janet_panic(janet_strerror(errno));
|
||||
}
|
||||
if (result) {
|
||||
JanetProc *proc = janet_abstract(&ProcAT, sizeof(JanetProc));
|
||||
@@ -1544,34 +1565,51 @@ JANET_CORE_FN(os_time,
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_clock,
|
||||
"(os/clock &opt source)",
|
||||
"Return the number of whole + fractional seconds of the requested clock source.\n\n"
|
||||
"(os/clock &opt source format)",
|
||||
"Return the current time of the requested clock source.\n\n"
|
||||
"The `source` argument selects the clock source to use, when not specified the default "
|
||||
"is `:realtime`:\n"
|
||||
"- :realtime: Return the real (i.e., wall-clock) time. This clock is affected by discontinuous "
|
||||
" jumps in the system time\n"
|
||||
"- :monotonic: Return the number of whole + fractional seconds since some fixed point in "
|
||||
" time. The clock is guaranteed to be non-decreasing in real time.\n"
|
||||
"- :cputime: Return the CPU time consumed by this process (i.e. all threads in the process)\n") {
|
||||
"- :cputime: Return the CPU time consumed by this process (i.e. all threads in the process)\n"
|
||||
"The `format` argument selects the type of output, when not specified the default is `:double`:\n"
|
||||
"- :double: Return the number of seconds + fractional seconds as a double\n"
|
||||
"- :int: Return the number of seconds as an integer\n"
|
||||
"- :tuple: Return a 2 integer tuple [seconds, nanoseconds]\n") {
|
||||
enum JanetTimeSource source;
|
||||
janet_sandbox_assert(JANET_SANDBOX_HRTIME);
|
||||
janet_arity(argc, 0, 1);
|
||||
enum JanetTimeSource source = JANET_TIME_REALTIME;
|
||||
if (argc == 1) {
|
||||
JanetKeyword sourcestr = janet_getkeyword(argv, 0);
|
||||
if (janet_cstrcmp(sourcestr, "realtime") == 0) {
|
||||
source = JANET_TIME_REALTIME;
|
||||
} else if (janet_cstrcmp(sourcestr, "monotonic") == 0) {
|
||||
source = JANET_TIME_MONOTONIC;
|
||||
} else if (janet_cstrcmp(sourcestr, "cputime") == 0) {
|
||||
source = JANET_TIME_CPUTIME;
|
||||
} else {
|
||||
janet_panicf("expected :realtime, :monotonic, or :cputime, got %v", argv[0]);
|
||||
}
|
||||
janet_arity(argc, 0, 2);
|
||||
|
||||
JanetKeyword sourcestr = janet_optkeyword(argv, argc, 0, (const uint8_t *) "realtime");
|
||||
if (janet_cstrcmp(sourcestr, "realtime") == 0) {
|
||||
source = JANET_TIME_REALTIME;
|
||||
} else if (janet_cstrcmp(sourcestr, "monotonic") == 0) {
|
||||
source = JANET_TIME_MONOTONIC;
|
||||
} else if (janet_cstrcmp(sourcestr, "cputime") == 0) {
|
||||
source = JANET_TIME_CPUTIME;
|
||||
} else {
|
||||
janet_panicf("expected :realtime, :monotonic, or :cputime, got %v", argv[0]);
|
||||
}
|
||||
|
||||
struct timespec tv;
|
||||
if (janet_gettime(&tv, source)) janet_panic("could not get time");
|
||||
double dtime = tv.tv_sec + (tv.tv_nsec / 1E9);
|
||||
return janet_wrap_number(dtime);
|
||||
|
||||
JanetKeyword formatstr = janet_optkeyword(argv, argc, 1, (const uint8_t *) "double");
|
||||
if (janet_cstrcmp(formatstr, "double") == 0) {
|
||||
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((double)(tv.tv_sec));
|
||||
} else if (janet_cstrcmp(formatstr, "tuple") == 0) {
|
||||
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 {
|
||||
janet_panicf("expected :double, :int, or :tuple, got %v", argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_sleep,
|
||||
@@ -1607,7 +1645,7 @@ JANET_CORE_FN(os_isatty,
|
||||
return janet_wrap_boolean(_isatty(fd));
|
||||
#else
|
||||
int fd = fileno(f);
|
||||
if (fd == -1) janet_panic(strerror(errno));
|
||||
if (fd == -1) janet_panic(janet_strerror(errno));
|
||||
return janet_wrap_boolean(isatty(fd));
|
||||
#endif
|
||||
}
|
||||
@@ -1842,7 +1880,7 @@ JANET_CORE_FN(os_mktime,
|
||||
}
|
||||
|
||||
if (t == (time_t) -1) {
|
||||
janet_panicf("%s", strerror(errno));
|
||||
janet_panicf("%s", janet_strerror(errno));
|
||||
}
|
||||
|
||||
return janet_wrap_number((double)t);
|
||||
@@ -1854,6 +1892,43 @@ JANET_CORE_FN(os_mktime,
|
||||
#define j_symlink symlink
|
||||
#endif
|
||||
|
||||
JANET_CORE_FN(os_setlocale,
|
||||
"(os/setlocale &opt locale category)",
|
||||
"Set the system locale, which affects how dates and numbers are formatted. "
|
||||
"Passing nil to locale will return the current locale. Category can be one of:\n\n"
|
||||
" * :all (default)\n"
|
||||
" * :collate\n"
|
||||
" * :ctype\n"
|
||||
" * :monetary\n"
|
||||
" * :numeric\n"
|
||||
" * :time\n\n"
|
||||
"Returns the new locale if set successfully, otherwise nil. Note that this will affect "
|
||||
"other functions such as `os/strftime` and even `printf`.") {
|
||||
janet_arity(argc, 0, 2);
|
||||
const char *locale_name = janet_optcstring(argv, argc, 0, NULL);
|
||||
int category_int = LC_ALL;
|
||||
if (argc > 1 && !janet_checktype(argv[1], JANET_NIL)) {
|
||||
if (janet_keyeq(argv[1], "all")) {
|
||||
category_int = LC_ALL;
|
||||
} else if (janet_keyeq(argv[1], "collate")) {
|
||||
category_int = LC_COLLATE;
|
||||
} else if (janet_keyeq(argv[1], "ctype")) {
|
||||
category_int = LC_CTYPE;
|
||||
} else if (janet_keyeq(argv[1], "monetary")) {
|
||||
category_int = LC_MONETARY;
|
||||
} else if (janet_keyeq(argv[1], "numeric")) {
|
||||
category_int = LC_NUMERIC;
|
||||
} else if (janet_keyeq(argv[1], "time")) {
|
||||
category_int = LC_TIME;
|
||||
} else {
|
||||
janet_panicf("expected one of :all, :collate, :ctype, :monetary, :numeric, or :time, got %v", argv[1]);
|
||||
}
|
||||
}
|
||||
const char *old = setlocale(category_int, locale_name);
|
||||
if (old == NULL) return janet_wrap_nil();
|
||||
return janet_cstringv(old);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_link,
|
||||
"(os/link oldpath newpath &opt symlink)",
|
||||
"Create a link at newpath that points to oldpath and returns nil. "
|
||||
@@ -1871,7 +1946,7 @@ JANET_CORE_FN(os_link,
|
||||
const char *oldpath = janet_getcstring(argv, 0);
|
||||
const char *newpath = janet_getcstring(argv, 1);
|
||||
int res = ((argc == 3 && janet_truthy(argv[2])) ? j_symlink : link)(oldpath, newpath);
|
||||
if (-1 == res) janet_panicf("%s: %s -> %s", strerror(errno), oldpath, newpath);
|
||||
if (-1 == res) janet_panicf("%s: %s -> %s", janet_strerror(errno), oldpath, newpath);
|
||||
return janet_wrap_nil();
|
||||
#endif
|
||||
}
|
||||
@@ -1890,7 +1965,7 @@ JANET_CORE_FN(os_symlink,
|
||||
const char *oldpath = janet_getcstring(argv, 0);
|
||||
const char *newpath = janet_getcstring(argv, 1);
|
||||
int res = j_symlink(oldpath, newpath);
|
||||
if (-1 == res) janet_panicf("%s: %s -> %s", strerror(errno), oldpath, newpath);
|
||||
if (-1 == res) janet_panicf("%s: %s -> %s", janet_strerror(errno), oldpath, newpath);
|
||||
return janet_wrap_nil();
|
||||
#endif
|
||||
}
|
||||
@@ -1912,7 +1987,7 @@ JANET_CORE_FN(os_mkdir,
|
||||
#endif
|
||||
if (res == 0) return janet_wrap_true();
|
||||
if (errno == EEXIST) return janet_wrap_false();
|
||||
janet_panicf("%s: %s", strerror(errno), path);
|
||||
janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_rmdir,
|
||||
@@ -1926,7 +2001,7 @@ JANET_CORE_FN(os_rmdir,
|
||||
#else
|
||||
int res = rmdir(path);
|
||||
#endif
|
||||
if (-1 == res) janet_panicf("%s: %s", strerror(errno), path);
|
||||
if (-1 == res) janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -1941,7 +2016,7 @@ JANET_CORE_FN(os_cd,
|
||||
#else
|
||||
int res = chdir(path);
|
||||
#endif
|
||||
if (-1 == res) janet_panicf("%s: %s", strerror(errno), path);
|
||||
if (-1 == res) janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -1965,7 +2040,7 @@ JANET_CORE_FN(os_touch,
|
||||
bufp = NULL;
|
||||
}
|
||||
int res = utime(path, bufp);
|
||||
if (-1 == res) janet_panic(strerror(errno));
|
||||
if (-1 == res) janet_panic(janet_strerror(errno));
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -1975,7 +2050,7 @@ JANET_CORE_FN(os_remove,
|
||||
janet_fixarity(argc, 1);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
int status = remove(path);
|
||||
if (-1 == status) janet_panicf("%s: %s", strerror(errno), path);
|
||||
if (-1 == status) janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -1994,7 +2069,7 @@ JANET_CORE_FN(os_readlink,
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
ssize_t len = readlink(path, buffer, sizeof buffer);
|
||||
if (len < 0 || (size_t)len >= sizeof buffer)
|
||||
janet_panicf("%s: %s", strerror(errno), path);
|
||||
janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
return janet_stringv((const uint8_t *)buffer, len);
|
||||
#endif
|
||||
}
|
||||
@@ -2289,7 +2364,7 @@ JANET_CORE_FN(os_chmod,
|
||||
#else
|
||||
int res = chmod(path, os_getmode(argv, 1));
|
||||
#endif
|
||||
if (-1 == res) janet_panicf("%s: %s", strerror(errno), path);
|
||||
if (-1 == res) janet_panicf("%s: %s", janet_strerror(errno), path);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -2325,7 +2400,7 @@ JANET_CORE_FN(os_dir,
|
||||
janet_panicf("path too long: %s", dir);
|
||||
sprintf(pattern, "%s/*", dir);
|
||||
intptr_t res = _findfirst(pattern, &afile);
|
||||
if (-1 == res) janet_panicv(janet_cstringv(strerror(errno)));
|
||||
if (-1 == res) janet_panicv(janet_cstringv(janet_strerror(errno)));
|
||||
do {
|
||||
if (strcmp(".", afile.name) && strcmp("..", afile.name)) {
|
||||
janet_array_push(paths, janet_cstringv(afile.name));
|
||||
@@ -2336,8 +2411,18 @@ JANET_CORE_FN(os_dir,
|
||||
/* Read directory items with opendir / readdir / closedir */
|
||||
struct dirent *dp;
|
||||
DIR *dfd = opendir(dir);
|
||||
if (dfd == NULL) janet_panicf("cannot open directory %s", dir);
|
||||
while ((dp = readdir(dfd)) != NULL) {
|
||||
if (dfd == NULL) janet_panicf("cannot open directory %s: %s", dir, janet_strerror(errno));
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
dp = readdir(dfd);
|
||||
if (dp == NULL) {
|
||||
if (errno) {
|
||||
int olderr = errno;
|
||||
closedir(dfd);
|
||||
janet_panicf("failed to read directory %s: %s", dir, janet_strerror(olderr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
|
||||
continue;
|
||||
}
|
||||
@@ -2357,7 +2442,7 @@ JANET_CORE_FN(os_rename,
|
||||
const char *dest = janet_getcstring(argv, 1);
|
||||
int status = rename(src, dest);
|
||||
if (status) {
|
||||
janet_panic(strerror(errno));
|
||||
janet_panic(janet_strerror(errno));
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
@@ -2377,7 +2462,7 @@ JANET_CORE_FN(os_realpath,
|
||||
#else
|
||||
char *dest = realpath(src, NULL);
|
||||
#endif
|
||||
if (NULL == dest) janet_panicf("%s: %s", strerror(errno), src);
|
||||
if (NULL == dest) janet_panicf("%s: %s", janet_strerror(errno), src);
|
||||
Janet ret = janet_cstringv(dest);
|
||||
janet_free(dest);
|
||||
return ret;
|
||||
@@ -2651,6 +2736,7 @@ void janet_lib_os(JanetTable *env) {
|
||||
JANET_CORE_REG("os/strftime", os_strftime),
|
||||
JANET_CORE_REG("os/sleep", os_sleep),
|
||||
JANET_CORE_REG("os/isatty", os_isatty),
|
||||
JANET_CORE_REG("os/setlocale", os_setlocale),
|
||||
|
||||
/* env functions */
|
||||
JANET_CORE_REG("os/environ", os_environ),
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
typedef struct {
|
||||
const uint8_t *text_start;
|
||||
const uint8_t *text_end;
|
||||
/* text_end will be restricted in a (sub) rule, but
|
||||
/* text_end can be restricted by some rules, but
|
||||
outer_text_end will always contain the real end of
|
||||
input, which we need to generate a line mapping */
|
||||
const uint8_t *outer_text_end;
|
||||
@@ -134,7 +134,7 @@ static LineCol get_linecol_from_position(PegState *s, int32_t position) {
|
||||
* a newline character is consider to be on the same line as the character before
|
||||
* (\n is line terminator, not line separator).
|
||||
* - in the not-found case, we still want to find the greatest-indexed newline that
|
||||
* is before position. we use that to calcuate the line and column.
|
||||
* is before position. we use that to calculate the line and column.
|
||||
* - in the case that lo = 0 and s->linemap[0] is still greater than position, we
|
||||
* are on the first line and our column is position + 1. */
|
||||
int32_t hi = s->linemaplen; /* hi is greater than the actual line */
|
||||
@@ -510,6 +510,44 @@ tail:
|
||||
return window_end;
|
||||
}
|
||||
|
||||
case RULE_SPLIT: {
|
||||
const uint8_t *saved_end = s->text_end;
|
||||
const uint32_t *rule_separator = s->bytecode + rule[1];
|
||||
const uint32_t *rule_subpattern = s->bytecode + rule[2];
|
||||
|
||||
const uint8_t *separator_end = NULL;
|
||||
do {
|
||||
const uint8_t *text_start = text;
|
||||
CapState cs = cap_save(s);
|
||||
down1(s);
|
||||
while (text <= s->text_end) {
|
||||
separator_end = peg_rule(s, rule_separator, text);
|
||||
cap_load(s, cs);
|
||||
if (separator_end) {
|
||||
break;
|
||||
}
|
||||
text++;
|
||||
}
|
||||
up1(s);
|
||||
|
||||
if (separator_end) {
|
||||
s->text_end = text;
|
||||
text = separator_end;
|
||||
}
|
||||
|
||||
down1(s);
|
||||
const uint8_t *subpattern_end = peg_rule(s, rule_subpattern, text_start);
|
||||
up1(s);
|
||||
s->text_end = saved_end;
|
||||
|
||||
if (!subpattern_end) {
|
||||
return NULL;
|
||||
}
|
||||
} while (separator_end);
|
||||
|
||||
return s->text_end;
|
||||
}
|
||||
|
||||
case RULE_REPLACE:
|
||||
case RULE_MATCHTIME: {
|
||||
uint32_t tag = rule[3];
|
||||
@@ -629,11 +667,11 @@ tail:
|
||||
case RULE_READINT: {
|
||||
uint32_t tag = rule[2];
|
||||
uint32_t signedness = rule[1] & 0x10;
|
||||
uint32_t endianess = rule[1] & 0x20;
|
||||
uint32_t endianness = rule[1] & 0x20;
|
||||
int width = (int)(rule[1] & 0xF);
|
||||
if (text + width > s->text_end) return NULL;
|
||||
uint64_t accum = 0;
|
||||
if (endianess) {
|
||||
if (endianness) {
|
||||
/* BE */
|
||||
for (int i = 0; i < width; i++) accum = (accum << 8) | text[i];
|
||||
} else {
|
||||
@@ -1143,6 +1181,14 @@ static void spec_sub(Builder *b, int32_t argc, const Janet *argv) {
|
||||
emit_2(r, RULE_SUB, subrule1, subrule2);
|
||||
}
|
||||
|
||||
static void spec_split(Builder *b, int32_t argc, const Janet *argv) {
|
||||
peg_fixarity(b, argc, 2);
|
||||
Reserve r = reserve(b, 3);
|
||||
uint32_t subrule1 = peg_compile1(b, argv[0]);
|
||||
uint32_t subrule2 = peg_compile1(b, argv[1]);
|
||||
emit_2(r, RULE_SPLIT, subrule1, subrule2);
|
||||
}
|
||||
|
||||
#ifdef JANET_INT_TYPES
|
||||
#define JANET_MAX_READINT_WIDTH 8
|
||||
#else
|
||||
@@ -1226,6 +1272,7 @@ static const SpecialPair peg_specials[] = {
|
||||
{"sequence", spec_sequence},
|
||||
{"set", spec_set},
|
||||
{"some", spec_some},
|
||||
{"split", spec_split},
|
||||
{"sub", spec_sub},
|
||||
{"thru", spec_thru},
|
||||
{"to", spec_to},
|
||||
@@ -1562,6 +1609,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
||||
i += 4;
|
||||
break;
|
||||
case RULE_SUB:
|
||||
case RULE_SPLIT:
|
||||
/* [rule, rule] */
|
||||
if (rule[1] >= blen) goto bad;
|
||||
if (rule[2] >= blen) goto bad;
|
||||
@@ -1580,7 +1628,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
||||
i += 2;
|
||||
break;
|
||||
case RULE_READINT:
|
||||
/* [ width | (endianess << 5) | (signedness << 6), tag ] */
|
||||
/* [ width | (endianness << 5) | (signedness << 6), tag ] */
|
||||
if (rule[1] > JANET_MAX_READINT_WIDTH) goto bad;
|
||||
i += 3;
|
||||
break;
|
||||
@@ -1677,7 +1725,7 @@ static JanetPeg *compile_peg(Janet x) {
|
||||
JANET_CORE_FN(cfun_peg_compile,
|
||||
"(peg/compile peg)",
|
||||
"Compiles a peg source data structure into a <core/peg>. This will speed up matching "
|
||||
"if the same peg will be used multiple times. Will also use `(dyn :peg-grammar)` to suppliment "
|
||||
"if the same peg will be used multiple times. Will also use `(dyn :peg-grammar)` to supplement "
|
||||
"the grammar of the peg for otherwise undefined peg keywords.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetPeg *peg = compile_peg(argv[0]);
|
||||
@@ -1817,7 +1865,7 @@ JANET_CORE_FN(cfun_peg_replace_all,
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_peg_replace,
|
||||
"(peg/replace peg repl text &opt start & args)",
|
||||
"(peg/replace peg subst text &opt start & args)",
|
||||
"Replace first match of `peg` in `text` with `subst`, returning a new buffer. "
|
||||
"The peg does not need to make captures to do replacement. "
|
||||
"If `subst` is a function, it will be called with the "
|
||||
|
||||
@@ -379,8 +379,10 @@ static int print_jdn_one(struct pretty *S, Janet x, int depth) {
|
||||
break;
|
||||
case JANET_NUMBER:
|
||||
janet_buffer_ensure(S->buffer, S->buffer->count + BUFSIZE, 2);
|
||||
int count = snprintf((char *) S->buffer->data + S->buffer->count, BUFSIZE, "%.17g", janet_unwrap_number(x));
|
||||
S->buffer->count += count;
|
||||
double num = janet_unwrap_number(x);
|
||||
if (isnan(num)) return 1;
|
||||
if (isinf(num)) return 1;
|
||||
janet_buffer_dtostr(S->buffer, num);
|
||||
break;
|
||||
case JANET_SYMBOL:
|
||||
case JANET_KEYWORD:
|
||||
@@ -830,7 +832,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++);
|
||||
|
||||
@@ -149,7 +149,7 @@ static int destructure(JanetCompiler *c,
|
||||
JanetTable *attr) {
|
||||
switch (janet_type(left)) {
|
||||
default:
|
||||
janetc_error(c, janet_formatc("unexpected type in destruction, got %v", left));
|
||||
janetc_error(c, janet_formatc("unexpected type in destructuring, got %v", left));
|
||||
return 1;
|
||||
case JANET_SYMBOL:
|
||||
/* Leaf, assign right to left */
|
||||
@@ -925,6 +925,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
int structarg = 0;
|
||||
int allow_extra = 0;
|
||||
int selfref = 0;
|
||||
int hasname = 0;
|
||||
int seenamp = 0;
|
||||
int seenopt = 0;
|
||||
int namedargs = 0;
|
||||
@@ -943,6 +944,10 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
head = argv[0];
|
||||
if (janet_checktype(head, JANET_SYMBOL)) {
|
||||
selfref = 1;
|
||||
hasname = 1;
|
||||
parami = 1;
|
||||
} else if (janet_checktype(head, JANET_KEYWORD)) {
|
||||
hasname = 1;
|
||||
parami = 1;
|
||||
}
|
||||
if (parami >= argn || !janet_checktype(argv[parami], JANET_TUPLE)) {
|
||||
@@ -1103,7 +1108,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
if (vararg) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
||||
if (structarg) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
|
||||
if (selfref) def->name = janet_unwrap_symbol(head);
|
||||
if (hasname) def->name = janet_unwrap_symbol(head); /* Also correctly unwraps keyword */
|
||||
janet_def_addflags(def);
|
||||
defindex = janetc_addfuncdef(c, def);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ void janet_vm_load(JanetVM *from) {
|
||||
}
|
||||
|
||||
/* Trigger suspension of the Janet vm by trying to
|
||||
* exit the interpeter loop when convenient. You can optionally
|
||||
* exit the interpreter loop when convenient. You can optionally
|
||||
* use NULL to interrupt the current VM when convenient */
|
||||
void janet_interpreter_interrupt(JanetVM *vm) {
|
||||
vm = vm ? vm : &janet_vm;
|
||||
|
||||
@@ -149,6 +149,11 @@ struct JanetVM {
|
||||
JanetTraversalNode *traversal_top;
|
||||
JanetTraversalNode *traversal_base;
|
||||
|
||||
/* Thread safe strerror error buffer - for janet_strerror */
|
||||
#ifndef JANET_WINDOWS
|
||||
char strerror_buf[256];
|
||||
#endif
|
||||
|
||||
/* Event loop and scheduler globals */
|
||||
#ifdef JANET_EV
|
||||
size_t tq_count;
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
* because E is a valid digit in bases 15 or greater. For bases greater than
|
||||
* 10, the letters are used as digits. A through Z correspond to the digits 10
|
||||
* through 35, and the lowercase letters have the same values. The radix number
|
||||
* is always in base 10. For example, a hexidecimal number could be written
|
||||
* is always in base 10. For example, a hexadecimal number could be written
|
||||
* '16rdeadbeef'. janet_scan_number also supports some c style syntax for
|
||||
* hexidecimal literals. The previous number could also be written
|
||||
* hexadecimal literals. The previous number could also be written
|
||||
* '0xdeadbeef'.
|
||||
*/
|
||||
|
||||
@@ -490,3 +490,18 @@ int janet_scan_uint64(const uint8_t *str, int32_t len, uint64_t *out) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void janet_buffer_dtostr(JanetBuffer *buffer, double x) {
|
||||
#define BUFSIZE 32
|
||||
janet_buffer_extra(buffer, BUFSIZE);
|
||||
int count = snprintf((char *) buffer->data + buffer->count, BUFSIZE, "%.17g", x);
|
||||
#undef BUFSIZE
|
||||
/* fix locale issues with commas */
|
||||
for (int i = 0; i < count; i++) {
|
||||
char c = buffer->data[buffer->count + i];
|
||||
if (c == ',') {
|
||||
buffer->data[buffer->count + i] = '.';
|
||||
}
|
||||
}
|
||||
buffer->count += count;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ static JanetTable *janet_table_init_impl(JanetTable *table, int32_t capacity, in
|
||||
return table;
|
||||
}
|
||||
|
||||
/* Initialize a table (for use withs scratch memory) */
|
||||
/* Initialize a table (for use with scratch memory) */
|
||||
JanetTable *janet_table_init(JanetTable *table, int32_t capacity) {
|
||||
return janet_table_init_impl(table, capacity, 1);
|
||||
}
|
||||
@@ -319,13 +319,6 @@ JANET_CORE_FN(cfun_table_new,
|
||||
int32_t cap = janet_getnat(argv, 0);
|
||||
return janet_wrap_table(janet_table(cap));
|
||||
}
|
||||
/*
|
||||
uint32_t flags = janet_getflags(argv, 1, "kv");
|
||||
if (flags == 0) return janet_wrap_table(janet_table(cap));
|
||||
if (flags == 1) return janet_wrap_table(janet_table_weakk(cap));
|
||||
if (flags == 2) return janet_wrap_table(janet_table_weakv(cap));
|
||||
return janet_wrap_table(janet_table_weakkv(cap));
|
||||
*/
|
||||
|
||||
JANET_CORE_FN(cfun_table_weak,
|
||||
"(table/weak capacity)",
|
||||
|
||||
@@ -826,6 +826,20 @@ int janet_checkuint64(Janet x) {
|
||||
return janet_checkuint64range(dval);
|
||||
}
|
||||
|
||||
int janet_checkint16(Janet x) {
|
||||
if (!janet_checktype(x, JANET_NUMBER))
|
||||
return 0;
|
||||
double dval = janet_unwrap_number(x);
|
||||
return janet_checkint16range(dval);
|
||||
}
|
||||
|
||||
int janet_checkuint16(Janet x) {
|
||||
if (!janet_checktype(x, JANET_NUMBER))
|
||||
return 0;
|
||||
double dval = janet_unwrap_number(x);
|
||||
return janet_checkuint16range(dval);
|
||||
}
|
||||
|
||||
int janet_checksize(Janet x) {
|
||||
if (!janet_checktype(x, JANET_NUMBER))
|
||||
return 0;
|
||||
@@ -953,6 +967,20 @@ int janet_gettime(struct timespec *spec, enum JanetTimeSource source) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Better strerror (thread-safe if available) */
|
||||
const char *janet_strerror(int e) {
|
||||
#ifdef JANET_WINDOWS
|
||||
/* Microsoft strerror seems sane here and is thread safe by default */
|
||||
return strerror(e);
|
||||
#elif defined(_GNU_SOURCE)
|
||||
/* See https://linux.die.net/man/3/strerror_r */
|
||||
return strerror_r(e, janet_vm.strerror_buf, sizeof(janet_vm.strerror_buf));
|
||||
#else
|
||||
strerror_r(e, janet_vm.strerror_buf, sizeof(janet_vm.strerror_buf));
|
||||
return janet_vm.strerror_buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Setting C99 standard makes this not available, but it should
|
||||
* work/link properly if we detect a BSD */
|
||||
#if defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
#ifndef JANET_EXIT
|
||||
#include <stdio.h>
|
||||
#define JANET_EXIT(m) do { \
|
||||
fprintf(stderr, "janet interpreter runtime error at line %d in file %s: %s\n",\
|
||||
fprintf(stderr, "janet internal error at line %d in file %s: %s\n",\
|
||||
__LINE__,\
|
||||
__FILE__,\
|
||||
(m));\
|
||||
exit(1);\
|
||||
abort();\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
@@ -80,6 +80,8 @@ void janet_memempty(JanetKV *mem, int32_t count);
|
||||
void *janet_memalloc_empty(int32_t count);
|
||||
JanetTable *janet_get_core_table(const char *name);
|
||||
void janet_def_addflags(JanetFuncDef *def);
|
||||
void janet_buffer_dtostr(JanetBuffer *buffer, double x);
|
||||
const char *janet_strerror(int e);
|
||||
const void *janet_strbinsearch(
|
||||
const void *tab,
|
||||
size_t tabcount,
|
||||
@@ -139,7 +141,7 @@ int janet_gettime(struct timespec *spec, enum JanetTimeSource source);
|
||||
#define strdup(x) _strdup(x)
|
||||
#endif
|
||||
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libraries
|
||||
* with native code. */
|
||||
#if defined(JANET_NO_DYNAMIC_MODULES)
|
||||
typedef int Clib;
|
||||
|
||||
@@ -318,7 +318,7 @@ static Janet janet_binop_call(const char *lmethod, const char *rmethod, Janet lh
|
||||
Janet lr = janet_method_lookup(rhs, rmethod);
|
||||
Janet argv[2] = { rhs, lhs };
|
||||
if (janet_checktype(lr, JANET_NIL)) {
|
||||
janet_panicf("could not find method :%s for %v, or :%s for %v",
|
||||
janet_panicf("could not find method :%s for %v or :%s for %v",
|
||||
lmethod, lhs,
|
||||
rmethod, rhs);
|
||||
}
|
||||
@@ -1268,7 +1268,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
/*
|
||||
* Execute a single instruction in the fiber. Does this by inspecting
|
||||
* the fiber, setting a breakpoint at the next instruction, executing, and
|
||||
* reseting breakpoints to how they were prior. Yes, it's a bit hacky.
|
||||
* resetting breakpoints to how they were prior. Yes, it's a bit hacky.
|
||||
*/
|
||||
JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
/* No finished or currently alive fibers. */
|
||||
@@ -1613,7 +1613,7 @@ int janet_init(void) {
|
||||
janet_vm.registry_count = 0;
|
||||
janet_vm.registry_dirty = 0;
|
||||
|
||||
/* Intialize abstract registry */
|
||||
/* Initialize abstract registry */
|
||||
janet_vm.abstract_registry = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Detect OS and endianess.
|
||||
* Detect OS and endianness.
|
||||
* From webkit source. There is likely some extreneous
|
||||
* detection for unsupported platforms
|
||||
*/
|
||||
@@ -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
|
||||
@@ -261,7 +262,7 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Tell complier some functions don't return */
|
||||
/* Tell compiler some functions don't return */
|
||||
#ifndef JANET_NO_RETURN
|
||||
#ifdef JANET_WINDOWS
|
||||
#define JANET_NO_RETURN __declspec(noreturn)
|
||||
@@ -271,7 +272,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Prevent some recursive functions from recursing too deeply
|
||||
* ands crashing (the parser). Instead, error out. */
|
||||
* and crashing (the parser). Instead, error out. */
|
||||
#define JANET_RECURSION_GUARD 1024
|
||||
|
||||
/* Maximum depth to follow table prototypes before giving up and returning nil. */
|
||||
@@ -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
|
||||
@@ -890,12 +897,16 @@ JANET_API Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer);
|
||||
/* End of tagged union implementation */
|
||||
#endif
|
||||
|
||||
JANET_API int janet_checkint16(Janet x);
|
||||
JANET_API int janet_checkuint16(Janet x);
|
||||
JANET_API int janet_checkint(Janet x);
|
||||
JANET_API int janet_checkuint(Janet x);
|
||||
JANET_API int janet_checkint64(Janet x);
|
||||
JANET_API int janet_checkuint64(Janet x);
|
||||
JANET_API int janet_checksize(Janet x);
|
||||
JANET_API JanetAbstract janet_checkabstract(Janet x, const JanetAbstractType *at);
|
||||
#define janet_checkint16range(x) ((x) >= INT16_MIN && (x) <= INT16_MAX && (x) == (int16_t)(x))
|
||||
#define janet_checkuint16range(x) ((x) >= 0 && (x) <= UINT16_MAX && (x) == (uint16_t)(x))
|
||||
#define janet_checkintrange(x) ((x) >= INT32_MIN && (x) <= INT32_MAX && (x) == (int32_t)(x))
|
||||
#define janet_checkuintrange(x) ((x) >= 0 && (x) <= UINT32_MAX && (x) == (uint32_t)(x))
|
||||
#define janet_checkint64range(x) ((x) >= JANET_INTMIN_DOUBLE && (x) <= JANET_INTMAX_DOUBLE && (x) == (int64_t)(x))
|
||||
@@ -2013,7 +2024,10 @@ JANET_API void *janet_getpointer(const Janet *argv, int32_t n);
|
||||
|
||||
JANET_API int32_t janet_getnat(const Janet *argv, int32_t n);
|
||||
JANET_API int32_t janet_getinteger(const Janet *argv, int32_t n);
|
||||
JANET_API int16_t janet_getinteger16(const Janet *argv, int32_t n);
|
||||
JANET_API int64_t janet_getinteger64(const Janet *argv, int32_t n);
|
||||
JANET_API uint32_t janet_getuinteger(const Janet *argv, int32_t n);
|
||||
JANET_API uint16_t janet_getuinteger16(const Janet *argv, int32_t n);
|
||||
JANET_API uint64_t janet_getuinteger64(const Janet *argv, int32_t n);
|
||||
JANET_API size_t janet_getsize(const Janet *argv, int32_t n);
|
||||
JANET_API JanetView janet_getindexed(const Janet *argv, int32_t n);
|
||||
@@ -2136,12 +2150,13 @@ typedef enum {
|
||||
RULE_TO, /* [rule] */
|
||||
RULE_THRU, /* [rule] */
|
||||
RULE_LENPREFIX, /* [rule_a, rule_b (repeat rule_b rule_a times)] */
|
||||
RULE_READINT, /* [(signedness << 4) | (endianess << 5) | bytewidth, tag] */
|
||||
RULE_READINT, /* [(signedness << 4) | (endianness << 5) | bytewidth, tag] */
|
||||
RULE_LINE, /* [tag] */
|
||||
RULE_COLUMN, /* [tag] */
|
||||
RULE_UNREF, /* [rule, tag] */
|
||||
RULE_CAPTURE_NUM, /* [rule, tag] */
|
||||
RULE_SUB /* [rule, rule] */
|
||||
RULE_SUB, /* [rule, rule] */
|
||||
RULE_SPLIT /* [rule, rule] */
|
||||
} JanetPegOpcod;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -51,5 +51,13 @@
|
||||
(def f (asm (disasm (fn [x] (fn [y] (+ x y))))))
|
||||
(assert (= ((f 10) 37) 47) "asm environment tables")
|
||||
|
||||
# issue #1424
|
||||
(assert-no-error "arity > used slots (issue #1424)"
|
||||
(asm
|
||||
(disasm
|
||||
(fn []
|
||||
(def foo (fn [one two] one))
|
||||
(foo 100 200)))))
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
"sort 5")
|
||||
(assert (<= ;(sort (map (fn [x] (math/random)) (range 1000)))) "sort 6")
|
||||
|
||||
# #1283
|
||||
# #1283
|
||||
(assert (deep=
|
||||
(partition 2 (generate [ i :in [:a :b :c :d :e]] i))
|
||||
'@[(:a :b) (:c :d) (:e)]))
|
||||
@@ -754,7 +754,7 @@
|
||||
(default name (string "has-key? " (++ test-has-key-auto)))
|
||||
(assert (= expected (has-key? col key)) name)
|
||||
(if
|
||||
# guarenteed by `has-key?` to never fail
|
||||
# guaranteed by `has-key?` to never fail
|
||||
expected (in col key)
|
||||
# if `has-key?` is false, then `in` should fail (for indexed types)
|
||||
#
|
||||
@@ -955,6 +955,10 @@
|
||||
(defn case-4 [&]
|
||||
(def x (break (break (break)))))
|
||||
(bytecode-roundtrip case-4)
|
||||
(defn case-5 []
|
||||
(def foo (fn [one two] one))
|
||||
(foo 100 200))
|
||||
(bytecode-roundtrip case-5)
|
||||
|
||||
# Debug bytecode of these functions
|
||||
# (pp (disasm case-1))
|
||||
@@ -972,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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2023 Calvin Rose
|
||||
# Copyright (c) 2024 Calvin Rose
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
@@ -77,6 +77,48 @@
|
||||
(buffer/push-string b5 "456" @"789")
|
||||
(assert (= "123456789" (string b5)) "buffer/push-buffer 2")
|
||||
|
||||
(def buffer-uint16-be @"")
|
||||
(buffer/push-uint16 buffer-uint16-be :be 0x0102)
|
||||
(assert (= "\x01\x02" (string buffer-uint16-be)) "buffer/push-uint16 big endian")
|
||||
|
||||
(def buffer-uint16-le @"")
|
||||
(buffer/push-uint16 buffer-uint16-le :le 0x0102)
|
||||
(assert (= "\x02\x01" (string buffer-uint16-le)) "buffer/push-uint16 little endian")
|
||||
|
||||
(def buffer-uint16-max @"")
|
||||
(buffer/push-uint16 buffer-uint16-max :be 0xFFFF)
|
||||
(assert (= "\xff\xff" (string buffer-uint16-max)) "buffer/push-uint16 max")
|
||||
(assert-error "too large" (buffer/push-uint16 @"" 0x1FFFF))
|
||||
(assert-error "too small" (buffer/push-uint16 @"" -0x1))
|
||||
|
||||
(def buffer-uint32-be @"")
|
||||
(buffer/push-uint32 buffer-uint32-be :be 0x01020304)
|
||||
(assert (= "\x01\x02\x03\x04" (string buffer-uint32-be)) "buffer/push-uint32 big endian")
|
||||
|
||||
(def buffer-uint32-le @"")
|
||||
(buffer/push-uint32 buffer-uint32-le :le 0x01020304)
|
||||
(assert (= "\x04\x03\x02\x01" (string buffer-uint32-le)) "buffer/push-uint32 little endian")
|
||||
|
||||
(def buffer-uint32-max @"")
|
||||
(buffer/push-uint32 buffer-uint32-max :be 0xFFFFFFFF)
|
||||
(assert (= "\xff\xff\xff\xff" (string buffer-uint32-max)) "buffer/push-uint32 max")
|
||||
|
||||
(def buffer-float32-be @"")
|
||||
(buffer/push-float32 buffer-float32-be :be 1.234)
|
||||
(assert (= "\x3f\x9d\xf3\xb6" (string buffer-float32-be)) "buffer/push-float32 big endian")
|
||||
|
||||
(def buffer-float32-le @"")
|
||||
(buffer/push-float32 buffer-float32-le :le 1.234)
|
||||
(assert (= "\xb6\xf3\x9d\x3f" (string buffer-float32-le)) "buffer/push-float32 little endian")
|
||||
|
||||
(def buffer-float64-be @"")
|
||||
(buffer/push-float64 buffer-float64-be :be 1.234)
|
||||
(assert (= "\x3f\xf3\xbe\x76\xc8\xb4\x39\x58" (string buffer-float64-be)) "buffer/push-float64 big endian")
|
||||
|
||||
(def buffer-float64-le @"")
|
||||
(buffer/push-float64 buffer-float64-le :le 1.234)
|
||||
(assert (= "\x58\x39\xb4\xc8\x76\xbe\xf3\x3f" (string buffer-float64-le)) "buffer/push-float64 little endian")
|
||||
|
||||
# Buffer from bytes
|
||||
(assert (deep= @"" (buffer/from-bytes)) "buffer/from-bytes 1")
|
||||
(assert (deep= @"ABC" (buffer/from-bytes 65 66 67)) "buffer/from-bytes 2")
|
||||
@@ -122,5 +164,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)
|
||||
|
||||
|
||||
125
test/suite-bundle.janet
Normal file
125
test/suite-bundle.janet
Normal file
@@ -0,0 +1,125 @@
|
||||
# Copyright (c) 2024 Calvin Rose
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
(import ./helper :prefix "" :exit true)
|
||||
(start-suite)
|
||||
|
||||
(assert true) # smoke test
|
||||
|
||||
# Copy since not exposed in boot.janet
|
||||
(defn- bundle-rpath
|
||||
[path]
|
||||
(string/replace-all "\\" "/" (os/realpath path)))
|
||||
|
||||
(defn- rmrf
|
||||
"rm -rf in janet"
|
||||
[x]
|
||||
(case (os/lstat x :mode)
|
||||
nil nil
|
||||
:directory (do
|
||||
(each y (os/dir x)
|
||||
(rmrf (string x "/" y)))
|
||||
(os/rmdir x))
|
||||
(os/rm x))
|
||||
nil)
|
||||
|
||||
# Test mkdir -> rmdir
|
||||
(assert (os/mkdir "tempdir123"))
|
||||
(rmrf "tempdir123")
|
||||
|
||||
# Setup a temporary syspath for manipultation
|
||||
(math/seedrandom (os/cryptorand 16))
|
||||
(def syspath (string (math/random) "_jpm_tree.tmp"))
|
||||
(rmrf syspath)
|
||||
(assert (os/mkdir syspath))
|
||||
(put root-env *syspath* (bundle-rpath syspath))
|
||||
(unless (os/getenv "VERBOSE")
|
||||
(setdyn *out* @""))
|
||||
(assert (empty? (bundle/list)) "initial bundle/list")
|
||||
(assert (empty? (bundle/topolist)) "initial bundle/topolist")
|
||||
|
||||
# Try (and fail) to install sample-bundle (missing deps)
|
||||
(assert-error "missing dependencies sample-dep1, sample-dep2"
|
||||
(bundle/install "./examples/sample-bundle"))
|
||||
(assert (empty? (bundle/list)))
|
||||
|
||||
# Install deps (dep1 as :auto-remove)
|
||||
(assert-no-error "sample-dep2"
|
||||
(bundle/install "./examples/sample-dep2"))
|
||||
(assert (= 1 (length (bundle/list))))
|
||||
(assert-no-error "sample-dep1" (bundle/install "./examples/sample-dep1"))
|
||||
(assert (= 2 (length (bundle/list))))
|
||||
|
||||
(assert-no-error "sample-dep2 reinstall" (bundle/reinstall "sample-dep2"))
|
||||
(assert-no-error "sample-dep1 reinstall" (bundle/reinstall "sample-dep1" :auto-remove true))
|
||||
|
||||
(assert (= 2 (length (bundle/list))) "bundles are listed correctly 1")
|
||||
(assert (= 2 (length (bundle/topolist))) "bundles are listed correctly 2")
|
||||
|
||||
# Now install sample-bundle
|
||||
(assert-no-error "sample-bundle install" (bundle/install "./examples/sample-bundle"))
|
||||
|
||||
(assert-error "" (bundle/install "./examples/sample-dep11111"))
|
||||
|
||||
(assert (= 3 (length (bundle/list))) "bundles are listed correctly 3")
|
||||
(assert (= 3 (length (bundle/topolist))) "bundles are listed correctly 4")
|
||||
|
||||
# Check topolist has not bad order
|
||||
(def tlist (bundle/topolist))
|
||||
(assert (> (index-of "sample-bundle" tlist) (index-of "sample-dep2" tlist)) "topolist 1")
|
||||
(assert (> (index-of "sample-bundle" tlist) (index-of "sample-dep1" tlist)) "topolist 2")
|
||||
(assert (> (index-of "sample-dep1" tlist) (index-of "sample-dep2" tlist)) "topolist 3")
|
||||
|
||||
# Prune should do nothing
|
||||
(assert-no-error "first prune" (bundle/prune))
|
||||
(assert (= 3 (length (bundle/list))) "bundles are listed correctly 3")
|
||||
(assert (= 3 (length (bundle/topolist))) "bundles are listed correctly 4")
|
||||
|
||||
# Check that we can import the main dependency
|
||||
(import mymod)
|
||||
(assert (= 288 (mymod/myfn 12)) "using sample-bundle")
|
||||
|
||||
# Manual uninstall of dep1 and dep2 shouldn't work either since that would break dependencies
|
||||
(assert-error "cannot uninstall sample-dep1, breaks dependent bundles @[\"sample-bundle\"]"
|
||||
(bundle/uninstall "sample-dep1"))
|
||||
|
||||
# Now re-install sample-bundle as auto-remove
|
||||
(assert-no-error "sample-bundle install" (bundle/reinstall "sample-bundle" :auto-remove true))
|
||||
|
||||
# Reinstallation should also work without being concerned about breaking dependencies
|
||||
(assert-no-error "reinstall dep" (bundle/reinstall "sample-dep2"))
|
||||
|
||||
# Now prune should get rid of everything except sample-dep2
|
||||
(assert-no-error "second prune" (bundle/prune))
|
||||
|
||||
# Now check that we exactly one package left, which is dep2
|
||||
(assert (= 1 (length (bundle/list))) "bundles are listed correctly 5")
|
||||
(assert (= 1 (length (bundle/topolist))) "bundles are listed correctly 6")
|
||||
|
||||
# Which we can uninstall manually
|
||||
(assert-no-error "uninstall dep2" (bundle/uninstall "sample-dep2"))
|
||||
|
||||
# Now check bundle listing is again empty
|
||||
(assert (= 0 (length (bundle/list))) "bundles are listed correctly 7")
|
||||
(assert (= 0 (length (bundle/topolist))) "bundles are listed correctly 8")
|
||||
|
||||
(rmrf syspath)
|
||||
|
||||
(end-suite)
|
||||
@@ -21,6 +21,9 @@
|
||||
(import ./helper :prefix "" :exit true)
|
||||
(start-suite)
|
||||
|
||||
(def test-port (os/getenv "JANET_TEST_PORT" "8761"))
|
||||
(def test-host (os/getenv "JANET_TEST_HOST" "127.0.0.1"))
|
||||
|
||||
# Subprocess
|
||||
# 5e1a8c86f
|
||||
(def janet (dyn *executable*))
|
||||
@@ -192,11 +195,11 @@
|
||||
(net/write stream b)
|
||||
(buffer/clear b)))
|
||||
|
||||
(def s (net/server "127.0.0.1" "8000" handler))
|
||||
(def s (net/server test-host test-port handler))
|
||||
(assert s "made server 1")
|
||||
|
||||
(defn test-echo [msg]
|
||||
(with [conn (net/connect "127.0.0.1" "8000")]
|
||||
(with [conn (net/connect test-host test-port)]
|
||||
(net/write conn msg)
|
||||
(def res (net/read conn 1024))
|
||||
(assert (= (string res) msg) (string "echo " msg))))
|
||||
@@ -216,18 +219,18 @@
|
||||
# prevent immediate close
|
||||
(ev/read stream 1)
|
||||
(def [host port] (net/localname stream))
|
||||
(assert (= host "127.0.0.1") "localname host server")
|
||||
(assert (= port 8000) "localname port server")))
|
||||
(assert (= host test-host) "localname host server")
|
||||
(assert (= port (scan-number test-port)) "localname port server")))
|
||||
|
||||
# Test localname and peername
|
||||
# 077bf5eba
|
||||
(repeat 10
|
||||
(with [s (net/server "127.0.0.1" "8000" names-handler)]
|
||||
(with [s (net/server test-host test-port names-handler)]
|
||||
(repeat 10
|
||||
(with [conn (net/connect "127.0.0.1" "8000")]
|
||||
(with [conn (net/connect test-host test-port)]
|
||||
(def [host port] (net/peername conn))
|
||||
(assert (= host "127.0.0.1") "peername host client ")
|
||||
(assert (= port 8000) "peername port client")
|
||||
(assert (= host test-host) "peername host client ")
|
||||
(assert (= port (scan-number test-port)) "peername port client")
|
||||
# let server close
|
||||
(ev/write conn " "))))
|
||||
(gccollect))
|
||||
|
||||
@@ -96,11 +96,23 @@
|
||||
(assert (= (in buf 0) 0) "cryptorand doesn't overwrite buffer")
|
||||
(assert (= (length buf) 2) "cryptorand appends to buffer"))
|
||||
|
||||
(assert-no-error "realtime clock" (os/clock))
|
||||
(assert-no-error "realtime clock" (os/clock nil))
|
||||
(assert-no-error "realtime clock" (os/clock nil nil))
|
||||
|
||||
# 80db68210
|
||||
(assert-no-error "realtime clock" (os/clock :realtime))
|
||||
(assert-no-error "cputime clock" (os/clock :cputime))
|
||||
(assert-no-error "monotonic clock" (os/clock :monotonic))
|
||||
|
||||
(assert-no-error "realtime clock double output" (os/clock nil :double))
|
||||
(assert-no-error "realtime clock int output" (os/clock nil :int))
|
||||
(assert-no-error "realtime clock tuple output" (os/clock nil :tuple))
|
||||
|
||||
(assert-error "invalid clock" (os/clock :a))
|
||||
(assert-error "invalid output" (os/clock :realtime :b))
|
||||
(assert-error "invalid clock and output" (os/clock :a :b))
|
||||
|
||||
(def before (os/clock :monotonic))
|
||||
(def after (os/clock :monotonic))
|
||||
(assert (>= after before) "monotonic clock is monotonic")
|
||||
@@ -148,4 +160,3 @@
|
||||
{:out dn :err dn})))
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
@@ -265,6 +265,7 @@
|
||||
(marshpeg '(group "abc"))
|
||||
(marshpeg '(sub "abcdf" "abc"))
|
||||
(marshpeg '(* (sub 1 1)))
|
||||
(marshpeg '(split "," (+ "a" "b" "c")))
|
||||
|
||||
# Peg swallowing errors
|
||||
# 159651117
|
||||
@@ -491,7 +492,7 @@
|
||||
# header, followed by body, and drop the :header-len capture
|
||||
:packet (/ (* :packet-header :packet-body) ,|$1)
|
||||
|
||||
# any exact seqence of packets (no extra characters)
|
||||
# any exact sequence of packets (no extra characters)
|
||||
:main (* (any :packet) -1)}))
|
||||
|
||||
(assert (deep= @["a" "bb" "ccc"] (peg/match peg2 "1:a2:bb3:ccc"))
|
||||
@@ -710,5 +711,50 @@
|
||||
"abcdef"
|
||||
@[])
|
||||
|
||||
(test "split: basic functionality"
|
||||
~(split "," '1)
|
||||
"a,b,c"
|
||||
@["a" "b" "c"])
|
||||
|
||||
(test "split: drops captures from separator pattern"
|
||||
~(split '"," '1)
|
||||
"a,b,c"
|
||||
@["a" "b" "c"])
|
||||
|
||||
(test "split: can match empty subpatterns"
|
||||
~(split "," ':w*)
|
||||
",a,,bar,,,c,,"
|
||||
@["" "a" "" "bar" "" "" "c" "" ""])
|
||||
|
||||
(test "split: subpattern is limited to only text before the separator"
|
||||
~(split "," '(to -1))
|
||||
"a,,bar,c"
|
||||
@["a" "" "bar" "c"])
|
||||
|
||||
(test "split: fails if any subpattern fails"
|
||||
~(split "," '"a")
|
||||
"a,a,b"
|
||||
nil)
|
||||
|
||||
(test "split: separator does not have to match anything"
|
||||
~(split "x" '(to -1))
|
||||
"a,a,b"
|
||||
@["a,a,b"])
|
||||
|
||||
(test "split: always consumes entire input"
|
||||
~(split 1 '"")
|
||||
"abc"
|
||||
@["" "" "" ""])
|
||||
|
||||
(test "split: separator can be an arbitrary PEG"
|
||||
~(split :s+ '(to -1))
|
||||
"a b c"
|
||||
@["a" "b" "c"])
|
||||
|
||||
(test "split: does not advance past the end of the input"
|
||||
~(* (split "," ':w+) 0)
|
||||
"a,b,c"
|
||||
@["a" "b" "c"])
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
(defn buffer-factory
|
||||
[]
|
||||
@"im am a buffer")
|
||||
@"i am a buffer")
|
||||
|
||||
(assert (not= (buffer-factory) (buffer-factory)) "buffer instantiation")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user