mirror of
https://github.com/janet-lang/janet
synced 2025-11-21 09:44:49 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1449ad8b31 | ||
|
|
c44592c84d | ||
|
|
37e084969a | ||
|
|
b389f01005 | ||
|
|
a886a93d2f | ||
|
|
f7d0d065c8 | ||
|
|
8c2a517cd7 | ||
|
|
7e0c692d4e | ||
|
|
732fe0ad03 | ||
|
|
0c8622c803 | ||
|
|
94f2494f8d | ||
|
|
0f9ecc2da5 | ||
|
|
83f5da3b8f | ||
|
|
9b9f2a1713 | ||
|
|
8df4d47ede | ||
|
|
1c372fbf32 | ||
|
|
8ace580498 | ||
|
|
8241d9cbb4 | ||
|
|
6bd02bb5b6 | ||
|
|
2a3308005d | ||
|
|
0c34033b72 | ||
|
|
f1ec0cc48b | ||
|
|
98265f0637 | ||
|
|
1018cb9cca | ||
|
|
2204209133 | ||
|
|
95abff31d9 | ||
|
|
a776466423 | ||
|
|
511c1f4b0a | ||
|
|
c29195596e | ||
|
|
56027227fb | ||
|
|
c057e14b20 | ||
|
|
db7f741dad | ||
|
|
c901edbfb9 | ||
|
|
8fd1672963 | ||
|
|
9b99fc44b9 | ||
|
|
f393531335 | ||
|
|
6b8e5249ca | ||
|
|
6a96b615f0 | ||
|
|
8ec465d308 | ||
|
|
07bfd34c2f | ||
|
|
5f7878c00f | ||
|
|
aaf8ac2217 | ||
|
|
73b1cf547e | ||
|
|
ed2ae562c6 | ||
|
|
dd59d84b51 | ||
|
|
06873fbf0b | ||
|
|
1ff26d702a | ||
|
|
4da568254a | ||
|
|
357f1f94ca | ||
|
|
015e49c806 | ||
|
|
6b06ab5f9c | ||
|
|
fe6c6e15a6 | ||
|
|
b4eb52ca45 | ||
|
|
aca5428846 | ||
|
|
3dab9737e2 | ||
|
|
e601e8faab | ||
|
|
07cf63622f | ||
|
|
8e7b1e9ce0 | ||
|
|
355c514f0e | ||
|
|
976329abc1 | ||
|
|
ab3e843433 | ||
|
|
148e108864 | ||
|
|
c90c737345 | ||
|
|
13b9976382 | ||
|
|
095a81286a | ||
|
|
82416e4e4e | ||
|
|
ae51434a05 | ||
|
|
bb6ac423a7 | ||
|
|
c5ba3c0513 |
@@ -1,4 +1,4 @@
|
|||||||
image: openbsd/7.6
|
image: openbsd/7.7
|
||||||
sources:
|
sources:
|
||||||
- https://git.sr.ht/~bakpakin/janet
|
- https://git.sr.ht/~bakpakin/janet
|
||||||
packages:
|
packages:
|
||||||
@@ -10,13 +10,17 @@ tasks:
|
|||||||
gmake
|
gmake
|
||||||
gmake test
|
gmake test
|
||||||
doas gmake install
|
doas gmake install
|
||||||
gmake test-install
|
|
||||||
doas gmake uninstall
|
doas gmake uninstall
|
||||||
- meson_min: |
|
- meson_min: |
|
||||||
cd janet
|
cd janet
|
||||||
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
|
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
|
||||||
cd build_meson_min
|
cd build_meson_min
|
||||||
ninja
|
ninja
|
||||||
|
- meson_reduced: |
|
||||||
|
cd janet
|
||||||
|
meson setup build_meson_reduced --buildtype=release -Dreduced_os=true
|
||||||
|
cd build_meson_reduced
|
||||||
|
ninja
|
||||||
- meson_prf: |
|
- meson_prf: |
|
||||||
cd janet
|
cd janet
|
||||||
meson setup build_meson_prf --buildtype=release -Dprf=true
|
meson setup build_meson_prf --buildtype=release -Dprf=true
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,6 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 1.40.1 - 2025-11-16
|
||||||
|
- Fix `JANET_REDUCED_OS` build regression caused by `os/posix-chroot`.
|
||||||
|
- Code formatting
|
||||||
|
|
||||||
|
## 1.40.0 - 2025-11-15
|
||||||
|
- Add `os/posix-chroot`
|
||||||
|
- Fix `ev/deadline` with interrupt race condition bug on Windows.
|
||||||
|
- Improve `flycheck` by allowing functions and macros to define their own flycheck behavior via the metadata `:flycheck`.
|
||||||
|
- Add `*flychecking*` dynamic binding to check if inside flycheck evalutation
|
||||||
|
- Add `gcperthread` callback for abstract types. This lets threaded abstracts have a finalizer that is called per thread, as well as a global finalizer.
|
||||||
|
- Add `JANET_DO_ERROR_*` flags to describe the return value of `janet_dobytes` and `janet_dostring`.
|
||||||
|
|
||||||
## 1.39.1 - 2025-08-30
|
## 1.39.1 - 2025-08-30
|
||||||
- Add support for chdir in os/spawn on older macOS versions
|
- Add support for chdir in os/spawn on older macOS versions
|
||||||
- Expose channels properly in C API
|
- Expose channels properly in C API
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ ensure a consistent code style for C.
|
|||||||
|
|
||||||
## Janet style
|
## Janet style
|
||||||
|
|
||||||
All janet code in the project should be formatted similar to the code in core.janet.
|
All janet code in the project should be formatted similar to the code in src/boot/boot.janet.
|
||||||
The auto formatting from janet.vim will work well.
|
The auto formatting from janet.vim will work well.
|
||||||
|
|
||||||
## Typo Fixing and One-Line changes
|
## Typo Fixing and One-Line changes
|
||||||
|
|||||||
42
Makefile
42
Makefile
@@ -220,9 +220,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
|
|||||||
########################
|
########################
|
||||||
|
|
||||||
ifeq ($(UNAME), Darwin)
|
ifeq ($(UNAME), Darwin)
|
||||||
SONAME=libjanet.1.39.dylib
|
SONAME=libjanet.1.40.dylib
|
||||||
else
|
else
|
||||||
SONAME=libjanet.so.1.39
|
SONAME=libjanet.so.1.40
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(MINGW_COMPILER), clang)
|
ifeq ($(MINGW_COMPILER), clang)
|
||||||
@@ -261,6 +261,7 @@ $(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
|
|||||||
# Testing assumes HOSTCC=CC
|
# Testing assumes HOSTCC=CC
|
||||||
|
|
||||||
TEST_SCRIPTS=$(wildcard test/suite*.janet)
|
TEST_SCRIPTS=$(wildcard test/suite*.janet)
|
||||||
|
EXAMPLE_SCRIPTS=$(wildcard examples/*.janet)
|
||||||
|
|
||||||
repl: $(JANET_TARGET)
|
repl: $(JANET_TARGET)
|
||||||
$(RUN) ./$(JANET_TARGET)
|
$(RUN) ./$(JANET_TARGET)
|
||||||
@@ -268,21 +269,26 @@ repl: $(JANET_TARGET)
|
|||||||
debug: $(JANET_TARGET)
|
debug: $(JANET_TARGET)
|
||||||
$(DEBUGGER) ./$(JANET_TARGET)
|
$(DEBUGGER) ./$(JANET_TARGET)
|
||||||
|
|
||||||
VALGRIND_COMMAND=valgrind --leak-check=full --quiet
|
VALGRIND_COMMAND=$(RUN) valgrind --leak-check=full --quiet
|
||||||
|
CALLGRIND_COMMAND=$(RUN) valgrind --tool=callgrind
|
||||||
|
|
||||||
valgrind: $(JANET_TARGET)
|
valgrind: $(JANET_TARGET)
|
||||||
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
|
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
|
||||||
|
|
||||||
test: $(JANET_TARGET) $(TEST_PROGRAMS)
|
test: $(JANET_TARGET) $(TEST_SCRIPTS) $(EXAMPLE_SCRIPTS)
|
||||||
for f in test/suite*.janet; do $(RUN) ./$(JANET_TARGET) "$$f" || exit; done
|
for f in test/suite*.janet; do $(RUN) ./$(JANET_TARGET) "$$f" || exit; done
|
||||||
for f in examples/*.janet; do $(RUN) ./$(JANET_TARGET) -k "$$f"; done
|
for f in examples/*.janet; do $(RUN) ./$(JANET_TARGET) -k "$$f"; done
|
||||||
|
|
||||||
valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
|
valtest: $(JANET_TARGET) $(TEST_SCRIPTS) $(EXAMPLE_SCRIPTS)
|
||||||
for f in test/suite*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
|
for f in test/suite*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
|
||||||
for f in examples/*.janet; do ./$(JANET_TARGET) -k "$$f"; done
|
for f in examples/*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) -k "$$f"; done
|
||||||
|
|
||||||
callgrind: $(JANET_TARGET)
|
callgrind: $(JANET_TARGET)
|
||||||
for f in test/suite*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done
|
$(CALLGRIND_COMMAND) ./$(JANET_TARGET)
|
||||||
|
|
||||||
|
calltest: $(JANET_TARGET) $(TEST_SCRIPTS) $(EXAMPLE_SCRIPTS)
|
||||||
|
for f in test/suite*.janet; do $(CALLGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
|
||||||
|
for f in examples/*.janet; do $(CALLGRIND_COMMAND) ./$(JANET_TARGET) -k "$$f"; done
|
||||||
|
|
||||||
########################
|
########################
|
||||||
##### Distribution #####
|
##### Distribution #####
|
||||||
@@ -341,6 +347,7 @@ build/janet.pc: $(JANET_TARGET)
|
|||||||
echo 'Libs.private: $(CLIBS)' >> $@
|
echo 'Libs.private: $(CLIBS)' >> $@
|
||||||
|
|
||||||
install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h
|
install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h
|
||||||
|
$(eval JANET_VERSION := $(shell $(JANET_TARGET) -e '(print janet/version)'))
|
||||||
mkdir -p '$(DESTDIR)$(BINDIR)'
|
mkdir -p '$(DESTDIR)$(BINDIR)'
|
||||||
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
||||||
strip $(STRIPFLAGS) '$(DESTDIR)$(BINDIR)/janet'
|
strip $(STRIPFLAGS) '$(DESTDIR)$(BINDIR)/janet'
|
||||||
@@ -350,13 +357,13 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
|
|||||||
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
||||||
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
||||||
if test $(UNAME) = Darwin ; then \
|
if test $(UNAME) = Darwin ; then \
|
||||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib' ; \
|
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.$(JANET_VERSION).dylib' ; \
|
||||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.dylib' ; \
|
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.dylib' ; \
|
||||||
ln -sf libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
ln -sf libjanet.$(JANET_VERSION).dylib $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||||
else \
|
else \
|
||||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')' ; \
|
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(JANET_VERSION)' ; \
|
||||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so' ; \
|
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so' ; \
|
||||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
ln -sf libjanet.so.$(JANET_VERSION) $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||||
fi
|
fi
|
||||||
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
|
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
|
||||||
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
|
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
|
||||||
@@ -413,9 +420,6 @@ clean:
|
|||||||
-rm -rf build vgcore.* callgrind.*
|
-rm -rf build vgcore.* callgrind.*
|
||||||
-rm -rf test/install/build test/install/modpath
|
-rm -rf test/install/build test/install/modpath
|
||||||
|
|
||||||
test-install:
|
|
||||||
echo "JPM has been removed from default install."
|
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo
|
@echo
|
||||||
@echo 'Janet: A Dynamic Language & Bytecode VM'
|
@echo 'Janet: A Dynamic Language & Bytecode VM'
|
||||||
@@ -427,7 +431,8 @@ help:
|
|||||||
@echo ' make test Test a built Janet'
|
@echo ' make test Test a built Janet'
|
||||||
@echo ' make valgrind Assess Janet with Valgrind'
|
@echo ' make valgrind Assess Janet with Valgrind'
|
||||||
@echo ' make callgrind Assess Janet with Valgrind, using Callgrind'
|
@echo ' make callgrind Assess Janet with Valgrind, using Callgrind'
|
||||||
@echo ' make valtest Run the test suite with Valgrind to check for memory leaks'
|
@echo ' make valtest Run the test suite and examples with Valgrind to check for memory leaks'
|
||||||
|
@echo ' make calltest Run the test suite and examples with Callgrind'
|
||||||
@echo ' make dist Create a distribution tarball'
|
@echo ' make dist Create a distribution tarball'
|
||||||
@echo ' make docs Generate documentation'
|
@echo ' make docs Generate documentation'
|
||||||
@echo ' make debug Run janet with GDB or LLDB'
|
@echo ' make debug Run janet with GDB or LLDB'
|
||||||
@@ -437,6 +442,9 @@ help:
|
|||||||
@echo " make format Format Janet's own source files"
|
@echo " make format Format Janet's own source files"
|
||||||
@echo ' make grammar Generate a TextMate language grammar'
|
@echo ' make grammar Generate a TextMate language grammar'
|
||||||
@echo
|
@echo
|
||||||
|
@echo ' make install-jpm-git Install jpm into the current filesystem'
|
||||||
|
@echo ' make install-spork-git Install spork into the current filesystem'
|
||||||
|
@echo
|
||||||
|
|
||||||
.PHONY: clean install repl debug valgrind test \
|
.PHONY: clean install install-jpm-git install-spork-git repl debug valgrind test \
|
||||||
valtest dist uninstall docs grammar format help compile-commands
|
valtest callgrind callgrind-test dist uninstall docs grammar format help compile-commands
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ for %%f in (src\boot\*.c) do (
|
|||||||
)
|
)
|
||||||
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
|
||||||
@if errorlevel 1 goto :BUILDFAIL
|
@if errorlevel 1 goto :BUILDFAIL
|
||||||
|
@rem note that there is no default syspath being baked in
|
||||||
build\janet_boot . > build\c\janet.c
|
build\janet_boot . > build\c\janet.c
|
||||||
@if errorlevel 1 goto :BUILDFAIL
|
@if errorlevel 1 goto :BUILDFAIL
|
||||||
|
|
||||||
|
|||||||
3
examples/sample-bad-bundle1/info.jdn
Normal file
3
examples/sample-bad-bundle1/info.jdn
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@{
|
||||||
|
:name "sample-bad-bundle1"
|
||||||
|
}
|
||||||
3
examples/sample-bad-bundle2/info.jdn
Normal file
3
examples/sample-bad-bundle2/info.jdn
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@{
|
||||||
|
:name "sample-bad-bundle2"
|
||||||
|
}
|
||||||
5
janet.1
5
janet.1
@@ -214,7 +214,7 @@ Don't execute a script, only compile it to check for errors. Useful for linting
|
|||||||
.BR \-m\ syspath
|
.BR \-m\ syspath
|
||||||
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
|
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
|
||||||
from a directory different than the default. The default is set when Janet is built, and defaults to
|
from a directory different than the default. The default is set when Janet is built, and defaults to
|
||||||
/usr/local/lib/janet on Linux/Posix, and C:/Janet/Library on Windows. This option supersedes JANET_PATH.
|
/usr/local/lib/janet on Linux/Posix. On Windows, there is no default value. This option supersedes JANET_PATH.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-c\ source\ output
|
.BR \-c\ source\ output
|
||||||
@@ -255,8 +255,7 @@ and then arguments to the script.
|
|||||||
.RS
|
.RS
|
||||||
The location to look for Janet libraries. This is the only environment variable Janet needs to
|
The location to look for Janet libraries. This is the only environment variable Janet needs to
|
||||||
find native and source code modules. If no JANET_PATH is set, Janet will look in
|
find native and source code modules. If no JANET_PATH is set, Janet will look in
|
||||||
the default location set at compile time. This should be a list of as well as a colon
|
the default location set at compile time. This should be a colon-separated list of directory names on Linux/Posix, and a semicolon-separated list on Windows. Note that a typical setup (i.e. not NixOS / Guix) will only use a single directory.
|
||||||
separate list of such directories.
|
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.B JANET_PROFILE
|
.B JANET_PROFILE
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
project('janet', 'c',
|
project('janet', 'c',
|
||||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||||
version : '1.39.1')
|
version : '1.40.1')
|
||||||
|
|
||||||
# Global settings
|
# Global settings
|
||||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||||
@@ -281,6 +281,7 @@ test_files = [
|
|||||||
'test/suite-corelib.janet',
|
'test/suite-corelib.janet',
|
||||||
'test/suite-debug.janet',
|
'test/suite-debug.janet',
|
||||||
'test/suite-ev.janet',
|
'test/suite-ev.janet',
|
||||||
|
'test/suite-ev2.janet',
|
||||||
'test/suite-ffi.janet',
|
'test/suite-ffi.janet',
|
||||||
'test/suite-filewatch.janet',
|
'test/suite-filewatch.janet',
|
||||||
'test/suite-inttypes.janet',
|
'test/suite-inttypes.janet',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
(def defn :macro
|
(def defn :macro :flycheck
|
||||||
```
|
```
|
||||||
(defn name & more)
|
(defn name & more)
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
# Build return value
|
# Build return value
|
||||||
~(def ,name ,;modifiers (fn ,name ,;(tuple/slice more start)))))
|
~(def ,name ,;modifiers (fn ,name ,;(tuple/slice more start)))))
|
||||||
|
|
||||||
(defn defmacro :macro
|
(defn defmacro :macro :flycheck
|
||||||
"Define a macro."
|
"Define a macro."
|
||||||
[name & more]
|
[name & more]
|
||||||
(setdyn name @{}) # override old macro definitions in the case of a recursive macro
|
(setdyn name @{}) # override old macro definitions in the case of a recursive macro
|
||||||
@@ -57,12 +57,12 @@
|
|||||||
[f & args]
|
[f & args]
|
||||||
(f ;args))
|
(f ;args))
|
||||||
|
|
||||||
(defmacro defmacro-
|
(defmacro defmacro- :flycheck
|
||||||
"Define a private macro that will not be exported."
|
"Define a private macro that will not be exported."
|
||||||
[name & more]
|
[name & more]
|
||||||
(apply defn name :macro :private more))
|
(apply defn name :macro :private more))
|
||||||
|
|
||||||
(defmacro defn-
|
(defmacro defn- :flycheck
|
||||||
"Define a private function that will not be exported."
|
"Define a private function that will not be exported."
|
||||||
[name & more]
|
[name & more]
|
||||||
(apply defn name :private more))
|
(apply defn name :private more))
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
(defmacro /= "Shorthand for (set x (/ x n))." [x & ns] ~(set ,x (,/ ,x ,;ns)))
|
(defmacro /= "Shorthand for (set x (/ x n))." [x & ns] ~(set ,x (,/ ,x ,;ns)))
|
||||||
(defmacro %= "Shorthand for (set x (% x n))." [x & ns] ~(set ,x (,% ,x ,;ns)))
|
(defmacro %= "Shorthand for (set x (% x n))." [x & ns] ~(set ,x (,% ,x ,;ns)))
|
||||||
|
|
||||||
(defmacro assert
|
(defmacro assert :flycheck # should top level assert flycheck?
|
||||||
"Throw an error if x is not truthy. Will not evaluate `err` if x is truthy."
|
"Throw an error if x is not truthy. Will not evaluate `err` if x is truthy."
|
||||||
[x &opt err]
|
[x &opt err]
|
||||||
(def v (gensym))
|
(def v (gensym))
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
,v
|
,v
|
||||||
(,error ,(if err err (string/format "assert failure in %j" x))))))
|
(,error ,(if err err (string/format "assert failure in %j" x))))))
|
||||||
|
|
||||||
(defmacro defdyn
|
(defmacro defdyn :flycheck
|
||||||
``Define an alias for a keyword that is used as a dynamic binding. The
|
``Define an alias for a keyword that is used as a dynamic binding. The
|
||||||
alias is a normal, lexically scoped binding that can be used instead of
|
alias is a normal, lexically scoped binding that can be used instead of
|
||||||
a keyword to prevent typos. `defdyn` does not set dynamic bindings or otherwise
|
a keyword to prevent typos. `defdyn` does not set dynamic bindings or otherwise
|
||||||
@@ -171,6 +171,9 @@
|
|||||||
(defdyn *macro-form*
|
(defdyn *macro-form*
|
||||||
"Inside a macro, is bound to the source form that invoked the macro")
|
"Inside a macro, is bound to the source form that invoked the macro")
|
||||||
|
|
||||||
|
(defdyn *flychecking*
|
||||||
|
"Check if the current form is being evaluated inside `flycheck`. Will be `true` while flychecking.")
|
||||||
|
|
||||||
(defdyn *lint-error*
|
(defdyn *lint-error*
|
||||||
"The current lint error level. The error level is the lint level at which compilation will exit with an error and not continue.")
|
"The current lint error level. The error level is the lint level at which compilation will exit with an error and not continue.")
|
||||||
|
|
||||||
@@ -345,12 +348,15 @@
|
|||||||
[body catch]
|
[body catch]
|
||||||
(assert (and (not (empty? catch)) (indexed? (catch 0))) "the first element of `catch` must be a tuple or array")
|
(assert (and (not (empty? catch)) (indexed? (catch 0))) "the first element of `catch` must be a tuple or array")
|
||||||
(let [[err fib] (catch 0)
|
(let [[err fib] (catch 0)
|
||||||
r (or err (gensym))
|
r (gensym)
|
||||||
f (or fib (gensym))]
|
f (gensym)]
|
||||||
~(let [,f (,fiber/new (fn :try [] ,body) :ie)
|
~(let [,f (,fiber/new (fn :try [] ,body) :ie)
|
||||||
,r (,resume ,f)]
|
,r (,resume ,f)]
|
||||||
(if (,= (,fiber/status ,f) :error)
|
(if (,= (,fiber/status ,f) :error)
|
||||||
(do ,;(tuple/slice catch 1))
|
(do
|
||||||
|
,(if err ~(def ,err ,r))
|
||||||
|
,(if fib ~(def ,fib ,f))
|
||||||
|
,;(tuple/slice catch 1))
|
||||||
,r))))
|
,r))))
|
||||||
|
|
||||||
(defmacro with-syms
|
(defmacro with-syms
|
||||||
@@ -1800,8 +1806,8 @@
|
|||||||
(flatten-into @[] xs))
|
(flatten-into @[] xs))
|
||||||
|
|
||||||
(defn kvs
|
(defn kvs
|
||||||
``Takes a table or struct and returns and array of key value pairs
|
``Takes a table or struct and returns a new array of key value pairs
|
||||||
like `@[k v k v ...]`. Returns a new array.``
|
like `@[k v k v ...]`.``
|
||||||
[dict]
|
[dict]
|
||||||
(def ret @[])
|
(def ret @[])
|
||||||
(loop [k :keys dict] (array/push ret k (in dict k)))
|
(loop [k :keys dict] (array/push ret k (in dict k)))
|
||||||
@@ -2354,7 +2360,7 @@
|
|||||||
|
|
||||||
(set macexvar macex)
|
(set macexvar macex)
|
||||||
|
|
||||||
(defmacro varfn
|
(defmacro varfn :flycheck
|
||||||
``Create a function that can be rebound. `varfn` has the same signature
|
``Create a function that can be rebound. `varfn` has the same signature
|
||||||
as `defn`, but defines functions in the environment as vars. If a var `name`
|
as `defn`, but defines functions in the environment as vars. If a var `name`
|
||||||
already exists in the environment, it is rebound to the new function. Returns
|
already exists in the environment, it is rebound to the new function. Returns
|
||||||
@@ -3945,7 +3951,7 @@
|
|||||||
[& forms]
|
[& forms]
|
||||||
(def state (gensym))
|
(def state (gensym))
|
||||||
(def loaded (gensym))
|
(def loaded (gensym))
|
||||||
~((fn []
|
~((fn :delay []
|
||||||
(var ,state nil)
|
(var ,state nil)
|
||||||
(var ,loaded nil)
|
(var ,loaded nil)
|
||||||
(fn []
|
(fn []
|
||||||
@@ -3977,7 +3983,7 @@
|
|||||||
:lazy lazy
|
:lazy lazy
|
||||||
:map-symbols map-symbols}))
|
:map-symbols map-symbols}))
|
||||||
|
|
||||||
(defmacro ffi/defbind-alias
|
(defmacro ffi/defbind-alias :flycheck
|
||||||
"Generate bindings for native functions in a convenient manner.
|
"Generate bindings for native functions in a convenient manner.
|
||||||
Similar to defbind but allows for the janet function name to be
|
Similar to defbind but allows for the janet function name to be
|
||||||
different than the FFI function."
|
different than the FFI function."
|
||||||
@@ -3988,6 +3994,8 @@
|
|||||||
(def formal-args (map 0 arg-pairs))
|
(def formal-args (map 0 arg-pairs))
|
||||||
(def type-args (map 1 arg-pairs))
|
(def type-args (map 1 arg-pairs))
|
||||||
(def computed-type-args (eval ~[,;type-args]))
|
(def computed-type-args (eval ~[,;type-args]))
|
||||||
|
(if (dyn *flychecking*)
|
||||||
|
(break ~(defn ,alias ,;meta [,;formal-args] nil)))
|
||||||
(def {:native lib
|
(def {:native lib
|
||||||
:lazy lazy
|
:lazy lazy
|
||||||
:native-lazy llib
|
:native-lazy llib
|
||||||
@@ -4003,7 +4011,7 @@
|
|||||||
~(defn ,alias ,;meta [,;formal-args]
|
~(defn ,alias ,;meta [,;formal-args]
|
||||||
(,ffi/call ,(make-ptr) ,(make-sig) ,;formal-args))))
|
(,ffi/call ,(make-ptr) ,(make-sig) ,;formal-args))))
|
||||||
|
|
||||||
(defmacro ffi/defbind
|
(defmacro ffi/defbind :flycheck
|
||||||
"Generate bindings for native functions in a convenient manner."
|
"Generate bindings for native functions in a convenient manner."
|
||||||
[name ret-type & body]
|
[name ret-type & body]
|
||||||
~(ffi/defbind-alias ,name ,name ,ret-type ,;body)))
|
~(ffi/defbind-alias ,name ,name ,ret-type ,;body)))
|
||||||
@@ -4014,6 +4022,51 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
|
(def- flycheck-specials @{})
|
||||||
|
|
||||||
|
(defn- flycheck-evaluator
|
||||||
|
``
|
||||||
|
An evaluator function that is passed to `run-context` that lints
|
||||||
|
(flychecks) code for `flycheck`. This means code will be parsed,
|
||||||
|
compiled, and have macros expanded, but the code will not be
|
||||||
|
evaluated.
|
||||||
|
``
|
||||||
|
[thunk source env where]
|
||||||
|
(when (and (tuple? source) (= (tuple/type source) :parens))
|
||||||
|
(def head (source 0))
|
||||||
|
(def entry (get env head {}))
|
||||||
|
(def fc (get flycheck-specials head (get entry :flycheck)))
|
||||||
|
(cond
|
||||||
|
# Sometimes safe form
|
||||||
|
(function? fc)
|
||||||
|
(fc thunk source env where)
|
||||||
|
# Always safe form
|
||||||
|
fc
|
||||||
|
(thunk))))
|
||||||
|
|
||||||
|
(defn flycheck
|
||||||
|
```
|
||||||
|
Check a file for errors without running the file. Found errors
|
||||||
|
will be printed to stderr in the usual format. Top level functions
|
||||||
|
and macros that have the metadata `:flycheck` will also be evaluated
|
||||||
|
during flychecking. For full control, the `:flycheck` metadata can
|
||||||
|
also be a function that takes 4 arguments - `thunk`, `source`, `env`,
|
||||||
|
and `where`, the same as the `:evaluator` argument to `run-context`.
|
||||||
|
Other arguments to `flycheck` are the same as `dofile`. Returns nil.
|
||||||
|
```
|
||||||
|
[path &keys kwargs]
|
||||||
|
(def mc @{})
|
||||||
|
(def new-env (make-env (get kwargs :env)))
|
||||||
|
(put new-env *flychecking* true)
|
||||||
|
(put new-env *module-cache* @{})
|
||||||
|
(put new-env *module-loading* @{})
|
||||||
|
(put new-env *module-make-env* (fn :make-flycheck-env [&] (make-env new-env)))
|
||||||
|
(try
|
||||||
|
(dofile path :evaluator flycheck-evaluator ;(kvs kwargs) :env new-env)
|
||||||
|
([e f]
|
||||||
|
(debug/stacktrace f e "")))
|
||||||
|
nil)
|
||||||
|
|
||||||
(defn- no-side-effects
|
(defn- no-side-effects
|
||||||
`Check if form may have side effects. If returns true, then the src
|
`Check if form may have side effects. If returns true, then the src
|
||||||
must not have side effects, such as calling a C function.`
|
must not have side effects, such as calling a C function.`
|
||||||
@@ -4029,59 +4082,29 @@
|
|||||||
(all no-side-effects (values src)))
|
(all no-side-effects (values src)))
|
||||||
true))
|
true))
|
||||||
|
|
||||||
(defn- is-safe-def [x] (no-side-effects (last x)))
|
(defn- is-safe-def [thunk source env where]
|
||||||
|
(if (no-side-effects (last source))
|
||||||
|
(thunk)))
|
||||||
|
|
||||||
(def- safe-forms {'defn true 'varfn true 'defn- true 'defmacro true 'defmacro- true
|
(defn- flycheck-importer
|
||||||
'def is-safe-def 'var is-safe-def 'def- is-safe-def 'var- is-safe-def
|
|
||||||
'defglobal is-safe-def 'varglobal is-safe-def 'defdyn true})
|
|
||||||
|
|
||||||
(def- importers {'import true 'import* true 'dofile true 'require true})
|
|
||||||
(defn- use-2 [evaluator args]
|
|
||||||
(each a args (import* (string a) :prefix "" :evaluator evaluator)))
|
|
||||||
|
|
||||||
(defn- flycheck-evaluator
|
|
||||||
``An evaluator function that is passed to `run-context` that lints (flychecks) code.
|
|
||||||
This means code will parsed and compiled, macros executed, but the code will not be run.
|
|
||||||
Used by `flycheck`.``
|
|
||||||
[thunk source env where]
|
[thunk source env where]
|
||||||
(when (tuple? source)
|
(let [[l c] (tuple/sourcemap source)
|
||||||
(def head (source 0))
|
newtup (tuple/setmap (tuple ;source :evaluator flycheck-evaluator) l c)]
|
||||||
(def safe-check
|
((compile newtup env where))))
|
||||||
(or
|
|
||||||
(safe-forms head)
|
|
||||||
(if (symbol? head)
|
|
||||||
(if (string/has-prefix? "define-" head) is-safe-def))))
|
|
||||||
(cond
|
|
||||||
# Sometimes safe form
|
|
||||||
(function? safe-check)
|
|
||||||
(if (safe-check source) (thunk))
|
|
||||||
# Always safe form
|
|
||||||
safe-check
|
|
||||||
(thunk)
|
|
||||||
# Use
|
|
||||||
(= 'use head)
|
|
||||||
(use-2 flycheck-evaluator (tuple/slice source 1))
|
|
||||||
# Import-like form
|
|
||||||
(importers head)
|
|
||||||
(let [[l c] (tuple/sourcemap source)
|
|
||||||
newtup (tuple/setmap (tuple ;source :evaluator flycheck-evaluator) l c)]
|
|
||||||
((compile newtup env where))))))
|
|
||||||
|
|
||||||
(defn flycheck
|
(defn- flycheck-use
|
||||||
``Check a file for errors without running the file. Found errors will be printed to stderr
|
[thunk source env where]
|
||||||
in the usual format. Macros will still be executed, however, so
|
(each a (drop 1 source) (import* (string a) :prefix "" :evaluator flycheck-evaluator)))
|
||||||
arbitrary execution is possible. Other arguments are the same as `dofile`. `path` can also be
|
|
||||||
a file value such as stdin. Returns nil.``
|
# Add metadata to defs and import macros for flychecking
|
||||||
[path &keys kwargs]
|
(each sym ['def 'var]
|
||||||
(def old-modcache (table/clone module/cache))
|
(put flycheck-specials sym is-safe-def))
|
||||||
(table/clear module/cache)
|
(each sym ['def- 'var- 'defglobal 'varglobal]
|
||||||
(try
|
(put (dyn sym) :flycheck is-safe-def))
|
||||||
(dofile path :evaluator flycheck-evaluator ;(kvs kwargs))
|
(each sym ['import 'import* 'dofile 'require]
|
||||||
([e f]
|
(put (dyn sym) :flycheck flycheck-importer))
|
||||||
(debug/stacktrace f e "")))
|
(each sym ['use]
|
||||||
(table/clear module/cache)
|
(put (dyn sym) :flycheck flycheck-use))
|
||||||
(merge-into module/cache old-modcache)
|
|
||||||
nil)
|
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@@ -4174,7 +4197,7 @@
|
|||||||
(spit manifest-name b))
|
(spit manifest-name b))
|
||||||
|
|
||||||
(defn bundle/manifest
|
(defn bundle/manifest
|
||||||
"Get the manifest for a give installed bundle"
|
"Get the manifest for a given installed bundle."
|
||||||
[bundle-name]
|
[bundle-name]
|
||||||
(def name (get-manifest-filename bundle-name))
|
(def name (get-manifest-filename bundle-name))
|
||||||
(assertf (fexists name) "no bundle %v found" bundle-name)
|
(assertf (fexists name) "no bundle %v found" bundle-name)
|
||||||
@@ -4199,7 +4222,9 @@
|
|||||||
(put new-env *syspath* fixed-syspath)
|
(put new-env *syspath* fixed-syspath)
|
||||||
(with-env new-env
|
(with-env new-env
|
||||||
(put new-env :bundle-dir (bundle-dir bundle-name)) # get the syspath right
|
(put new-env :bundle-dir (bundle-dir bundle-name)) # get the syspath right
|
||||||
(require (string "@syspath/bundle/" bundle-name)))))
|
(try
|
||||||
|
(require (string "@syspath/bundle/" bundle-name))
|
||||||
|
([_] (error "bundle must contain bundle.janet or bundle/init.janet"))))))
|
||||||
|
|
||||||
(defn- do-hook
|
(defn- do-hook
|
||||||
[module bundle-name hook & args]
|
[module bundle-name hook & args]
|
||||||
@@ -4236,7 +4261,9 @@
|
|||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defn bundle/uninstall
|
(defn bundle/uninstall
|
||||||
"Remove a bundle from the current syspath"
|
``Remove a bundle from the current syspath. There is 1 hook called during
|
||||||
|
uninstallation (uninstall). A user can register a hook by defining a
|
||||||
|
function with the same name in the bundle script.``
|
||||||
[bundle-name]
|
[bundle-name]
|
||||||
(def breakage @{})
|
(def breakage @{})
|
||||||
(each b (bundle/list)
|
(each b (bundle/list)
|
||||||
@@ -4272,8 +4299,8 @@
|
|||||||
order)
|
order)
|
||||||
|
|
||||||
(defn bundle/prune
|
(defn bundle/prune
|
||||||
"Remove all orphaned bundles from the syspath. An orphaned bundle is a bundle that is
|
``Remove all orphaned bundles from the current syspath. An orphaned bundle is a
|
||||||
marked for :auto-remove and is not depended on by any other bundle."
|
bundle that is marked for :auto-remove and is not depended on by any other bundle.``
|
||||||
[]
|
[]
|
||||||
(def topo (bundle/topolist))
|
(def topo (bundle/topolist))
|
||||||
(def rtopo (reverse topo))
|
(def rtopo (reverse topo))
|
||||||
@@ -4302,33 +4329,44 @@
|
|||||||
(not (not (os/stat (bundle-dir bundle-name) :mode))))
|
(not (not (os/stat (bundle-dir bundle-name) :mode))))
|
||||||
|
|
||||||
(defn bundle/install
|
(defn bundle/install
|
||||||
"Install a bundle from the local filesystem. The name of the bundle will be inferred from the bundle, or passed as a parameter :name in `config`."
|
``Install a bundle from the local filesystem. The name of the bundle is
|
||||||
|
the value mapped to :name in either `config` or the info file. There are
|
||||||
|
5 hooks called during installation (postdeps, clean, build, install and
|
||||||
|
check). A user can register a hook by defining a function with the same name
|
||||||
|
in the bundle script.``
|
||||||
[path &keys config]
|
[path &keys config]
|
||||||
(def path (bundle-rpath path))
|
(def path (bundle-rpath path))
|
||||||
(def s (sep))
|
(def s (sep))
|
||||||
# Detect bundle name
|
# Detect bundle name
|
||||||
(def infofile-src1 (string path s "bundle" s "info.jdn"))
|
(def infofile-src1 (string path s "bundle" s "info.jdn"))
|
||||||
(def infofile-src2 (string path s "info.jdn"))
|
(def infofile-src2 (string path s "info.jdn"))
|
||||||
(def infofile-src (cond (fexists infofile-src1) infofile-src1
|
(def infofile-src (cond
|
||||||
(fexists infofile-src2) infofile-src2))
|
(fexists infofile-src1) infofile-src1
|
||||||
|
(fexists infofile-src2) infofile-src2))
|
||||||
(def info (-?> infofile-src slurp parse))
|
(def info (-?> infofile-src slurp parse))
|
||||||
(def bundle-name (get config :name (get info :name)))
|
(def bundle-name (get config :name (get info :name)))
|
||||||
(assertf bundle-name "unable to infer bundle name for %v, use :name argument" path)
|
(assertf bundle-name
|
||||||
|
"unable to infer bundle name for %v, use :name argument or add :name to info file" path)
|
||||||
(assertf (not (string/check-set "\\/" bundle-name))
|
(assertf (not (string/check-set "\\/" bundle-name))
|
||||||
"bundle name %v cannot contain path separators" bundle-name)
|
"bundle name %v cannot contain path separators" bundle-name)
|
||||||
(assert (next bundle-name) "cannot use empty bundle-name")
|
(assert (next bundle-name) "cannot use empty bundle-name")
|
||||||
(assertf (not (fexists (get-manifest-filename bundle-name)))
|
(assertf (not (fexists (get-manifest-filename bundle-name)))
|
||||||
"bundle %v is already installed" bundle-name)
|
"bundle %v is already installed" bundle-name)
|
||||||
|
# Check bscript
|
||||||
|
(def bscript-src1 (string path s "bundle" s "init.janet"))
|
||||||
|
(def bscript-src2 (string path s "bundle.janet"))
|
||||||
|
(def bscript-src (cond
|
||||||
|
(fexists bscript-src1) bscript-src1
|
||||||
|
(fexists bscript-src2) bscript-src2))
|
||||||
# Setup installed paths
|
# Setup installed paths
|
||||||
(prime-bundle-paths)
|
(prime-bundle-paths)
|
||||||
(os/mkdir (bundle-dir bundle-name))
|
(os/mkdir (bundle-dir bundle-name))
|
||||||
# Copy infofile
|
# Copy aliased infofile
|
||||||
(def infofile-dest (bundle-file bundle-name "info.jdn"))
|
(when (fexists infofile-src2)
|
||||||
(when infofile-src (copyfile infofile-src infofile-dest))
|
(copyfile infofile-src2 (bundle-file bundle-name "info.jdn")))
|
||||||
# Copy aliased initfile
|
# Copy aliased bscript
|
||||||
(def initfile-alias (string path s "bundle.janet"))
|
(when (fexists bscript-src2)
|
||||||
(def initfile-dest (bundle-file bundle-name "init.janet"))
|
(copyfile bscript-src2 (bundle-file bundle-name "init.janet")))
|
||||||
(when (fexists initfile-alias) (copyfile initfile-alias initfile-dest))
|
|
||||||
# Copy some files into the new location unconditionally
|
# Copy some files into the new location unconditionally
|
||||||
(def implicit-sources (string path s "bundle"))
|
(def implicit-sources (string path s "bundle"))
|
||||||
(when (= :directory (os/stat implicit-sources :mode))
|
(when (= :directory (os/stat implicit-sources :mode))
|
||||||
@@ -4337,21 +4375,21 @@
|
|||||||
(merge-into man config)
|
(merge-into man config)
|
||||||
(sync-manifest man)
|
(sync-manifest man)
|
||||||
(edefer (do (print "installation error, uninstalling") (bundle/uninstall bundle-name))
|
(edefer (do (print "installation error, uninstalling") (bundle/uninstall bundle-name))
|
||||||
(when (os/stat infofile-dest :mode)
|
(when info
|
||||||
(def info (-> infofile-dest slurp parse))
|
|
||||||
(def deps (seq [d :in (get info :dependencies @[])]
|
(def deps (seq [d :in (get info :dependencies @[])]
|
||||||
(string (if (dictionary? d) (get d :name) d))))
|
(string (if (dictionary? d) (get d :name) d))))
|
||||||
(def missing (filter (complement bundle/installed?) deps))
|
(def missing (filter (complement bundle/installed?) deps))
|
||||||
(when (next missing)
|
(when (next missing)
|
||||||
(error (string "missing dependencies " (string/join missing ", "))))
|
(error (string "missing dependencies " (string/join missing ", "))))
|
||||||
(put man :dependencies deps)
|
(put man :dependencies deps)
|
||||||
(put man :info info))
|
(put man :info info))
|
||||||
|
(def module (get-bundle-module bundle-name))
|
||||||
(def clean (get config :clean))
|
(def clean (get config :clean))
|
||||||
(def check (get config :check))
|
(def check (get config :check))
|
||||||
(def module (get-bundle-module bundle-name))
|
|
||||||
(def all-hooks (seq [[k v] :pairs module :when (symbol? k) :unless (get v :private)] (keyword k)))
|
(def all-hooks (seq [[k v] :pairs module :when (symbol? k) :unless (get v :private)] (keyword k)))
|
||||||
(put man :hooks all-hooks)
|
(put man :hooks all-hooks)
|
||||||
(do-hook module bundle-name :dependencies man)
|
(do-hook module bundle-name :dependencies man) # deprecated, use :postdeps
|
||||||
|
(do-hook module bundle-name :postdeps man)
|
||||||
(when clean
|
(when clean
|
||||||
(do-hook module bundle-name :clean man))
|
(do-hook module bundle-name :clean man))
|
||||||
(do-hook module bundle-name :build man)
|
(do-hook module bundle-name :build man)
|
||||||
@@ -4361,15 +4399,21 @@
|
|||||||
(when check
|
(when check
|
||||||
(do-hook module bundle-name :check man)))
|
(do-hook module bundle-name :check man)))
|
||||||
(print "installed " bundle-name)
|
(print "installed " bundle-name)
|
||||||
(when (get man :has-bin-script)
|
(when (or (get man :has-exe)
|
||||||
|
# remove eventually
|
||||||
|
(get man :has-bin-script))
|
||||||
(def binpath (string (dyn *syspath*) s "bin"))
|
(def binpath (string (dyn *syspath*) s "bin"))
|
||||||
(eprintf "executable scripts have been installed to %s" binpath))
|
(eprintf "executable files have been installed to %s" binpath))
|
||||||
|
(when (get man :has-man)
|
||||||
|
(def manpath (string (dyn *syspath*) s "man"))
|
||||||
|
(eprintf "man pages have been installed to %s" manpath))
|
||||||
bundle-name)
|
bundle-name)
|
||||||
|
|
||||||
(defn- bundle/pack
|
(defn- bundle/pack
|
||||||
"Take an installed bundle and create a bundle source directory that can be used to
|
``Take an installed bundle and create a bundle source directory that can be
|
||||||
reinstall the bundle on a compatible system. This is used to create backups for installed
|
used to reinstall the bundle on a compatible system. This is used to create
|
||||||
bundles without rebuilding, or make a prebuilt bundle for other systems."
|
backups for installed bundles without rebuilding, or make a prebuilt bundle
|
||||||
|
for other systems.``
|
||||||
[bundle-name dest-dir &opt is-backup]
|
[bundle-name dest-dir &opt is-backup]
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(def man (bundle/manifest bundle-name))
|
(def man (bundle/manifest bundle-name))
|
||||||
@@ -4399,9 +4443,9 @@
|
|||||||
dest-dir)
|
dest-dir)
|
||||||
|
|
||||||
(defn bundle/replace
|
(defn bundle/replace
|
||||||
"Reinstall an existing bundle from a new directory. Similar to bundle/reinstall,
|
``Reinstall an existing bundle from a new directory. Similar to
|
||||||
but installs the replacement bundle from any directory. This is necesarry to replace a package without
|
bundle/reinstall, but installs the replacement bundle from any directory.
|
||||||
breaking any dependencies."
|
This is necessary to replace a package without breaking any dependencies.``
|
||||||
[bundle-name path &keys new-config]
|
[bundle-name path &keys new-config]
|
||||||
(def manifest (bundle/manifest bundle-name))
|
(def manifest (bundle/manifest bundle-name))
|
||||||
(def config (get manifest :config @{}))
|
(def config (get manifest :config @{}))
|
||||||
@@ -4428,7 +4472,7 @@
|
|||||||
bundle-name)
|
bundle-name)
|
||||||
|
|
||||||
(defn bundle/add-directory
|
(defn bundle/add-directory
|
||||||
"Add a directory during the install process relative to `(dyn *syspath*)`"
|
"Add a directory during an install relative to `(dyn *syspath*)`."
|
||||||
[manifest dest &opt chmod-mode]
|
[manifest dest &opt chmod-mode]
|
||||||
(def files (get-files manifest))
|
(def files (get-files manifest))
|
||||||
(def s (sep))
|
(def s (sep))
|
||||||
@@ -4456,7 +4500,7 @@
|
|||||||
ret)
|
ret)
|
||||||
|
|
||||||
(defn bundle/add-file
|
(defn bundle/add-file
|
||||||
"Add files during an install relative to `(dyn *syspath*)`"
|
"Add a file during an install relative to `(dyn *syspath*)`."
|
||||||
[manifest src &opt dest chmod-mode]
|
[manifest src &opt dest chmod-mode]
|
||||||
(default dest src)
|
(default dest src)
|
||||||
(def files (get-files manifest))
|
(def files (get-files manifest))
|
||||||
@@ -4473,9 +4517,9 @@
|
|||||||
absdest)
|
absdest)
|
||||||
|
|
||||||
(defn bundle/add
|
(defn bundle/add
|
||||||
"Add files and directories during a bundle install relative to `(dyn *syspath*)`.
|
``Add a file or directory during an install relative to `(dyn *syspath*)`.
|
||||||
Added files and directories will be recorded in the bundle manifest such that they are properly tracked
|
Added files and directories will be recorded in the bundle manifest such
|
||||||
and removed during an upgrade or uninstall."
|
that they are properly tracked and removed during an upgrade or uninstall.``
|
||||||
[manifest src &opt dest chmod-mode]
|
[manifest src &opt dest chmod-mode]
|
||||||
(default dest src)
|
(default dest src)
|
||||||
(def s (sep))
|
(def s (sep))
|
||||||
@@ -4490,20 +4534,31 @@
|
|||||||
(errorf "bad path %s - file is a %s" src mode)))
|
(errorf "bad path %s - file is a %s" src mode)))
|
||||||
|
|
||||||
(defn bundle/add-bin
|
(defn bundle/add-bin
|
||||||
``
|
``Add a file to the "bin" subdirectory of the current syspath. By default,
|
||||||
Shorthand for adding scripts during an install. Scripts will be installed to
|
files will be set to be executable.``
|
||||||
`(string (dyn *syspath*) "/bin")` by default and will be set to be executable.
|
[manifest src &opt filename chmod-mode]
|
||||||
``
|
|
||||||
[manifest src &opt dest chmod-mode]
|
|
||||||
(def s (sep))
|
(def s (sep))
|
||||||
(default dest (last (string/split s src)))
|
(default filename (last (string/split s src)))
|
||||||
(default chmod-mode 8r755)
|
(default chmod-mode 8r755)
|
||||||
(os/mkdir (string (dyn *syspath*) s "bin"))
|
(os/mkdir (string (dyn *syspath*) s "bin"))
|
||||||
(put manifest :has-bin-script true)
|
(put manifest :has-exe true)
|
||||||
(bundle/add-file manifest src (string "bin" s dest) chmod-mode))
|
(put manifest :has-bin-script true) # remove eventually
|
||||||
|
(bundle/add-file manifest src (string "bin" s filename) chmod-mode))
|
||||||
|
|
||||||
|
(defn bundle/add-manpage
|
||||||
|
``Add a file to the man subdirectory of the current syspath. Files are
|
||||||
|
copied inside a directory `mansec`. By default, `mansec` is "man1".``
|
||||||
|
[manifest src &opt mansec]
|
||||||
|
(def s (sep))
|
||||||
|
(default mansec "man1")
|
||||||
|
(def filename (last (string/split s src)))
|
||||||
|
(os/mkdir (string (dyn *syspath*) s "man"))
|
||||||
|
(os/mkdir (string (dyn *syspath*) s "man" s mansec))
|
||||||
|
(put manifest :has-man true)
|
||||||
|
(bundle/add-file manifest src (string "man" s mansec s filename)))
|
||||||
|
|
||||||
(defn bundle/update-all
|
(defn bundle/update-all
|
||||||
"Reinstall all bundles"
|
"Reinstall all bundles."
|
||||||
[&keys configs]
|
[&keys configs]
|
||||||
(each bundle (bundle/topolist)
|
(each bundle (bundle/topolist)
|
||||||
(bundle/reinstall bundle ;(kvs configs)))))
|
(bundle/reinstall bundle ;(kvs configs)))))
|
||||||
@@ -4515,7 +4570,10 @@
|
|||||||
###
|
###
|
||||||
|
|
||||||
# conditional compilation for reduced os
|
# conditional compilation for reduced os
|
||||||
(def- getenv-alias (if-let [entry (in root-env 'os/getenv)] (entry :value) (fn [&])))
|
(def- getenv-raw (if-let [entry (in root-env 'os/getenv)] (entry :value) (fn [&])))
|
||||||
|
(defn- getenv-alias [env-var &opt dflt]
|
||||||
|
(def x (getenv-raw env-var dflt))
|
||||||
|
(if (= x "") nil x)) # empty string is coerced to nil
|
||||||
|
|
||||||
(defn- run-main
|
(defn- run-main
|
||||||
[env subargs arg]
|
[env subargs arg]
|
||||||
@@ -4638,7 +4696,7 @@
|
|||||||
--reinstall (-B) name : Reinstall a bundle by bundle name
|
--reinstall (-B) name : Reinstall a bundle by bundle name
|
||||||
--uninstall (-u) name : Uninstall a bundle by bundle name
|
--uninstall (-u) name : Uninstall a bundle by bundle name
|
||||||
--update-all (-U) : Reinstall all installed bundles
|
--update-all (-U) : Reinstall all installed bundles
|
||||||
--prune (-P) : Uninstalled all bundles that are orphaned
|
--prune (-P) : Uninstall all bundles that are orphaned
|
||||||
--list (-L) : List all installed bundles
|
--list (-L) : List all installed bundles
|
||||||
-- : Stop handling options
|
-- : Stop handling options
|
||||||
```)
|
```)
|
||||||
@@ -4890,14 +4948,15 @@
|
|||||||
"src/core/wrap.c"])
|
"src/core/wrap.c"])
|
||||||
|
|
||||||
# Print janet.c to stdout
|
# Print janet.c to stdout
|
||||||
(print "/* Amalgamated build - DO NOT EDIT */")
|
(def image-only (has-value? boot/args "image-only"))
|
||||||
|
(print "/* " (if image-only "Image-only" "Amalgamated") " build - DO NOT EDIT */")
|
||||||
(print "/* Generated from janet version " janet/version "-" janet/build " */")
|
(print "/* Generated from janet version " janet/version "-" janet/build " */")
|
||||||
(print "#define JANET_BUILD \"" janet/build "\"")
|
(print "#define JANET_BUILD \"" janet/build "\"")
|
||||||
(print ```#define JANET_AMALG```)
|
(print ```#define JANET_AMALG```)
|
||||||
|
|
||||||
(defn do-one-file
|
(defn do-one-file
|
||||||
[fname]
|
[fname]
|
||||||
(unless (has-value? boot/args "image-only")
|
(unless image-only
|
||||||
(print "\n/* " fname " */")
|
(print "\n/* " fname " */")
|
||||||
(print "#line 0 \"" fname "\"\n")
|
(print "#line 0 \"" fname "\"\n")
|
||||||
(def source (slurp fname))
|
(def source (slurp fname))
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#define JANETCONF_H
|
#define JANETCONF_H
|
||||||
|
|
||||||
#define JANET_VERSION_MAJOR 1
|
#define JANET_VERSION_MAJOR 1
|
||||||
#define JANET_VERSION_MINOR 39
|
#define JANET_VERSION_MINOR 40
|
||||||
#define JANET_VERSION_PATCH 1
|
#define JANET_VERSION_PATCH 1
|
||||||
#define JANET_VERSION_EXTRA ""
|
#define JANET_VERSION_EXTRA ""
|
||||||
#define JANET_VERSION "1.39.1"
|
#define JANET_VERSION "1.40.1"
|
||||||
|
|
||||||
/* #define JANET_BUILD "local" */
|
/* #define JANET_BUILD "local" */
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ JanetModule janet_native(const char *name, const uint8_t **error) {
|
|||||||
JanetBuildConfig modconf = getter();
|
JanetBuildConfig modconf = getter();
|
||||||
JanetBuildConfig host = janet_config_current();
|
JanetBuildConfig host = janet_config_current();
|
||||||
if (host.major != modconf.major ||
|
if (host.major != modconf.major ||
|
||||||
host.minor < modconf.minor ||
|
host.minor != modconf.minor ||
|
||||||
host.bits != modconf.bits) {
|
host.bits != modconf.bits) {
|
||||||
char errbuf[128];
|
char errbuf[128];
|
||||||
snprintf(errbuf, sizeof(errbuf), "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
|
snprintf(errbuf, sizeof(errbuf), "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
|
||||||
@@ -746,6 +746,7 @@ typedef struct SandboxOption {
|
|||||||
|
|
||||||
static const SandboxOption sandbox_options[] = {
|
static const SandboxOption sandbox_options[] = {
|
||||||
{"all", JANET_SANDBOX_ALL},
|
{"all", JANET_SANDBOX_ALL},
|
||||||
|
{"chroot", JANET_SANDBOX_CHROOT},
|
||||||
{"env", JANET_SANDBOX_ENV},
|
{"env", JANET_SANDBOX_ENV},
|
||||||
{"ffi", JANET_SANDBOX_FFI},
|
{"ffi", JANET_SANDBOX_FFI},
|
||||||
{"ffi-define", JANET_SANDBOX_FFI_DEFINE},
|
{"ffi-define", JANET_SANDBOX_FFI_DEFINE},
|
||||||
@@ -771,6 +772,7 @@ JANET_CORE_FN(janet_core_sandbox,
|
|||||||
"Disable feature sets to prevent the interpreter from using certain system resources. "
|
"Disable feature sets to prevent the interpreter from using certain system resources. "
|
||||||
"Once a feature is disabled, there is no way to re-enable it. Capabilities can be:\n\n"
|
"Once a feature is disabled, there is no way to re-enable it. Capabilities can be:\n\n"
|
||||||
"* :all - disallow all (except IO to stdout, stderr, and stdin)\n"
|
"* :all - disallow all (except IO to stdout, stderr, and stdin)\n"
|
||||||
|
"* :chroot - disallow calling `os/posix-chroot`\n"
|
||||||
"* :env - disallow reading and write env variables\n"
|
"* :env - disallow reading and write env variables\n"
|
||||||
"* :ffi - disallow FFI (recommended if disabling anything else)\n"
|
"* :ffi - disallow FFI (recommended if disabling anything else)\n"
|
||||||
"* :ffi-define - disallow loading new FFI modules and binding new functions\n"
|
"* :ffi-define - disallow loading new FFI modules and binding new functions\n"
|
||||||
@@ -995,11 +997,11 @@ static void make_apply(JanetTable *env) {
|
|||||||
janet_quick_asm(env, JANET_FUN_APPLY | JANET_FUNCDEF_FLAG_VARARG,
|
janet_quick_asm(env, JANET_FUN_APPLY | JANET_FUNCDEF_FLAG_VARARG,
|
||||||
"apply", 1, 1, INT32_MAX, 6, apply_asm, sizeof(apply_asm),
|
"apply", 1, 1, INT32_MAX, 6, apply_asm, sizeof(apply_asm),
|
||||||
JDOC("(apply f & args)\n\n"
|
JDOC("(apply f & args)\n\n"
|
||||||
"Applies a function f to a variable number of arguments. Each "
|
"Applies a function f to a variable number of arguments. Each "
|
||||||
"element in args is used as an argument to f, except the last "
|
"element in args is used as an argument to f, except the last "
|
||||||
"element in args, which is expected to be an array or a tuple. "
|
"element in args, which is expected to be an array or a tuple. "
|
||||||
"Each element in this last argument is then also pushed as an "
|
"Each element in this last argument is then also pushed as an "
|
||||||
"argument to f."));
|
"argument to f."));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t error_asm[] = {
|
static const uint32_t error_asm[] = {
|
||||||
@@ -1152,82 +1154,82 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
|||||||
janet_quick_asm(env, JANET_FUN_CMP,
|
janet_quick_asm(env, JANET_FUN_CMP,
|
||||||
"cmp", 2, 2, 2, 2, cmp_asm, sizeof(cmp_asm),
|
"cmp", 2, 2, 2, 2, cmp_asm, sizeof(cmp_asm),
|
||||||
JDOC("(cmp x y)\n\n"
|
JDOC("(cmp x y)\n\n"
|
||||||
"Returns -1 if x is strictly less than y, 1 if y is strictly greater "
|
"Returns -1 if x is strictly less than y, 1 if y is strictly greater "
|
||||||
"than x, and 0 otherwise. To return 0, x and y must be the exact same type."));
|
"than x, and 0 otherwise. To return 0, x and y must be the exact same type."));
|
||||||
janet_quick_asm(env, JANET_FUN_NEXT,
|
janet_quick_asm(env, JANET_FUN_NEXT,
|
||||||
"next", 2, 1, 2, 2, next_asm, sizeof(next_asm),
|
"next", 2, 1, 2, 2, next_asm, sizeof(next_asm),
|
||||||
JDOC("(next ds &opt key)\n\n"
|
JDOC("(next ds &opt key)\n\n"
|
||||||
"Gets the next key in a data structure. Can be used to iterate through "
|
"Gets the next key in a data structure. Can be used to iterate through "
|
||||||
"the keys of a data structure in an unspecified order. Keys are guaranteed "
|
"the keys of a data structure in an unspecified order. Keys are guaranteed "
|
||||||
"to be seen only once per iteration if the data structure is not mutated "
|
"to be seen only once per iteration if the data structure is not mutated "
|
||||||
"during iteration. If key is nil, next returns the first key. If next "
|
"during iteration. If key is nil, next returns the first key. If next "
|
||||||
"returns nil, there are no more keys to iterate through."));
|
"returns nil, there are no more keys to iterate through."));
|
||||||
janet_quick_asm(env, JANET_FUN_PROP,
|
janet_quick_asm(env, JANET_FUN_PROP,
|
||||||
"propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm),
|
"propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm),
|
||||||
JDOC("(propagate x fiber)\n\n"
|
JDOC("(propagate x fiber)\n\n"
|
||||||
"Propagate a signal from a fiber to the current fiber and "
|
"Propagate a signal from a fiber to the current fiber and "
|
||||||
"set the last value of the current fiber to `x`. The signal "
|
"set the last value of the current fiber to `x`. The signal "
|
||||||
"value is then available as the status of the current fiber. "
|
"value is then available as the status of the current fiber. "
|
||||||
"The resulting stack trace from the current fiber will include "
|
"The resulting stack trace from the current fiber will include "
|
||||||
"frames from fiber. If fiber is in a state that can be resumed, "
|
"frames from fiber. If fiber is in a state that can be resumed, "
|
||||||
"resuming the current fiber will first resume `fiber`. "
|
"resuming the current fiber will first resume `fiber`. "
|
||||||
"This function can be used to re-raise an error without losing "
|
"This function can be used to re-raise an error without losing "
|
||||||
"the original stack trace."));
|
"the original stack trace."));
|
||||||
janet_quick_asm(env, JANET_FUN_DEBUG,
|
janet_quick_asm(env, JANET_FUN_DEBUG,
|
||||||
"debug", 1, 0, 1, 1, debug_asm, sizeof(debug_asm),
|
"debug", 1, 0, 1, 1, debug_asm, sizeof(debug_asm),
|
||||||
JDOC("(debug &opt x)\n\n"
|
JDOC("(debug &opt x)\n\n"
|
||||||
"Throws a debug signal that can be caught by a parent fiber and used to inspect "
|
"Throws a debug signal that can be caught by a parent fiber and used to inspect "
|
||||||
"the running state of the current fiber. Returns the value passed in by resume."));
|
"the running state of the current fiber. Returns the value passed in by resume."));
|
||||||
janet_quick_asm(env, JANET_FUN_ERROR,
|
janet_quick_asm(env, JANET_FUN_ERROR,
|
||||||
"error", 1, 1, 1, 1, error_asm, sizeof(error_asm),
|
"error", 1, 1, 1, 1, error_asm, sizeof(error_asm),
|
||||||
JDOC("(error e)\n\n"
|
JDOC("(error e)\n\n"
|
||||||
"Throws an error e that can be caught and handled by a parent fiber."));
|
"Throws an error e that can be caught and handled by a parent fiber."));
|
||||||
janet_quick_asm(env, JANET_FUN_YIELD,
|
janet_quick_asm(env, JANET_FUN_YIELD,
|
||||||
"yield", 1, 0, 1, 2, yield_asm, sizeof(yield_asm),
|
"yield", 1, 0, 1, 2, yield_asm, sizeof(yield_asm),
|
||||||
JDOC("(yield &opt x)\n\n"
|
JDOC("(yield &opt x)\n\n"
|
||||||
"Yield a value to a parent fiber. When a fiber yields, its execution is paused until "
|
"Yield a value to a parent fiber. When a fiber yields, its execution is paused until "
|
||||||
"another thread resumes it. The fiber will then resume, and the last yield call will "
|
"another thread resumes it. The fiber will then resume, and the last yield call will "
|
||||||
"return the value that was passed to resume."));
|
"return the value that was passed to resume."));
|
||||||
janet_quick_asm(env, JANET_FUN_CANCEL,
|
janet_quick_asm(env, JANET_FUN_CANCEL,
|
||||||
"cancel", 2, 2, 2, 2, cancel_asm, sizeof(cancel_asm),
|
"cancel", 2, 2, 2, 2, cancel_asm, sizeof(cancel_asm),
|
||||||
JDOC("(cancel fiber err)\n\n"
|
JDOC("(cancel fiber err)\n\n"
|
||||||
"Resume a fiber but have it immediately raise an error. This lets a programmer unwind a pending fiber. "
|
"Resume a fiber but have it immediately raise an error. This lets a programmer unwind a pending fiber. "
|
||||||
"Returns the same result as resume."));
|
"Returns the same result as resume."));
|
||||||
janet_quick_asm(env, JANET_FUN_RESUME,
|
janet_quick_asm(env, JANET_FUN_RESUME,
|
||||||
"resume", 2, 1, 2, 2, resume_asm, sizeof(resume_asm),
|
"resume", 2, 1, 2, 2, resume_asm, sizeof(resume_asm),
|
||||||
JDOC("(resume fiber &opt x)\n\n"
|
JDOC("(resume fiber &opt x)\n\n"
|
||||||
"Resume a new or suspended fiber and optionally pass in a value to the fiber that "
|
"Resume a new or suspended fiber and optionally pass in a value to the fiber that "
|
||||||
"will be returned to the last yield in the case of a pending fiber, or the argument to "
|
"will be returned to the last yield in the case of a pending fiber, or the argument to "
|
||||||
"the dispatch function in the case of a new fiber. Returns either the return result of "
|
"the dispatch function in the case of a new fiber. Returns either the return result of "
|
||||||
"the fiber's dispatch function, or the value from the next yield call in fiber."));
|
"the fiber's dispatch function, or the value from the next yield call in fiber."));
|
||||||
janet_quick_asm(env, JANET_FUN_IN,
|
janet_quick_asm(env, JANET_FUN_IN,
|
||||||
"in", 3, 2, 3, 4, in_asm, sizeof(in_asm),
|
"in", 3, 2, 3, 4, in_asm, sizeof(in_asm),
|
||||||
JDOC("(in ds key &opt dflt)\n\n"
|
JDOC("(in ds key &opt dflt)\n\n"
|
||||||
"Get value in ds at key, works on associative data structures. Arrays, tuples, tables, structs, "
|
"Get value in ds at key, works on associative data structures. Arrays, tuples, tables, structs, "
|
||||||
"strings, symbols, and buffers are all associative and can be used. Arrays, tuples, strings, buffers, "
|
"strings, symbols, and buffers are all associative and can be used. Arrays, tuples, strings, buffers, "
|
||||||
"and symbols must use integer keys that are in bounds or an error is raised. Structs and tables can "
|
"and symbols must use integer keys that are in bounds or an error is raised. Structs and tables can "
|
||||||
"take any value as a key except nil and will return nil or dflt if not found."));
|
"take any value as a key except nil and will return nil or dflt if not found."));
|
||||||
janet_quick_asm(env, JANET_FUN_GET,
|
janet_quick_asm(env, JANET_FUN_GET,
|
||||||
"get", 3, 2, 3, 4, get_asm, sizeof(in_asm),
|
"get", 3, 2, 3, 4, get_asm, sizeof(in_asm),
|
||||||
JDOC("(get ds key &opt dflt)\n\n"
|
JDOC("(get ds key &opt dflt)\n\n"
|
||||||
"Get the value mapped to key in data structure ds, and return dflt or nil if not found. "
|
"Get the value mapped to key in data structure ds, and return dflt or nil if not found. "
|
||||||
"Similar to in, but will not throw an error if the key is invalid for the data structure "
|
"Similar to in, but will not throw an error if the key is invalid for the data structure "
|
||||||
"unless the data structure is an abstract type. In that case, the abstract type getter may throw "
|
"unless the data structure is an abstract type. In that case, the abstract type getter may throw "
|
||||||
"an error."));
|
"an error."));
|
||||||
janet_quick_asm(env, JANET_FUN_PUT,
|
janet_quick_asm(env, JANET_FUN_PUT,
|
||||||
"put", 3, 3, 3, 3, put_asm, sizeof(put_asm),
|
"put", 3, 3, 3, 3, put_asm, sizeof(put_asm),
|
||||||
JDOC("(put ds key value)\n\n"
|
JDOC("(put ds key value)\n\n"
|
||||||
"Associate a key with a value in any mutable associative data structure. Indexed data structures "
|
"Associate a key with a value in any mutable associative data structure. Indexed data structures "
|
||||||
"(arrays and buffers) only accept non-negative integer keys, and will expand if an out of bounds "
|
"(arrays and buffers) only accept non-negative integer keys, and will expand if an out of bounds "
|
||||||
"value is provided. In an array, extra space will be filled with nils, and in a buffer, extra "
|
"value is provided. In an array, extra space will be filled with nils, and in a buffer, extra "
|
||||||
"space will be filled with 0 bytes. In a table, putting a key that is contained in the table prototype "
|
"space will be filled with 0 bytes. In a table, putting a key that is contained in the table prototype "
|
||||||
"will hide the association defined by the prototype, but will not mutate the prototype table. Putting "
|
"will hide the association defined by the prototype, but will not mutate the prototype table. Putting "
|
||||||
"a value nil into a table will remove the key from the table. Returns the data structure ds."));
|
"a value nil into a table will remove the key from the table. Returns the data structure ds."));
|
||||||
janet_quick_asm(env, JANET_FUN_LENGTH,
|
janet_quick_asm(env, JANET_FUN_LENGTH,
|
||||||
"length", 1, 1, 1, 1, length_asm, sizeof(length_asm),
|
"length", 1, 1, 1, 1, length_asm, sizeof(length_asm),
|
||||||
JDOC("(length ds)\n\n"
|
JDOC("(length ds)\n\n"
|
||||||
"Returns the length or count of a data structure in constant time as an integer. For "
|
"Returns the length or count of a data structure in constant time as an integer. For "
|
||||||
"structs and tables, returns the number of key-value pairs in the data structure."));
|
"structs and tables, returns the number of key-value pairs in the data structure."));
|
||||||
janet_quick_asm(env, JANET_FUN_BNOT,
|
janet_quick_asm(env, JANET_FUN_BNOT,
|
||||||
"bnot", 1, 1, 1, 1, bnot_asm, sizeof(bnot_asm),
|
"bnot", 1, 1, 1, 1, bnot_asm, sizeof(bnot_asm),
|
||||||
JDOC("(bnot x)\n\nReturns the bit-wise inverse of integer x."));
|
JDOC("(bnot x)\n\nReturns the bit-wise inverse of integer x."));
|
||||||
@@ -1236,74 +1238,74 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
|||||||
/* Variadic ops */
|
/* Variadic ops */
|
||||||
templatize_varop(env, JANET_FUN_ADD, "+", 0, 0, JOP_ADD,
|
templatize_varop(env, JANET_FUN_ADD, "+", 0, 0, JOP_ADD,
|
||||||
JDOC("(+ & xs)\n\n"
|
JDOC("(+ & xs)\n\n"
|
||||||
"Returns the sum of all xs. xs must be integers or real numbers only. If xs is empty, return 0."));
|
"Returns the sum of all xs. xs must be integers or real numbers only. If xs is empty, return 0."));
|
||||||
templatize_varop(env, JANET_FUN_SUBTRACT, "-", 0, 0, JOP_SUBTRACT,
|
templatize_varop(env, JANET_FUN_SUBTRACT, "-", 0, 0, JOP_SUBTRACT,
|
||||||
JDOC("(- & xs)\n\n"
|
JDOC("(- & xs)\n\n"
|
||||||
"Returns the difference of xs. If xs is empty, returns 0. If xs has one element, returns the "
|
"Returns the difference of xs. If xs is empty, returns 0. If xs has one element, returns the "
|
||||||
"negative value of that element. Otherwise, returns the first element in xs minus the sum of "
|
"negative value of that element. Otherwise, returns the first element in xs minus the sum of "
|
||||||
"the rest of the elements."));
|
"the rest of the elements."));
|
||||||
templatize_varop(env, JANET_FUN_MULTIPLY, "*", 1, 1, JOP_MULTIPLY,
|
templatize_varop(env, JANET_FUN_MULTIPLY, "*", 1, 1, JOP_MULTIPLY,
|
||||||
JDOC("(* & xs)\n\n"
|
JDOC("(* & xs)\n\n"
|
||||||
"Returns the product of all elements in xs. If xs is empty, returns 1."));
|
"Returns the product of all elements in xs. If xs is empty, returns 1."));
|
||||||
templatize_varop(env, JANET_FUN_DIVIDE, "/", 1, 1, JOP_DIVIDE,
|
templatize_varop(env, JANET_FUN_DIVIDE, "/", 1, 1, JOP_DIVIDE,
|
||||||
JDOC("(/ & xs)\n\n"
|
JDOC("(/ & xs)\n\n"
|
||||||
"Returns the quotient of xs. If xs is empty, returns 1. If xs has one value x, returns "
|
"Returns the quotient of xs. If xs is empty, returns 1. If xs has one value x, returns "
|
||||||
"the reciprocal of x. Otherwise return the first value of xs repeatedly divided by the remaining "
|
"the reciprocal of x. Otherwise return the first value of xs repeatedly divided by the remaining "
|
||||||
"values."));
|
"values."));
|
||||||
templatize_varop(env, JANET_FUN_DIVIDE_FLOOR, "div", 1, 1, JOP_DIVIDE_FLOOR,
|
templatize_varop(env, JANET_FUN_DIVIDE_FLOOR, "div", 1, 1, JOP_DIVIDE_FLOOR,
|
||||||
JDOC("(div & xs)\n\n"
|
JDOC("(div & xs)\n\n"
|
||||||
"Returns the floored division of xs. If xs is empty, returns 1. If xs has one value x, returns "
|
"Returns the floored division of xs. If xs is empty, returns 1. If xs has one value x, returns "
|
||||||
"the reciprocal of x. Otherwise return the first value of xs repeatedly divided by the remaining "
|
"the reciprocal of x. Otherwise return the first value of xs repeatedly divided by the remaining "
|
||||||
"values."));
|
"values."));
|
||||||
templatize_varop(env, JANET_FUN_MODULO, "mod", 0, 1, JOP_MODULO,
|
templatize_varop(env, JANET_FUN_MODULO, "mod", 0, 1, JOP_MODULO,
|
||||||
JDOC("(mod & xs)\n\n"
|
JDOC("(mod & xs)\n\n"
|
||||||
"Returns the result of applying the modulo operator on the first value of xs with each remaining value. "
|
"Returns the result of applying the modulo operator on the first value of xs with each remaining value. "
|
||||||
"`(mod x 0)` is defined to be `x`."));
|
"`(mod x 0)` is defined to be `x`."));
|
||||||
templatize_varop(env, JANET_FUN_REMAINDER, "%", 0, 1, JOP_REMAINDER,
|
templatize_varop(env, JANET_FUN_REMAINDER, "%", 0, 1, JOP_REMAINDER,
|
||||||
JDOC("(% & xs)\n\n"
|
JDOC("(% & xs)\n\n"
|
||||||
"Returns the remainder of dividing the first value of xs by each remaining value."));
|
"Returns the remainder of dividing the first value of xs by each remaining value."));
|
||||||
templatize_varop(env, JANET_FUN_BAND, "band", -1, -1, JOP_BAND,
|
templatize_varop(env, JANET_FUN_BAND, "band", -1, -1, JOP_BAND,
|
||||||
JDOC("(band & xs)\n\n"
|
JDOC("(band & xs)\n\n"
|
||||||
"Returns the bit-wise and of all values in xs. Each x in xs must be an integer."));
|
"Returns the bit-wise and of all values in xs. Each x in xs must be an integer."));
|
||||||
templatize_varop(env, JANET_FUN_BOR, "bor", 0, 0, JOP_BOR,
|
templatize_varop(env, JANET_FUN_BOR, "bor", 0, 0, JOP_BOR,
|
||||||
JDOC("(bor & xs)\n\n"
|
JDOC("(bor & xs)\n\n"
|
||||||
"Returns the bit-wise or of all values in xs. Each x in xs must be an integer."));
|
"Returns the bit-wise or of all values in xs. Each x in xs must be an integer."));
|
||||||
templatize_varop(env, JANET_FUN_BXOR, "bxor", 0, 0, JOP_BXOR,
|
templatize_varop(env, JANET_FUN_BXOR, "bxor", 0, 0, JOP_BXOR,
|
||||||
JDOC("(bxor & xs)\n\n"
|
JDOC("(bxor & xs)\n\n"
|
||||||
"Returns the bit-wise xor of all values in xs. Each in xs must be an integer."));
|
"Returns the bit-wise xor of all values in xs. Each in xs must be an integer."));
|
||||||
templatize_varop(env, JANET_FUN_LSHIFT, "blshift", 1, 1, JOP_SHIFT_LEFT,
|
templatize_varop(env, JANET_FUN_LSHIFT, "blshift", 1, 1, JOP_SHIFT_LEFT,
|
||||||
JDOC("(blshift x & shifts)\n\n"
|
JDOC("(blshift x & shifts)\n\n"
|
||||||
"Returns the value of x bit shifted left by the sum of all values in shifts. x "
|
"Returns the value of x bit shifted left by the sum of all values in shifts. x "
|
||||||
"and each element in shift must be an integer."));
|
"and each element in shift must be an integer."));
|
||||||
templatize_varop(env, JANET_FUN_RSHIFT, "brshift", 1, 1, JOP_SHIFT_RIGHT,
|
templatize_varop(env, JANET_FUN_RSHIFT, "brshift", 1, 1, JOP_SHIFT_RIGHT,
|
||||||
JDOC("(brshift x & shifts)\n\n"
|
JDOC("(brshift x & shifts)\n\n"
|
||||||
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
|
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
|
||||||
"and each element in shift must be an integer."));
|
"and each element in shift must be an integer."));
|
||||||
templatize_varop(env, JANET_FUN_RSHIFTU, "brushift", 1, 1, JOP_SHIFT_RIGHT_UNSIGNED,
|
templatize_varop(env, JANET_FUN_RSHIFTU, "brushift", 1, 1, JOP_SHIFT_RIGHT_UNSIGNED,
|
||||||
JDOC("(brushift x & shifts)\n\n"
|
JDOC("(brushift x & shifts)\n\n"
|
||||||
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
|
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
|
||||||
"and each element in shift must be an integer. The sign of x is not preserved, so "
|
"and each element in shift must be an integer. The sign of x is not preserved, so "
|
||||||
"for positive shifts the return value will always be positive."));
|
"for positive shifts the return value will always be positive."));
|
||||||
|
|
||||||
/* Variadic comparators */
|
/* Variadic comparators */
|
||||||
templatize_comparator(env, JANET_FUN_GT, ">", 0, JOP_GREATER_THAN,
|
templatize_comparator(env, JANET_FUN_GT, ">", 0, JOP_GREATER_THAN,
|
||||||
JDOC("(> & xs)\n\n"
|
JDOC("(> & xs)\n\n"
|
||||||
"Check if xs is in descending order. Returns a boolean."));
|
"Check if xs is in descending order. Returns a boolean."));
|
||||||
templatize_comparator(env, JANET_FUN_LT, "<", 0, JOP_LESS_THAN,
|
templatize_comparator(env, JANET_FUN_LT, "<", 0, JOP_LESS_THAN,
|
||||||
JDOC("(< & xs)\n\n"
|
JDOC("(< & xs)\n\n"
|
||||||
"Check if xs is in ascending order. Returns a boolean."));
|
"Check if xs is in ascending order. Returns a boolean."));
|
||||||
templatize_comparator(env, JANET_FUN_GTE, ">=", 0, JOP_GREATER_THAN_EQUAL,
|
templatize_comparator(env, JANET_FUN_GTE, ">=", 0, JOP_GREATER_THAN_EQUAL,
|
||||||
JDOC("(>= & xs)\n\n"
|
JDOC("(>= & xs)\n\n"
|
||||||
"Check if xs is in non-ascending order. Returns a boolean."));
|
"Check if xs is in non-ascending order. Returns a boolean."));
|
||||||
templatize_comparator(env, JANET_FUN_LTE, "<=", 0, JOP_LESS_THAN_EQUAL,
|
templatize_comparator(env, JANET_FUN_LTE, "<=", 0, JOP_LESS_THAN_EQUAL,
|
||||||
JDOC("(<= & xs)\n\n"
|
JDOC("(<= & xs)\n\n"
|
||||||
"Check if xs is in non-descending order. Returns a boolean."));
|
"Check if xs is in non-descending order. Returns a boolean."));
|
||||||
templatize_comparator(env, JANET_FUN_EQ, "=", 0, JOP_EQUALS,
|
templatize_comparator(env, JANET_FUN_EQ, "=", 0, JOP_EQUALS,
|
||||||
JDOC("(= & xs)\n\n"
|
JDOC("(= & xs)\n\n"
|
||||||
"Check if all values in xs are equal. Returns a boolean."));
|
"Check if all values in xs are equal. Returns a boolean."));
|
||||||
templatize_comparator(env, JANET_FUN_NEQ, "not=", 1, JOP_EQUALS,
|
templatize_comparator(env, JANET_FUN_NEQ, "not=", 1, JOP_EQUALS,
|
||||||
JDOC("(not= & xs)\n\n"
|
JDOC("(not= & xs)\n\n"
|
||||||
"Check if any values in xs are not equal. Returns a boolean."));
|
"Check if any values in xs are not equal. Returns a boolean."));
|
||||||
|
|
||||||
/* Platform detection */
|
/* Platform detection */
|
||||||
janet_def(env, "janet/version", janet_cstringv(JANET_VERSION),
|
janet_def(env, "janet/version", janet_cstringv(JANET_VERSION),
|
||||||
@@ -1312,7 +1314,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
|||||||
JDOC("The build identifier of the running janet program."));
|
JDOC("The build identifier of the running janet program."));
|
||||||
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
|
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
|
||||||
JDOC("The flag set of config options from janetconf.h which is used to check "
|
JDOC("The flag set of config options from janetconf.h which is used to check "
|
||||||
"if native modules are compatible with the host program."));
|
"if native modules are compatible with the host program."));
|
||||||
|
|
||||||
/* Allow references to the environment */
|
/* Allow references to the environment */
|
||||||
janet_def(env, "root-env", janet_wrap_table(env),
|
janet_def(env, "root-env", janet_wrap_table(env),
|
||||||
|
|||||||
107
src/core/ev.c
107
src/core/ev.c
@@ -117,6 +117,9 @@ typedef struct {
|
|||||||
double sec;
|
double sec;
|
||||||
JanetVM *vm;
|
JanetVM *vm;
|
||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
HANDLE cancel_event;
|
||||||
|
#endif
|
||||||
} JanetThreadedTimeout;
|
} JanetThreadedTimeout;
|
||||||
|
|
||||||
#define JANET_MAX_Q_CAPACITY 0x7FFFFFF
|
#define JANET_MAX_Q_CAPACITY 0x7FFFFFF
|
||||||
@@ -604,12 +607,7 @@ void janet_ev_init_common(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JANET_WINDOWS
|
#if JANET_ANDROID
|
||||||
static VOID CALLBACK janet_timeout_stop(ULONG_PTR ptr) {
|
|
||||||
UNREFERENCED_PARAMETER(ptr);
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
#elif JANET_ANDROID
|
|
||||||
static void janet_timeout_stop(int sig_num) {
|
static void janet_timeout_stop(int sig_num) {
|
||||||
if (sig_num == SIGUSR1) {
|
if (sig_num == SIGUSR1) {
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
@@ -620,10 +618,14 @@ static void janet_timeout_stop(int sig_num) {
|
|||||||
static void handle_timeout_worker(JanetTimeout to, int cancel) {
|
static void handle_timeout_worker(JanetTimeout to, int cancel) {
|
||||||
if (!to.has_worker) return;
|
if (!to.has_worker) return;
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
(void) cancel;
|
if (cancel && to.worker_event) {
|
||||||
QueueUserAPC(janet_timeout_stop, to.worker, 0);
|
SetEvent(to.worker_event);
|
||||||
|
}
|
||||||
WaitForSingleObject(to.worker, INFINITE);
|
WaitForSingleObject(to.worker, INFINITE);
|
||||||
CloseHandle(to.worker);
|
CloseHandle(to.worker);
|
||||||
|
if (to.worker_event) {
|
||||||
|
CloseHandle(to.worker_event);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef JANET_ANDROID
|
#ifdef JANET_ANDROID
|
||||||
if (cancel) janet_assert(!pthread_kill(to.worker, SIGUSR1), "pthread_kill");
|
if (cancel) janet_assert(!pthread_kill(to.worker, SIGUSR1), "pthread_kill");
|
||||||
@@ -693,10 +695,20 @@ static void janet_timeout_cb(JanetEVGenericMessage msg) {
|
|||||||
static DWORD WINAPI janet_timeout_body(LPVOID ptr) {
|
static DWORD WINAPI janet_timeout_body(LPVOID ptr) {
|
||||||
JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr;
|
JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr;
|
||||||
janet_free(ptr);
|
janet_free(ptr);
|
||||||
SleepEx((DWORD)(tto.sec * 1000), TRUE);
|
JanetTimestamp wait_begin = ts_now();
|
||||||
janet_interpreter_interrupt(tto.vm);
|
DWORD duration = (DWORD)round(tto.sec * 1000);
|
||||||
JanetEVGenericMessage msg = {0};
|
DWORD res = WAIT_TIMEOUT;
|
||||||
janet_ev_post_event(tto.vm, janet_timeout_cb, msg);
|
JanetTimestamp wait_end = ts_now();
|
||||||
|
for (DWORD i = 1; res == WAIT_TIMEOUT && (wait_end - wait_begin) < duration; i++) {
|
||||||
|
res = WaitForSingleObject(tto.cancel_event, (duration + i));
|
||||||
|
wait_end = ts_now();
|
||||||
|
}
|
||||||
|
/* only send interrupt message if result is WAIT_TIMEOUT */
|
||||||
|
if (res == WAIT_TIMEOUT) {
|
||||||
|
janet_interpreter_interrupt(tto.vm);
|
||||||
|
JanetEVGenericMessage msg = {0};
|
||||||
|
janet_ev_post_event(tto.vm, janet_timeout_cb, msg);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -839,6 +851,34 @@ static int janet_chanat_gc(void *p, size_t s) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void janet_chanat_remove_vmref(JanetQueue *fq) {
|
||||||
|
JanetChannelPending *pending = fq->data;
|
||||||
|
if (fq->head <= fq->tail) {
|
||||||
|
for (int32_t i = fq->head; i < fq->tail; i++) {
|
||||||
|
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int32_t i = fq->head; i < fq->capacity; i++) {
|
||||||
|
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
|
||||||
|
}
|
||||||
|
for (int32_t i = 0; i < fq->tail; i++) {
|
||||||
|
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int janet_chanat_gcperthread(void *p, size_t s) {
|
||||||
|
(void) s;
|
||||||
|
JanetChannel *chan = p;
|
||||||
|
janet_chan_lock(chan);
|
||||||
|
/* Make sure that the internals of the threaded channel no longer reference _this_ thread. Replace
|
||||||
|
* those references with NULL. */
|
||||||
|
janet_chanat_remove_vmref(&chan->read_pending);
|
||||||
|
janet_chanat_remove_vmref(&chan->write_pending);
|
||||||
|
janet_chan_unlock(chan);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void janet_chanat_mark_fq(JanetQueue *fq) {
|
static void janet_chanat_mark_fq(JanetQueue *fq) {
|
||||||
JanetChannelPending *pending = fq->data;
|
JanetChannelPending *pending = fq->data;
|
||||||
if (fq->head <= fq->tail) {
|
if (fq->head <= fq->tail) {
|
||||||
@@ -921,8 +961,9 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
|
|||||||
int is_read = (mode == JANET_CP_MODE_CHOICE_READ) || (mode == JANET_CP_MODE_READ);
|
int is_read = (mode == JANET_CP_MODE_CHOICE_READ) || (mode == JANET_CP_MODE_READ);
|
||||||
if (is_read) {
|
if (is_read) {
|
||||||
JanetChannelPending reader;
|
JanetChannelPending reader;
|
||||||
if (!janet_q_pop(&channel->read_pending, &reader, sizeof(reader))) {
|
while (!janet_q_pop(&channel->read_pending, &reader, sizeof(reader))) {
|
||||||
JanetVM *vm = reader.thread;
|
JanetVM *vm = reader.thread;
|
||||||
|
if (!vm) continue;
|
||||||
JanetEVGenericMessage msg;
|
JanetEVGenericMessage msg;
|
||||||
msg.tag = reader.mode;
|
msg.tag = reader.mode;
|
||||||
msg.fiber = reader.fiber;
|
msg.fiber = reader.fiber;
|
||||||
@@ -930,11 +971,13 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
|
|||||||
msg.argp = channel;
|
msg.argp = channel;
|
||||||
msg.argj = x;
|
msg.argj = x;
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JanetChannelPending writer;
|
JanetChannelPending writer;
|
||||||
if (!janet_q_pop(&channel->write_pending, &writer, sizeof(writer))) {
|
while (!janet_q_pop(&channel->write_pending, &writer, sizeof(writer))) {
|
||||||
JanetVM *vm = writer.thread;
|
JanetVM *vm = writer.thread;
|
||||||
|
if (!vm) continue;
|
||||||
JanetEVGenericMessage msg;
|
JanetEVGenericMessage msg;
|
||||||
msg.tag = writer.mode;
|
msg.tag = writer.mode;
|
||||||
msg.fiber = writer.fiber;
|
msg.fiber = writer.fiber;
|
||||||
@@ -942,6 +985,7 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
|
|||||||
msg.argp = channel;
|
msg.argp = channel;
|
||||||
msg.argj = janet_wrap_nil();
|
msg.argj = janet_wrap_nil();
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1005,7 +1049,9 @@ static int janet_channel_push_with_lock(JanetChannel *channel, Janet x, int mode
|
|||||||
msg.argi = (int32_t) reader.sched_id;
|
msg.argi = (int32_t) reader.sched_id;
|
||||||
msg.argp = channel;
|
msg.argp = channel;
|
||||||
msg.argj = x;
|
msg.argj = x;
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
if (vm) {
|
||||||
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||||
janet_schedule(reader.fiber, make_read_result(channel, x));
|
janet_schedule(reader.fiber, make_read_result(channel, x));
|
||||||
@@ -1060,7 +1106,9 @@ static int janet_channel_pop_with_lock(JanetChannel *channel, Janet *item, int i
|
|||||||
msg.argi = (int32_t) writer.sched_id;
|
msg.argi = (int32_t) writer.sched_id;
|
||||||
msg.argp = channel;
|
msg.argp = channel;
|
||||||
msg.argj = janet_wrap_nil();
|
msg.argj = janet_wrap_nil();
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
if (vm) {
|
||||||
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||||
janet_schedule(writer.fiber, make_write_result(channel));
|
janet_schedule(writer.fiber, make_write_result(channel));
|
||||||
@@ -1324,7 +1372,9 @@ JANET_CORE_FN(cfun_channel_close,
|
|||||||
msg.tag = JANET_CP_MODE_CLOSE;
|
msg.tag = JANET_CP_MODE_CLOSE;
|
||||||
msg.argi = (int32_t) writer.sched_id;
|
msg.argi = (int32_t) writer.sched_id;
|
||||||
msg.argj = janet_wrap_nil();
|
msg.argj = janet_wrap_nil();
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
if (vm) {
|
||||||
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (janet_fiber_can_resume(writer.fiber)) {
|
if (janet_fiber_can_resume(writer.fiber)) {
|
||||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||||
@@ -1345,7 +1395,9 @@ JANET_CORE_FN(cfun_channel_close,
|
|||||||
msg.tag = JANET_CP_MODE_CLOSE;
|
msg.tag = JANET_CP_MODE_CLOSE;
|
||||||
msg.argi = (int32_t) reader.sched_id;
|
msg.argi = (int32_t) reader.sched_id;
|
||||||
msg.argj = janet_wrap_nil();
|
msg.argj = janet_wrap_nil();
|
||||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
if (vm) {
|
||||||
|
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (janet_fiber_can_resume(reader.fiber)) {
|
if (janet_fiber_can_resume(reader.fiber)) {
|
||||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||||
@@ -1438,7 +1490,10 @@ const JanetAbstractType janet_channel_type = {
|
|||||||
NULL, /* compare */
|
NULL, /* compare */
|
||||||
NULL, /* hash */
|
NULL, /* hash */
|
||||||
janet_chanat_next,
|
janet_chanat_next,
|
||||||
JANET_ATEND_NEXT
|
NULL, /* call */
|
||||||
|
NULL, /* length */
|
||||||
|
NULL, /* bytes */
|
||||||
|
janet_chanat_gcperthread
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Main event loop */
|
/* Main event loop */
|
||||||
@@ -2175,7 +2230,7 @@ void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGenericMessage ms
|
|||||||
event.cb = cb;
|
event.cb = cb;
|
||||||
int fd = vm->selfpipe[1];
|
int fd = vm->selfpipe[1];
|
||||||
/* handle a bit of back pressure before giving up. */
|
/* handle a bit of back pressure before giving up. */
|
||||||
int tries = 4;
|
int tries = 20;
|
||||||
while (tries > 0) {
|
while (tries > 0) {
|
||||||
int status;
|
int status;
|
||||||
do {
|
do {
|
||||||
@@ -3227,7 +3282,13 @@ JANET_CORE_FN(cfun_ev_deadline,
|
|||||||
tto->vm = &janet_vm;
|
tto->vm = &janet_vm;
|
||||||
tto->fiber = tocheck;
|
tto->fiber = tocheck;
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
HANDLE worker = CreateThread(NULL, 0, janet_timeout_body, tto, 0, NULL);
|
HANDLE cancel_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (NULL == cancel_event) {
|
||||||
|
janet_free(tto);
|
||||||
|
janet_panic("failed to create cancel event");
|
||||||
|
}
|
||||||
|
tto->cancel_event = cancel_event;
|
||||||
|
HANDLE worker = CreateThread(NULL, 0, janet_timeout_body, tto, CREATE_SUSPENDED, NULL);
|
||||||
if (NULL == worker) {
|
if (NULL == worker) {
|
||||||
janet_free(tto);
|
janet_free(tto);
|
||||||
janet_panic("failed to create thread");
|
janet_panic("failed to create thread");
|
||||||
@@ -3242,6 +3303,10 @@ JANET_CORE_FN(cfun_ev_deadline,
|
|||||||
#endif
|
#endif
|
||||||
to.has_worker = 1;
|
to.has_worker = 1;
|
||||||
to.worker = worker;
|
to.worker = worker;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
to.worker_event = cancel_event;
|
||||||
|
ResumeThread(worker);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
to.has_worker = 0;
|
to.has_worker = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ JANET_CORE_FN(cfun_filewatch_add,
|
|||||||
"* `:modified`\n\n"
|
"* `:modified`\n\n"
|
||||||
"* `:renamed-old`\n\n"
|
"* `:renamed-old`\n\n"
|
||||||
"* `:renamed-new`\n\n"
|
"* `:renamed-new`\n\n"
|
||||||
"On Linux, events will a `:type` corresponding to the possible flags, excluding `:all`.\n"
|
"On Linux, events will have a `:type` corresponding to the possible flags, excluding `:all`.\n"
|
||||||
"") {
|
"") {
|
||||||
janet_arity(argc, 2, -1);
|
janet_arity(argc, 2, -1);
|
||||||
JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at);
|
JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at);
|
||||||
|
|||||||
@@ -346,6 +346,9 @@ static void janet_deinit_block(JanetGCObject *mem) {
|
|||||||
break;
|
break;
|
||||||
case JANET_MEMORY_ABSTRACT: {
|
case JANET_MEMORY_ABSTRACT: {
|
||||||
JanetAbstractHead *head = (JanetAbstractHead *)mem;
|
JanetAbstractHead *head = (JanetAbstractHead *)mem;
|
||||||
|
if (head->type->gcperthread) {
|
||||||
|
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
|
||||||
|
}
|
||||||
if (head->type->gc) {
|
if (head->type->gc) {
|
||||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||||
}
|
}
|
||||||
@@ -497,9 +500,12 @@ void janet_sweep() {
|
|||||||
/* If not visited... */
|
/* If not visited... */
|
||||||
if (!janet_truthy(items[i].value)) {
|
if (!janet_truthy(items[i].value)) {
|
||||||
void *abst = janet_unwrap_abstract(items[i].key);
|
void *abst = janet_unwrap_abstract(items[i].key);
|
||||||
|
JanetAbstractHead *head = janet_abstract_head(abst);
|
||||||
|
if (head->type->gcperthread) {
|
||||||
|
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
|
||||||
|
}
|
||||||
if (0 == janet_abstract_decref(abst)) {
|
if (0 == janet_abstract_decref(abst)) {
|
||||||
/* Run finalizer */
|
/* Run finalizer */
|
||||||
JanetAbstractHead *head = janet_abstract_head(abst);
|
|
||||||
if (head->type->gc) {
|
if (head->type->gc) {
|
||||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||||
}
|
}
|
||||||
@@ -672,8 +678,11 @@ void janet_clear_memory(void) {
|
|||||||
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
|
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
|
||||||
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
|
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
|
||||||
void *abst = janet_unwrap_abstract(items[i].key);
|
void *abst = janet_unwrap_abstract(items[i].key);
|
||||||
|
JanetAbstractHead *head = janet_abstract_head(abst);
|
||||||
|
if (head->type->gcperthread) {
|
||||||
|
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
|
||||||
|
}
|
||||||
if (0 == janet_abstract_decref(abst)) {
|
if (0 == janet_abstract_decref(abst)) {
|
||||||
JanetAbstractHead *head = janet_abstract_head(abst);
|
|
||||||
if (head->type->gc) {
|
if (head->type->gc) {
|
||||||
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
#include <crt_externs.h>
|
#include <crt_externs.h>
|
||||||
#define environ (*_NSGetEnviron())
|
#define environ (*_NSGetEnviron())
|
||||||
#include <AvailabilityMacros.h>
|
#include <AvailabilityMacros.h>
|
||||||
|
int chroot(const char *dirname);
|
||||||
#else
|
#else
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
#endif
|
#endif
|
||||||
@@ -1541,6 +1542,28 @@ JANET_CORE_FN(os_posix_fork,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(os_posix_chroot,
|
||||||
|
"(os/posix-chroot dirname)",
|
||||||
|
"Call `chroot` to change the root directory to `dirname`. "
|
||||||
|
"Not supported on all systems (POSIX only).") {
|
||||||
|
janet_sandbox_assert(JANET_SANDBOX_CHROOT);
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
(void) argv;
|
||||||
|
janet_panic("not supported on Windows");
|
||||||
|
#else
|
||||||
|
const char *root = janet_getcstring(argv, 0);
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
result = chroot(root);
|
||||||
|
} while (result == -1 && errno == EINTR);
|
||||||
|
if (result == -1) {
|
||||||
|
janet_panic(janet_strerror(errno));
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
/* Runs in a separate thread */
|
/* Runs in a separate thread */
|
||||||
static JanetEVGenericMessage os_shell_subr(JanetEVGenericMessage args) {
|
static JanetEVGenericMessage os_shell_subr(JanetEVGenericMessage args) {
|
||||||
@@ -2873,6 +2896,7 @@ void janet_lib_os(JanetTable *env) {
|
|||||||
JANET_CORE_REG("os/shell", os_shell),
|
JANET_CORE_REG("os/shell", os_shell),
|
||||||
JANET_CORE_REG("os/posix-fork", os_posix_fork),
|
JANET_CORE_REG("os/posix-fork", os_posix_fork),
|
||||||
JANET_CORE_REG("os/posix-exec", os_posix_exec),
|
JANET_CORE_REG("os/posix-exec", os_posix_exec),
|
||||||
|
JANET_CORE_REG("os/posix-chroot", os_posix_chroot),
|
||||||
/* no need to sandbox process management if you can't create processes
|
/* no need to sandbox process management if you can't create processes
|
||||||
* (allows for limited functionality if use exposes C-functions to create specific processes) */
|
* (allows for limited functionality if use exposes C-functions to create specific processes) */
|
||||||
JANET_CORE_REG("os/proc-wait", os_proc_wait),
|
JANET_CORE_REG("os/proc-wait", os_proc_wait),
|
||||||
|
|||||||
@@ -1060,19 +1060,11 @@ void janet_buffer_format(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 's': {
|
case 's': {
|
||||||
JanetByteView bytes = janet_getbytes(argv, arg);
|
const char *s = janet_getcbytes(argv, arg);
|
||||||
const uint8_t *s = bytes.bytes;
|
|
||||||
int32_t l = bytes.len;
|
|
||||||
if (form[2] == '\0')
|
if (form[2] == '\0')
|
||||||
janet_buffer_push_bytes(b, s, l);
|
janet_buffer_push_cstring(b, s);
|
||||||
else {
|
else {
|
||||||
if (l != (int32_t) strnlen((const char *) s, l))
|
nb = snprintf(item, MAX_ITEM, form, s);
|
||||||
janet_panic("string contains zeros");
|
|
||||||
if (!strchr(form, '.') && l >= 100) {
|
|
||||||
janet_panic("no precision and string is too long to be formatted");
|
|
||||||
} else {
|
|
||||||
nb = snprintf(item, MAX_ITEM, form, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
#include "state.h"
|
#include "state.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Run a string */
|
/* Run a string of code. The return value is a set of error flags, JANET_DO_ERROR_RUNTIME, JANET_DO_ERROR_COMPILE, and JANET_DOR_ERROR_PARSE if
|
||||||
|
* any errors were encountered in those phases. More information is printed to stderr. */
|
||||||
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
|
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
|
||||||
JanetParser *parser;
|
JanetParser *parser;
|
||||||
int errflags = 0, done = 0;
|
int errflags = 0, done = 0;
|
||||||
@@ -55,11 +56,10 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
|
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
|
||||||
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
|
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
|
||||||
janet_stacktrace_ext(fiber, ret, "");
|
janet_stacktrace_ext(fiber, ret, "");
|
||||||
errflags |= 0x01;
|
errflags |= JANET_DO_ERROR_RUNTIME;
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = janet_wrap_string(cres.error);
|
|
||||||
int32_t line = (int32_t) parser->line;
|
int32_t line = (int32_t) parser->line;
|
||||||
int32_t col = (int32_t) parser->column;
|
int32_t col = (int32_t) parser->column;
|
||||||
if ((cres.error_mapping.line > 0) &&
|
if ((cres.error_mapping.line > 0) &&
|
||||||
@@ -67,15 +67,19 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
line = cres.error_mapping.line;
|
line = cres.error_mapping.line;
|
||||||
col = cres.error_mapping.column;
|
col = cres.error_mapping.column;
|
||||||
}
|
}
|
||||||
|
JanetString ctx = janet_formatc("%s:%d:%d: compile error",
|
||||||
|
sourcePath, line, col);
|
||||||
|
JanetString errstr = janet_formatc("%s: %s",
|
||||||
|
(const char *)ctx,
|
||||||
|
(const char *)cres.error);
|
||||||
|
ret = janet_wrap_string(errstr);
|
||||||
if (cres.macrofiber) {
|
if (cres.macrofiber) {
|
||||||
janet_eprintf("%s:%d:%d: compile error", sourcePath,
|
janet_eprintf("%s", (const char *)ctx);
|
||||||
line, col);
|
|
||||||
janet_stacktrace_ext(cres.macrofiber, ret, "");
|
janet_stacktrace_ext(cres.macrofiber, ret, "");
|
||||||
} else {
|
} else {
|
||||||
janet_eprintf("%s:%d:%d: compile error: %s\n", sourcePath,
|
janet_eprintf("%s\n", (const char *)errstr);
|
||||||
line, col, (const char *)cres.error);
|
|
||||||
}
|
}
|
||||||
errflags |= 0x02;
|
errflags |= JANET_DO_ERROR_COMPILE;
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,12 +92,14 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
case JANET_PARSE_ERROR: {
|
case JANET_PARSE_ERROR: {
|
||||||
const char *e = janet_parser_error(parser);
|
errflags |= JANET_DO_ERROR_PARSE;
|
||||||
errflags |= 0x04;
|
|
||||||
ret = janet_cstringv(e);
|
|
||||||
int32_t line = (int32_t) parser->line;
|
int32_t line = (int32_t) parser->line;
|
||||||
int32_t col = (int32_t) parser->column;
|
int32_t col = (int32_t) parser->column;
|
||||||
janet_eprintf("%s:%d:%d: parse error: %s\n", sourcePath, line, col, e);
|
JanetString errstr = janet_formatc("%s:%d:%d: parse error: %s",
|
||||||
|
sourcePath, line, col,
|
||||||
|
janet_parser_error(parser));
|
||||||
|
ret = janet_wrap_string(errstr);
|
||||||
|
janet_eprintf("%s\n", (const char *)errstr);
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -121,7 +127,8 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
janet_loop();
|
janet_loop();
|
||||||
if (fiber) {
|
if (fiber) {
|
||||||
janet_gcunroot(janet_wrap_fiber(fiber));
|
janet_gcunroot(janet_wrap_fiber(fiber));
|
||||||
ret = fiber->last_value;
|
if (!errflags)
|
||||||
|
ret = fiber->last_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,8 +23,11 @@
|
|||||||
#ifndef JANET_STATE_H_defined
|
#ifndef JANET_STATE_H_defined
|
||||||
#define JANET_STATE_H_defined
|
#define JANET_STATE_H_defined
|
||||||
|
|
||||||
|
#ifndef JANET_AMALG
|
||||||
|
#include "features.h"
|
||||||
#include <janet.h>
|
#include <janet.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
@@ -65,6 +68,7 @@ typedef struct {
|
|||||||
int has_worker;
|
int has_worker;
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
HANDLE worker;
|
HANDLE worker;
|
||||||
|
HANDLE worker_event;
|
||||||
#else
|
#else
|
||||||
pthread_t worker;
|
pthread_t worker;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -322,7 +322,8 @@ int32_t janet_hash(Janet x) {
|
|||||||
break;
|
break;
|
||||||
case JANET_TUPLE:
|
case JANET_TUPLE:
|
||||||
hash = janet_tuple_hash(janet_unwrap_tuple(x));
|
hash = janet_tuple_hash(janet_unwrap_tuple(x));
|
||||||
hash += (janet_tuple_flag(janet_unwrap_tuple(x)) & JANET_TUPLE_FLAG_BRACKETCTOR) ? 1 : 0;
|
uint32_t inc = (janet_tuple_flag(janet_unwrap_tuple(x)) & JANET_TUPLE_FLAG_BRACKETCTOR) ? 1 : 0;
|
||||||
|
hash = (int32_t)((uint32_t)hash + inc); /* avoid overflow undefined behavior */
|
||||||
break;
|
break;
|
||||||
case JANET_STRUCT:
|
case JANET_STRUCT:
|
||||||
hash = janet_struct_hash(janet_unwrap_struct(x));
|
hash = janet_struct_hash(janet_unwrap_struct(x));
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ extern "C" {
|
|||||||
|| defined(__s390x__) /* S390 64-bit */ \
|
|| defined(__s390x__) /* S390 64-bit */ \
|
||||||
|| defined(__s390__) /* S390 32-bit */ \
|
|| defined(__s390__) /* S390 32-bit */ \
|
||||||
|| defined(__ARMEB__) /* ARM big endian */ \
|
|| defined(__ARMEB__) /* ARM big endian */ \
|
||||||
|
|| defined(__AARCH64EB__) /* ARM64 big endian */ \
|
||||||
|| ((defined(__CC_ARM) || defined(__ARMCC__)) /* ARM RealView compiler */ \
|
|| ((defined(__CC_ARM) || defined(__ARMCC__)) /* ARM RealView compiler */ \
|
||||||
&& defined(__BIG_ENDIAN))
|
&& defined(__BIG_ENDIAN))
|
||||||
#define JANET_BIG_ENDIAN 1
|
#define JANET_BIG_ENDIAN 1
|
||||||
@@ -1188,6 +1189,7 @@ struct JanetAbstractType {
|
|||||||
Janet(*call)(void *p, int32_t argc, Janet *argv);
|
Janet(*call)(void *p, int32_t argc, Janet *argv);
|
||||||
size_t (*length)(void *p, size_t len);
|
size_t (*length)(void *p, size_t len);
|
||||||
JanetByteView(*bytes)(void *p, size_t len);
|
JanetByteView(*bytes)(void *p, size_t len);
|
||||||
|
int (*gcperthread)(void *data, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Some macros to let us add extra types to JanetAbstract types without
|
/* Some macros to let us add extra types to JanetAbstract types without
|
||||||
@@ -1207,7 +1209,8 @@ struct JanetAbstractType {
|
|||||||
#define JANET_ATEND_NEXT NULL,JANET_ATEND_CALL
|
#define JANET_ATEND_NEXT NULL,JANET_ATEND_CALL
|
||||||
#define JANET_ATEND_CALL NULL,JANET_ATEND_LENGTH
|
#define JANET_ATEND_CALL NULL,JANET_ATEND_LENGTH
|
||||||
#define JANET_ATEND_LENGTH NULL,JANET_ATEND_BYTES
|
#define JANET_ATEND_LENGTH NULL,JANET_ATEND_BYTES
|
||||||
#define JANET_ATEND_BYTES
|
#define JANET_ATEND_BYTES NULL,JANET_ATEND_GCPERTHREAD
|
||||||
|
#define JANET_ATEND_GCPERTHREAD
|
||||||
|
|
||||||
struct JanetReg {
|
struct JanetReg {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -1616,6 +1619,9 @@ JANET_API JanetTable *janet_core_env(JanetTable *replacements);
|
|||||||
JANET_API JanetTable *janet_core_lookup_table(JanetTable *replacements);
|
JANET_API JanetTable *janet_core_lookup_table(JanetTable *replacements);
|
||||||
|
|
||||||
/* Execute strings */
|
/* Execute strings */
|
||||||
|
#define JANET_DO_ERROR_RUNTIME 0x01
|
||||||
|
#define JANET_DO_ERROR_COMPILE 0x02
|
||||||
|
#define JANET_DO_ERROR_PARSE 0x04
|
||||||
JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out);
|
JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out);
|
||||||
JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out);
|
JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out);
|
||||||
|
|
||||||
@@ -1894,6 +1900,7 @@ JANET_API void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *pr
|
|||||||
#define JANET_SANDBOX_FFI_USE 2048
|
#define JANET_SANDBOX_FFI_USE 2048
|
||||||
#define JANET_SANDBOX_FFI_JIT 4096
|
#define JANET_SANDBOX_FFI_JIT 4096
|
||||||
#define JANET_SANDBOX_SIGNAL 8192
|
#define JANET_SANDBOX_SIGNAL 8192
|
||||||
|
#define JANET_SANDBOX_CHROOT 16384
|
||||||
#define JANET_SANDBOX_FFI (JANET_SANDBOX_FFI_DEFINE | JANET_SANDBOX_FFI_USE | JANET_SANDBOX_FFI_JIT)
|
#define JANET_SANDBOX_FFI (JANET_SANDBOX_FFI_DEFINE | JANET_SANDBOX_FFI_USE | JANET_SANDBOX_FFI_JIT)
|
||||||
#define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ | JANET_SANDBOX_FS_TEMP)
|
#define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ | JANET_SANDBOX_FS_TEMP)
|
||||||
#define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN)
|
#define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN)
|
||||||
|
|||||||
@@ -50,6 +50,11 @@
|
|||||||
(def errsym (keyword (gensym)))
|
(def errsym (keyword (gensym)))
|
||||||
~(assert (= ,errsym (try (do ,;forms) ([_] ,errsym))) ,msg))
|
~(assert (= ,errsym (try (do ,;forms) ([_] ,errsym))) ,msg))
|
||||||
|
|
||||||
|
(defmacro assert-error-value
|
||||||
|
[msg errval & forms]
|
||||||
|
(def e (gensym))
|
||||||
|
~(assert (= ,errval (try (do ,;forms) ([,e] ,e))) ,msg))
|
||||||
|
|
||||||
(defn check-compile-error
|
(defn check-compile-error
|
||||||
[form]
|
[form]
|
||||||
(def result (compile form))
|
(def result (compile form))
|
||||||
|
|||||||
@@ -1023,4 +1023,11 @@
|
|||||||
(assert (deep-not= @{:key1 "value1" [@"key2"] @"value2"}
|
(assert (deep-not= @{:key1 "value1" [@"key2"] @"value2"}
|
||||||
@{:key1 "value1" [@"key2"] @"value2"}) "deep= mutable keys")
|
@{:key1 "value1" [@"key2"] @"value2"}) "deep= mutable keys")
|
||||||
|
|
||||||
|
# different try overloads
|
||||||
|
(assert (= (try (error :error) ([] :caught)) :caught))
|
||||||
|
(assert (= (try (error :error) ([e] e)) :error))
|
||||||
|
(assert (= (try (error :error) ([e fib] [e (fiber? fib)])) [:error true]))
|
||||||
|
# regression test for #1659
|
||||||
|
(assert (= (try (error :error) ([_ _] :caught)) :caught))
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|||||||
@@ -117,8 +117,17 @@
|
|||||||
(assert (= 0 (length (bundle/list))) "bundles are listed correctly 7")
|
(assert (= 0 (length (bundle/list))) "bundles are listed correctly 7")
|
||||||
(assert (= 0 (length (bundle/topolist))) "bundles are listed correctly 8")
|
(assert (= 0 (length (bundle/topolist))) "bundles are listed correctly 8")
|
||||||
|
|
||||||
|
# Try installing a bundle that is missing bundle script
|
||||||
|
(assert-error-value "bundle missing bundle script"
|
||||||
|
"bundle must contain bundle.janet or bundle/init.janet"
|
||||||
|
(bundle/install "./examples/sample-bad-bundle1"))
|
||||||
|
(assert (= 0 (length (bundle/list))) "check failure 0")
|
||||||
|
(assert (= 0 (length (bundle/topolist))) "check failure 1")
|
||||||
|
|
||||||
# Try installing a bundle that fails check
|
# Try installing a bundle that fails check
|
||||||
(assert-error "bad test" (bundle/install "./examples/sample-bad-bundle" :check true))
|
(assert-error-value "bundle check hook fails"
|
||||||
|
"Check failed!"
|
||||||
|
(bundle/install "./examples/sample-bad-bundle2" :check true))
|
||||||
(assert (= 0 (length (bundle/list))) "check failure 0")
|
(assert (= 0 (length (bundle/list))) "check failure 0")
|
||||||
(assert (= 0 (length (bundle/topolist))) "check failure 1")
|
(assert (= 0 (length (bundle/topolist))) "check failure 1")
|
||||||
|
|
||||||
|
|||||||
58
test/suite-ev2.janet
Normal file
58
test/suite-ev2.janet
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Copyright (c) 2025 Calvin Rose & contributors
|
||||||
|
#
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Issue #1629
|
||||||
|
(def thread-channel (ev/thread-chan 100))
|
||||||
|
(def super (ev/thread-chan 10))
|
||||||
|
(defn worker []
|
||||||
|
(while true
|
||||||
|
(def item (ev/take thread-channel))
|
||||||
|
(when (= item :deadline)
|
||||||
|
(ev/deadline 0.1 nil (fiber/current) true))))
|
||||||
|
(ev/thread worker nil :n super)
|
||||||
|
(ev/give thread-channel :item)
|
||||||
|
(ev/sleep 0.05)
|
||||||
|
(ev/give thread-channel :item)
|
||||||
|
(ev/sleep 0.05)
|
||||||
|
(ev/give thread-channel :deadline)
|
||||||
|
(ev/sleep 0.05)
|
||||||
|
(ev/give thread-channel :item)
|
||||||
|
(ev/sleep 0.05)
|
||||||
|
(ev/give thread-channel :item)
|
||||||
|
(ev/sleep 0.15)
|
||||||
|
(assert (deep= '(:error "deadline expired" nil) (ev/take super)) "deadline expirataion")
|
||||||
|
|
||||||
|
# Another variant
|
||||||
|
(def thread-channel (ev/thread-chan 100))
|
||||||
|
(def super (ev/thread-chan 10))
|
||||||
|
(defn worker []
|
||||||
|
(while true
|
||||||
|
(def item (ev/take thread-channel))
|
||||||
|
(when (= item :deadline)
|
||||||
|
(ev/deadline 0.1))))
|
||||||
|
(ev/thread worker nil :n super)
|
||||||
|
(ev/give thread-channel :deadline)
|
||||||
|
(ev/sleep 0.2)
|
||||||
|
(assert (deep= '(:error "deadline expired" nil) (ev/take super)) "deadline expirataion")
|
||||||
|
|
||||||
|
(end-suite)
|
||||||
@@ -136,5 +136,8 @@
|
|||||||
"keyword slice")
|
"keyword slice")
|
||||||
(assert (= 'symbol (symbol/slice "some_symbol_slice" 5 11)) "symbol slice")
|
(assert (= 'symbol (symbol/slice "some_symbol_slice" 5 11)) "symbol slice")
|
||||||
|
|
||||||
|
# Check string formatting, #1600
|
||||||
|
(assert (= "" (string/format "%.99s" @"")) "string/format %s buffer")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,12 @@
|
|||||||
Version="$(var.Version)"
|
Version="$(var.Version)"
|
||||||
Manufacturer="$(var.Manufacturer)"
|
Manufacturer="$(var.Manufacturer)"
|
||||||
UpgradeCode="$(var.UpgradeCode)">
|
UpgradeCode="$(var.UpgradeCode)">
|
||||||
|
<!--
|
||||||
|
perUser means destination will be under user's %AppData% directory,
|
||||||
|
not Program Files or similar.
|
||||||
|
|
||||||
|
see: https://learn.microsoft.com/en-us/windows/win32/msi/installation-context
|
||||||
|
-->
|
||||||
<Package Compressed="yes"
|
<Package Compressed="yes"
|
||||||
InstallScope="perUser"
|
InstallScope="perUser"
|
||||||
Manufacturer="$(var.Manufacturer)"
|
Manufacturer="$(var.Manufacturer)"
|
||||||
|
|||||||
Reference in New Issue
Block a user