mirror of
https://github.com/janet-lang/janet
synced 2025-11-08 11:33:02 +00:00
Compare commits
104 Commits
ev-epoll-f
...
v1.34.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f92f3eb6fa | ||
|
|
89e74dca3e | ||
|
|
f2e86d2f8d | ||
|
|
623da131e5 | ||
|
|
e89ec31ae5 | ||
|
|
68a6ed208e | ||
|
|
c01b32c4f3 | ||
|
|
ee11ff9da9 | ||
|
|
ed56d5d6ff | ||
|
|
b317ab755c | ||
|
|
9819994999 | ||
|
|
e9dbaa81d2 | ||
|
|
9f9146ffae | ||
|
|
9d9732af97 | ||
|
|
ebb8fa9787 | ||
|
|
9e6abbf4d4 | ||
|
|
6032a6d658 | ||
|
|
c29ab22e6d | ||
|
|
592ac4904c | ||
|
|
03ae2ec153 | ||
|
|
3bc42d0d37 | ||
|
|
12630d3e54 | ||
|
|
c9897f99c3 | ||
|
|
e66dc14b3a | ||
|
|
7a2868c147 | ||
|
|
9e0daaee09 | ||
|
|
c293c7de93 | ||
|
|
49eb5f8563 | ||
|
|
674b375b2c | ||
|
|
7e94c091eb | ||
|
|
5885ccba61 | ||
|
|
431ecd3d1a | ||
|
|
f6df8ff935 | ||
|
|
3fd70f0951 | ||
|
|
bebb635d4f | ||
|
|
354896bc4b | ||
|
|
5ddefff27e | ||
|
|
91827eef4f | ||
|
|
9c14c09962 | ||
|
|
e85a84171f | ||
|
|
3a4f86c3d7 | ||
|
|
5e75963312 | ||
|
|
184d9289b5 | ||
|
|
b7ff9577c0 | ||
|
|
942a1aaac6 | ||
|
|
69f0fe004d | ||
|
|
2a04347a42 | ||
|
|
1394f1a5c0 | ||
|
|
cf4d19a8ea | ||
|
|
23b0fe9f8e | ||
|
|
1ba718b15e | ||
|
|
df5f79ff35 | ||
|
|
6d7e8528ea | ||
|
|
197bb73a62 | ||
|
|
f91e599451 | ||
|
|
5b9aa9237c | ||
|
|
61f38fab37 | ||
|
|
9142f38cbc | ||
|
|
e8ed961572 | ||
|
|
be11a2a1ad | ||
|
|
ea75086300 | ||
|
|
9eeefbd79a | ||
|
|
c573a98363 | ||
|
|
11d7af3f95 | ||
|
|
a10b4f61d8 | ||
|
|
a0cb7514f1 | ||
|
|
b066edc116 | ||
|
|
938f5a689e | ||
|
|
772f4c26e8 | ||
|
|
6b5d151beb | ||
|
|
a9176a77e6 | ||
|
|
16f409c6a9 | ||
|
|
9593c930de | ||
|
|
56f33f514b | ||
|
|
1ccd544b94 | ||
|
|
93c83a2ee2 | ||
|
|
f459e32ada | ||
|
|
9b640c8e9c | ||
|
|
a3228f4997 | ||
|
|
715eb69d92 | ||
|
|
df2d5cb3d3 | ||
|
|
3b189eab64 | ||
|
|
609b629c22 | ||
|
|
e74365fe38 | ||
|
|
46b34833c2 | ||
|
|
045c80869d | ||
|
|
2ea2e72ddd | ||
|
|
1b17e12fd6 | ||
|
|
cc5beda0d2 | ||
|
|
a363fd926d | ||
|
|
21ebede529 | ||
|
|
15d67e9191 | ||
|
|
b5996f5f02 | ||
|
|
83204dc293 | ||
|
|
e3f4142d2a | ||
|
|
f18ad36b1b | ||
|
|
cb25a2ecd6 | ||
|
|
741a5036e8 | ||
|
|
549ee95f3d | ||
|
|
6ae81058aa | ||
|
|
267c603824 | ||
|
|
a8f583a372 | ||
|
|
2b5d90f73a | ||
|
|
4139e426fe |
@@ -1,4 +1,4 @@
|
|||||||
image: freebsd/12.x
|
image: freebsd/14.x
|
||||||
sources:
|
sources:
|
||||||
- https://git.sr.ht/~bakpakin/janet
|
- https://git.sr.ht/~bakpakin/janet
|
||||||
packages:
|
packages:
|
||||||
|
|||||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
|||||||
gcc
|
gcc
|
||||||
- name: Build the project
|
- name: Build the project
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: make -j CC=gcc
|
run: make -j4 CC=gcc JANET_NO_AMALG=1
|
||||||
|
|
||||||
test-mingw-linux:
|
test-mingw-linux:
|
||||||
name: Build and test with Mingw on Linux + Wine
|
name: Build and test with Mingw on Linux + Wine
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -34,8 +34,11 @@ local
|
|||||||
|
|
||||||
# Common test files I use.
|
# Common test files I use.
|
||||||
temp.janet
|
temp.janet
|
||||||
temp*.janet
|
temp.c
|
||||||
|
temp*janet
|
||||||
|
temp*.c
|
||||||
scratch.janet
|
scratch.janet
|
||||||
|
scratch.c
|
||||||
|
|
||||||
# Emscripten
|
# Emscripten
|
||||||
*.bc
|
*.bc
|
||||||
|
|||||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,7 +1,47 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
## Unreleased - ???
|
## 1.34.0 - 2024-03-22
|
||||||
|
- Add a new (split) PEG special by @ianthehenry
|
||||||
|
- Add buffer/push-* sized int and float by @pnelson
|
||||||
|
- Documentation improvements: @amano-kenji, @llmII, @MaxGyver83, @pepe, @sogaiu.
|
||||||
|
- Expose _exit to skip certain cleanup with os/exit.
|
||||||
|
- Swap set / body order for each by @sogaiu.
|
||||||
|
- Abort on assert failure instead of exit.
|
||||||
|
- Fix: os/proc-wait by @llmII.
|
||||||
|
- Fix macex1 to keep syntax location for all tuples.
|
||||||
|
- Restore if-let tail calls.
|
||||||
|
- Don't try and resume fibers that can't be resumed.
|
||||||
|
- Register stream on unmarshal.
|
||||||
|
- Fix asm roundtrip issue.
|
||||||
|
|
||||||
|
## 1.33.0 - 2024-01-07
|
||||||
|
- Add more + and * keywords to default-peg-grammar by @sogaiu.
|
||||||
|
- Use libc strlen in janet_buffer_push_cstring by @williewillus.
|
||||||
|
- Be a bit safer with reference counting.
|
||||||
|
- Add support for atomic loads in Janet's atomic abstraction.
|
||||||
|
- Fix poll event loop CPU usage issue.
|
||||||
|
- Add ipv6, shared, and cryptorand options to meson.
|
||||||
|
- Add more ipv6 feature detection.
|
||||||
|
- Fix loop for forever loop.
|
||||||
|
- Cleaned up unused NetStateConnect, fixed janet_async_end() ev refcount by @zevv.
|
||||||
|
- Fix warnings w/ MSVC and format.
|
||||||
|
- Fix marshal_one_env w/ JANET_MARSHAL_UNSAFE.
|
||||||
|
- Fix `(default)`.
|
||||||
|
- Fix cannot marshal fiber with c stackframe, in a dynamic way that is fairly conservative.
|
||||||
|
- Fix typo for SIGALARM in os/proc-kill.
|
||||||
|
- Prevent bytecode optimization from remove mk* instructions.
|
||||||
|
- Fix arity typo in peg.c by @pepe.
|
||||||
|
- Update Makefile for MinGW.
|
||||||
|
- Fix canceling waiting fiber.
|
||||||
|
- Add a new (sub) PEG special by @ianthehenry.
|
||||||
|
- Fix if net/server's handler has incorrect arity.
|
||||||
|
- Fix macex raising on ().
|
||||||
|
|
||||||
|
## 1.32.1 - 2023-10-15
|
||||||
|
- Fix return value from C function `janet_dobytes` when called on Janet functions that yield to event loop.
|
||||||
|
- Change C API for event loop interaction - get rid of JanetListener and instead use `janet_async_start` and `janet_async_end`.
|
||||||
|
- Rework event loop to make fewer system calls on kqueue and epoll.
|
||||||
- Expose atomic refcount abstraction in janet.h
|
- Expose atomic refcount abstraction in janet.h
|
||||||
- Add `array/weak` for weak references in arrays
|
- Add `array/weak` for weak references in arrays
|
||||||
- Add support for weak tables via `table/weak`, `table/weak-keys`, and `table/weak-values`.
|
- Add support for weak tables via `table/weak`, `table/weak-keys`, and `table/weak-values`.
|
||||||
|
|||||||
25
Makefile
25
Makefile
@@ -33,6 +33,7 @@ CLIBS=-lm -lpthread
|
|||||||
JANET_TARGET=build/janet
|
JANET_TARGET=build/janet
|
||||||
JANET_BOOT=build/janet_boot
|
JANET_BOOT=build/janet_boot
|
||||||
JANET_IMPORT_LIB=build/janet.lib
|
JANET_IMPORT_LIB=build/janet.lib
|
||||||
|
JANET_LIBRARY_IMPORT_LIB=build/libjanet.lib
|
||||||
JANET_LIBRARY=build/libjanet.so
|
JANET_LIBRARY=build/libjanet.so
|
||||||
JANET_STATIC_LIBRARY=build/libjanet.a
|
JANET_STATIC_LIBRARY=build/libjanet.a
|
||||||
JANET_PATH?=$(LIBDIR)/janet
|
JANET_PATH?=$(LIBDIR)/janet
|
||||||
@@ -42,6 +43,7 @@ JANET_DIST_DIR?=janet-dist
|
|||||||
JANET_BOOT_FLAGS:=. JANET_PATH '$(JANET_PATH)'
|
JANET_BOOT_FLAGS:=. JANET_PATH '$(JANET_PATH)'
|
||||||
JANET_TARGET_OBJECTS=build/janet.o build/shell.o
|
JANET_TARGET_OBJECTS=build/janet.o build/shell.o
|
||||||
JPM_TAG?=master
|
JPM_TAG?=master
|
||||||
|
HAS_SHARED?=1
|
||||||
DEBUGGER=gdb
|
DEBUGGER=gdb
|
||||||
SONAME_SETTER=-Wl,-soname,
|
SONAME_SETTER=-Wl,-soname,
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ HOSTAR?=$(AR)
|
|||||||
# Symbols are (optionally) removed later, keep -g as default!
|
# Symbols are (optionally) removed later, keep -g as default!
|
||||||
CFLAGS?=-O2 -g
|
CFLAGS?=-O2 -g
|
||||||
LDFLAGS?=-rdynamic
|
LDFLAGS?=-rdynamic
|
||||||
|
LIBJANET_LDFLAGS?=$(LD_FLAGS)
|
||||||
RUN:=$(RUN)
|
RUN:=$(RUN)
|
||||||
|
|
||||||
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
|
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
|
||||||
@@ -93,12 +96,17 @@ endif
|
|||||||
ifeq ($(findstring MINGW,$(UNAME)), MINGW)
|
ifeq ($(findstring MINGW,$(UNAME)), MINGW)
|
||||||
CLIBS:=-lws2_32 -lpsapi -lwsock32
|
CLIBS:=-lws2_32 -lpsapi -lwsock32
|
||||||
LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB)
|
LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB)
|
||||||
|
LIBJANET_LDFLAGS:=-Wl,--out-implib,$(JANET_LIBRARY_IMPORT_LIB)
|
||||||
JANET_TARGET:=$(JANET_TARGET).exe
|
JANET_TARGET:=$(JANET_TARGET).exe
|
||||||
JANET_BOOT:=$(JANET_BOOT).exe
|
JANET_BOOT:=$(JANET_BOOT).exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
$(shell mkdir -p build/core build/c build/boot build/mainclient)
|
$(shell mkdir -p build/core build/c build/boot build/mainclient)
|
||||||
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.h
|
all: $(JANET_TARGET) $(JANET_STATIC_LIBRARY) build/janet.h
|
||||||
|
ifeq ($(HAS_SHARED), 1)
|
||||||
|
all: $(JANET_LIBRARY)
|
||||||
|
endif
|
||||||
|
|
||||||
######################
|
######################
|
||||||
##### Name Files #####
|
##### Name Files #####
|
||||||
@@ -196,9 +204,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
|
|||||||
########################
|
########################
|
||||||
|
|
||||||
ifeq ($(UNAME), Darwin)
|
ifeq ($(UNAME), Darwin)
|
||||||
SONAME=libjanet.1.31.dylib
|
SONAME=libjanet.1.34.dylib
|
||||||
else
|
else
|
||||||
SONAME=libjanet.so.1.31
|
SONAME=libjanet.so.1.34
|
||||||
endif
|
endif
|
||||||
|
|
||||||
build/c/shell.c: src/mainclient/shell.c
|
build/c/shell.c: src/mainclient/shell.c
|
||||||
@@ -220,7 +228,7 @@ $(JANET_TARGET): $(JANET_TARGET_OBJECTS)
|
|||||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
|
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
$(JANET_LIBRARY): $(JANET_TARGET_OBJECTS)
|
$(JANET_LIBRARY): $(JANET_TARGET_OBJECTS)
|
||||||
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
|
$(HOSTCC) $(LIBJANET_LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
$(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
|
$(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
|
||||||
$(HOSTAR) rcs $@ $^
|
$(HOSTAR) rcs $@ $^
|
||||||
@@ -263,7 +271,7 @@ dist: build/janet-dist.tar.gz
|
|||||||
|
|
||||||
build/janet-%.tar.gz: $(JANET_TARGET) \
|
build/janet-%.tar.gz: $(JANET_TARGET) \
|
||||||
build/janet.h \
|
build/janet.h \
|
||||||
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
|
janet.1 LICENSE CONTRIBUTING.md $(JANET_STATIC_LIBRARY) \
|
||||||
README.md build/c/janet.c build/c/shell.c
|
README.md build/c/janet.c build/c/shell.c
|
||||||
mkdir -p build/$(JANET_DIST_DIR)/bin
|
mkdir -p build/$(JANET_DIST_DIR)/bin
|
||||||
cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
|
cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
|
||||||
@@ -271,13 +279,17 @@ build/janet-%.tar.gz: $(JANET_TARGET) \
|
|||||||
mkdir -p build/$(JANET_DIST_DIR)/include
|
mkdir -p build/$(JANET_DIST_DIR)/include
|
||||||
cp build/janet.h build/$(JANET_DIST_DIR)/include/
|
cp build/janet.h build/$(JANET_DIST_DIR)/include/
|
||||||
mkdir -p build/$(JANET_DIST_DIR)/lib/
|
mkdir -p build/$(JANET_DIST_DIR)/lib/
|
||||||
cp $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
|
cp $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
|
||||||
|
cp $(JANET_LIBRARY) build/$(JANET_DIST_DIR)/lib/ || true
|
||||||
mkdir -p build/$(JANET_DIST_DIR)/man/man1/
|
mkdir -p build/$(JANET_DIST_DIR)/man/man1/
|
||||||
cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
|
cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
|
||||||
mkdir -p build/$(JANET_DIST_DIR)/src/
|
mkdir -p build/$(JANET_DIST_DIR)/src/
|
||||||
cp build/c/janet.c build/c/shell.c build/$(JANET_DIST_DIR)/src/
|
cp build/c/janet.c build/c/shell.c build/$(JANET_DIST_DIR)/src/
|
||||||
cp CONTRIBUTING.md LICENSE README.md build/$(JANET_DIST_DIR)/
|
cp CONTRIBUTING.md LICENSE README.md build/$(JANET_DIST_DIR)/
|
||||||
cd build && tar -czvf ../$@ ./$(JANET_DIST_DIR)
|
cd build && tar -czvf ../$@ ./$(JANET_DIST_DIR)
|
||||||
|
ifeq ($(HAS_SHARED), 1)
|
||||||
|
build/janet-%.tar.gz: $(JANET_LIBRARY)
|
||||||
|
endif
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
##### Documentation #####
|
##### Documentation #####
|
||||||
@@ -331,6 +343,7 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
|
|||||||
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
||||||
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||||
cp '$(JANET_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
|
cp '$(JANET_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
|
||||||
|
cp '$(JANET_LIBRARY_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
|
||||||
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || echo "You can ignore this error for non-Linux systems or local installs"
|
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || echo "You can ignore this error for non-Linux systems or local installs"
|
||||||
|
|
||||||
install-jpm-git: $(JANET_TARGET)
|
install-jpm-git: $(JANET_TARGET)
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ exit /b 0
|
|||||||
:CLEAN
|
:CLEAN
|
||||||
del *.exe *.lib *.exp
|
del *.exe *.lib *.exp
|
||||||
rd /s /q build
|
rd /s /q build
|
||||||
rd /s /q dist
|
if exist dist (
|
||||||
|
rd /s /q dist
|
||||||
|
)
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
@rem Run tests
|
@rem Run tests
|
||||||
|
|||||||
5
examples/posix-exec.janet
Normal file
5
examples/posix-exec.janet
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Switch to python
|
||||||
|
|
||||||
|
(print "running in Janet")
|
||||||
|
(os/posix-exec ["python"] :p)
|
||||||
|
(print "will not print")
|
||||||
62
meson.build
62
meson.build
@@ -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.31.0')
|
version : '1.34.0')
|
||||||
|
|
||||||
# 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')
|
||||||
@@ -61,6 +61,7 @@ conf.set('JANET_NO_SOURCEMAPS', not get_option('sourcemaps'))
|
|||||||
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
|
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
|
||||||
conf.set('JANET_NO_PEG', not get_option('peg'))
|
conf.set('JANET_NO_PEG', not get_option('peg'))
|
||||||
conf.set('JANET_NO_NET', not get_option('net'))
|
conf.set('JANET_NO_NET', not get_option('net'))
|
||||||
|
conf.set('JANET_NO_IPV6', not get_option('ipv6'))
|
||||||
conf.set('JANET_NO_EV', not get_option('ev') or get_option('single_threaded'))
|
conf.set('JANET_NO_EV', not get_option('ev') or get_option('single_threaded'))
|
||||||
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
|
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
|
||||||
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
|
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
|
||||||
@@ -78,6 +79,7 @@ conf.set('JANET_EV_NO_KQUEUE', not get_option('kqueue'))
|
|||||||
conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt'))
|
conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt'))
|
||||||
conf.set('JANET_NO_FFI', not get_option('ffi'))
|
conf.set('JANET_NO_FFI', not get_option('ffi'))
|
||||||
conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit'))
|
conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit'))
|
||||||
|
conf.set('JANET_NO_CRYPTORAND', not get_option('cryptorand'))
|
||||||
if get_option('os_name') != ''
|
if get_option('os_name') != ''
|
||||||
conf.set('JANET_OS_NAME', get_option('os_name'))
|
conf.set('JANET_OS_NAME', get_option('os_name'))
|
||||||
endif
|
endif
|
||||||
@@ -182,32 +184,41 @@ if not get_option('single_threaded')
|
|||||||
janet_dependencies += thread_dep
|
janet_dependencies += thread_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Allow building with no shared library
|
||||||
if cc.has_argument('-fvisibility=hidden')
|
if cc.has_argument('-fvisibility=hidden')
|
||||||
lib_cflags = ['-fvisibility=hidden']
|
lib_cflags = ['-fvisibility=hidden']
|
||||||
else
|
else
|
||||||
lib_cflags = []
|
lib_cflags = []
|
||||||
endif
|
endif
|
||||||
libjanet = library('janet', janetc,
|
if get_option('shared')
|
||||||
include_directories : incdir,
|
libjanet = library('janet', janetc,
|
||||||
dependencies : janet_dependencies,
|
include_directories : incdir,
|
||||||
version: meson.project_version(),
|
dependencies : janet_dependencies,
|
||||||
soversion: version_parts[0] + '.' + version_parts[1],
|
version: meson.project_version(),
|
||||||
c_args : lib_cflags,
|
soversion: version_parts[0] + '.' + version_parts[1],
|
||||||
install : true)
|
c_args : lib_cflags,
|
||||||
|
install : true)
|
||||||
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
|
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
|
||||||
# shaves off about 10k on linux x64, likely similar on other platforms.
|
# shaves off about 10k on linux x64, likely similar on other platforms.
|
||||||
if cc.has_argument('-fvisibility=hidden')
|
if cc.has_argument('-fvisibility=hidden')
|
||||||
extra_cflags = ['-fvisibility=hidden', '-DJANET_DLL_IMPORT']
|
extra_cflags = ['-fvisibility=hidden', '-DJANET_DLL_IMPORT']
|
||||||
|
else
|
||||||
|
extra_cflags = ['-DJANET_DLL_IMPORT']
|
||||||
|
endif
|
||||||
|
janet_mainclient = executable('janet', mainclient_src,
|
||||||
|
include_directories : incdir,
|
||||||
|
dependencies : janet_dependencies,
|
||||||
|
link_with: [libjanet],
|
||||||
|
c_args : extra_cflags,
|
||||||
|
install : true)
|
||||||
else
|
else
|
||||||
extra_cflags = ['-DJANET_DLL_IMPORT']
|
# No shared library
|
||||||
|
janet_mainclient = executable('janet', mainclient_src, janetc,
|
||||||
|
include_directories : incdir,
|
||||||
|
dependencies : janet_dependencies,
|
||||||
|
c_args : lib_cflags,
|
||||||
|
install : true)
|
||||||
endif
|
endif
|
||||||
janet_mainclient = executable('janet', mainclient_src,
|
|
||||||
include_directories : incdir,
|
|
||||||
dependencies : janet_dependencies,
|
|
||||||
link_with: [libjanet],
|
|
||||||
c_args : extra_cflags,
|
|
||||||
install : true)
|
|
||||||
|
|
||||||
if meson.is_cross_build()
|
if meson.is_cross_build()
|
||||||
native_cc = meson.get_compiler('c', native: true)
|
native_cc = meson.get_compiler('c', native: true)
|
||||||
@@ -271,14 +282,15 @@ endforeach
|
|||||||
run_target('repl', command : [janet_nativeclient])
|
run_target('repl', command : [janet_nativeclient])
|
||||||
|
|
||||||
# For use as meson subproject (wrap)
|
# For use as meson subproject (wrap)
|
||||||
janet_dep = declare_dependency(include_directories : incdir,
|
if get_option('shared')
|
||||||
link_with : libjanet)
|
janet_dep = declare_dependency(include_directories : incdir,
|
||||||
|
link_with : libjanet)
|
||||||
# pkgconfig
|
# pkgconfig
|
||||||
pkg = import('pkgconfig')
|
pkg = import('pkgconfig')
|
||||||
pkg.generate(libjanet,
|
pkg.generate(libjanet,
|
||||||
subdirs: 'janet',
|
subdirs: 'janet',
|
||||||
description: 'Library for the Janet programming language.')
|
description: 'Library for the Janet programming language.')
|
||||||
|
endif
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
install_man('janet.1')
|
install_man('janet.1')
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ option('peg', type : 'boolean', value : true)
|
|||||||
option('int_types', type : 'boolean', value : true)
|
option('int_types', type : 'boolean', value : true)
|
||||||
option('prf', type : 'boolean', value : false)
|
option('prf', type : 'boolean', value : false)
|
||||||
option('net', type : 'boolean', value : true)
|
option('net', type : 'boolean', value : true)
|
||||||
|
option('ipv6', type : 'boolean', value : true)
|
||||||
option('ev', type : 'boolean', value : true)
|
option('ev', type : 'boolean', value : true)
|
||||||
option('processes', type : 'boolean', value : true)
|
option('processes', type : 'boolean', value : true)
|
||||||
option('umask', type : 'boolean', value : true)
|
option('umask', type : 'boolean', value : true)
|
||||||
option('realpath', type : 'boolean', value : true)
|
option('realpath', type : 'boolean', value : true)
|
||||||
option('simple_getline', type : 'boolean', value : false)
|
option('simple_getline', type : 'boolean', value : false)
|
||||||
option('epoll', type : 'boolean', value : false)
|
option('epoll', type : 'boolean', value : true)
|
||||||
option('kqueue', type : 'boolean', value : false)
|
option('kqueue', type : 'boolean', value : true)
|
||||||
option('interpreter_interrupt', type : 'boolean', value : true)
|
option('interpreter_interrupt', type : 'boolean', value : true)
|
||||||
option('ffi', type : 'boolean', value : true)
|
option('ffi', type : 'boolean', value : true)
|
||||||
option('ffi_jit', type : 'boolean', value : true)
|
option('ffi_jit', type : 'boolean', value : true)
|
||||||
@@ -29,3 +30,5 @@ option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7f
|
|||||||
|
|
||||||
option('arch_name', type : 'string', value: '')
|
option('arch_name', type : 'string', value: '')
|
||||||
option('os_name', type : 'string', value: '')
|
option('os_name', type : 'string', value: '')
|
||||||
|
option('shared', type : 'boolean', value: true)
|
||||||
|
option('cryptorand', type : 'boolean', value: true)
|
||||||
|
|||||||
@@ -162,7 +162,7 @@
|
|||||||
``Define a default value for an optional argument.
|
``Define a default value for an optional argument.
|
||||||
Expands to `(def sym (if (= nil sym) val sym))`.``
|
Expands to `(def sym (if (= nil sym) val sym))`.``
|
||||||
[sym val]
|
[sym val]
|
||||||
~(def ,sym (if (= nil ,sym) ,val ,sym)))
|
~(def ,sym (if (,= nil ,sym) ,val ,sym)))
|
||||||
|
|
||||||
(defmacro comment
|
(defmacro comment
|
||||||
"Ignores the body of the comment."
|
"Ignores the body of the comment."
|
||||||
@@ -420,10 +420,14 @@
|
|||||||
|
|
||||||
(defn- range-template
|
(defn- range-template
|
||||||
[binding object kind rest op comparison]
|
[binding object kind rest op comparison]
|
||||||
(let [[start stop step] (check-indexed object)]
|
(check-indexed object)
|
||||||
(case kind
|
(def [a b c] object)
|
||||||
:range (for-template binding (if stop start 0) (or stop start) (or step 1) comparison op [rest])
|
(def [start stop step]
|
||||||
:down (for-template binding start (or stop 0) (or step 1) comparison op [rest]))))
|
(case (length object)
|
||||||
|
1 (case kind :range [0 a 1] :down [a 0 1])
|
||||||
|
2 [a b 1]
|
||||||
|
[a b c]))
|
||||||
|
(for-template binding start stop step comparison op [rest]))
|
||||||
|
|
||||||
(defn- each-template
|
(defn- each-template
|
||||||
[binding inx kind body]
|
[binding inx kind body]
|
||||||
@@ -438,8 +442,8 @@
|
|||||||
:each ~(,in ,ds ,k)
|
:each ~(,in ,ds ,k)
|
||||||
:keys k
|
:keys k
|
||||||
:pairs ~[,k (,in ,ds ,k)]))
|
:pairs ~[,k (,in ,ds ,k)]))
|
||||||
(set ,k (,next ,ds ,k))
|
,;body
|
||||||
,;body))))
|
(set ,k (,next ,ds ,k))))))
|
||||||
|
|
||||||
(defn- iterate-template
|
(defn- iterate-template
|
||||||
[binding expr body]
|
[binding expr body]
|
||||||
@@ -661,6 +665,9 @@
|
|||||||
(each x xs (*= accum x))
|
(each x xs (*= accum x))
|
||||||
accum)
|
accum)
|
||||||
|
|
||||||
|
# declare ahead of time
|
||||||
|
(var- macexvar nil)
|
||||||
|
|
||||||
(defmacro if-let
|
(defmacro if-let
|
||||||
``Make multiple bindings, and if all are truthy,
|
``Make multiple bindings, and if all are truthy,
|
||||||
evaluate the `tru` form. If any are false or nil, evaluate
|
evaluate the `tru` form. If any are false or nil, evaluate
|
||||||
@@ -669,20 +676,19 @@
|
|||||||
(def len (length bindings))
|
(def len (length bindings))
|
||||||
(if (= 0 len) (error "expected at least 1 binding"))
|
(if (= 0 len) (error "expected at least 1 binding"))
|
||||||
(if (odd? len) (error "expected an even number of bindings"))
|
(if (odd? len) (error "expected an even number of bindings"))
|
||||||
(def res (gensym))
|
(def fal2 (if macexvar (macexvar fal) fal))
|
||||||
(defn aux [i]
|
(defn aux [i]
|
||||||
(if (>= i len)
|
(if (>= i len)
|
||||||
~(do (set ,res ,tru) true)
|
tru
|
||||||
(do
|
(do
|
||||||
(def bl (in bindings i))
|
(def bl (in bindings i))
|
||||||
(def br (in bindings (+ 1 i)))
|
(def br (in bindings (+ 1 i)))
|
||||||
(if (symbol? bl)
|
(if (symbol? bl)
|
||||||
~(if (def ,bl ,br) ,(aux (+ 2 i)))
|
~(if (def ,bl ,br) ,(aux (+ 2 i)) ,fal2)
|
||||||
~(if (def ,(def sym (gensym)) ,br)
|
~(if (def ,(def sym (gensym)) ,br)
|
||||||
(do (def ,bl ,sym) ,(aux (+ 2 i))))))))
|
(do (def ,bl ,sym) ,(aux (+ 2 i)))
|
||||||
~(do
|
,fal2)))))
|
||||||
(var ,res nil)
|
(aux 0))
|
||||||
(if ,(aux 0) ,res ,fal)))
|
|
||||||
|
|
||||||
(defmacro when-let
|
(defmacro when-let
|
||||||
"Same as `(if-let bindings (do ;body))`."
|
"Same as `(if-let bindings (do ;body))`."
|
||||||
@@ -2123,21 +2129,22 @@
|
|||||||
'upscope expandall})
|
'upscope expandall})
|
||||||
|
|
||||||
(defn dotup [t]
|
(defn dotup [t]
|
||||||
|
(if (= nil (next t)) (break ()))
|
||||||
(def h (in t 0))
|
(def h (in t 0))
|
||||||
(def s (in specs h))
|
(def s (in specs h))
|
||||||
(def entry (or (dyn h) {}))
|
(def entry (or (dyn h) {}))
|
||||||
(def m (do (def r (get entry :ref)) (if r (in r 0) (get entry :value))))
|
(def m (do (def r (get entry :ref)) (if r (in r 0) (get entry :value))))
|
||||||
(def m? (in entry :macro))
|
(def m? (in entry :macro))
|
||||||
(cond
|
(cond
|
||||||
s (s t)
|
s (keep-syntax t (s t))
|
||||||
m? (do (setdyn *macro-form* t) (m ;(tuple/slice t 1)))
|
m? (do (setdyn *macro-form* t) (m ;(tuple/slice t 1)))
|
||||||
(tuple/slice (map recur t))))
|
(keep-syntax! t (map recur t))))
|
||||||
|
|
||||||
(def ret
|
(def ret
|
||||||
(case (type x)
|
(case (type x)
|
||||||
:tuple (if (= (tuple/type x) :brackets)
|
:tuple (if (= (tuple/type x) :brackets)
|
||||||
(tuple/brackets ;(map recur x))
|
(tuple/brackets ;(map recur x))
|
||||||
(dotup x))
|
(dotup x))
|
||||||
:array (map recur x)
|
:array (map recur x)
|
||||||
:struct (table/to-struct (dotable x recur))
|
:struct (table/to-struct (dotable x recur))
|
||||||
:table (dotable x recur)
|
:table (dotable x recur)
|
||||||
@@ -2243,6 +2250,8 @@
|
|||||||
(set current (macex1 current on-binding)))
|
(set current (macex1 current on-binding)))
|
||||||
current)
|
current)
|
||||||
|
|
||||||
|
(set macexvar macex)
|
||||||
|
|
||||||
(defmacro varfn
|
(defmacro varfn
|
||||||
``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`
|
||||||
@@ -2333,26 +2342,36 @@
|
|||||||
(def default-peg-grammar
|
(def default-peg-grammar
|
||||||
`The default grammar used for pegs. This grammar defines several common patterns
|
`The default grammar used for pegs. This grammar defines several common patterns
|
||||||
that should make it easier to write more complex patterns.`
|
that should make it easier to write more complex patterns.`
|
||||||
~@{:d (range "09")
|
~@{:a (range "az" "AZ")
|
||||||
:a (range "az" "AZ")
|
:d (range "09")
|
||||||
|
:h (range "09" "af" "AF")
|
||||||
:s (set " \t\r\n\0\f\v")
|
:s (set " \t\r\n\0\f\v")
|
||||||
:w (range "az" "AZ" "09")
|
:w (range "az" "AZ" "09")
|
||||||
:h (range "09" "af" "AF")
|
|
||||||
:S (if-not :s 1)
|
|
||||||
:W (if-not :w 1)
|
|
||||||
:A (if-not :a 1)
|
:A (if-not :a 1)
|
||||||
:D (if-not :d 1)
|
:D (if-not :d 1)
|
||||||
:H (if-not :h 1)
|
:H (if-not :h 1)
|
||||||
:d+ (some :d)
|
:S (if-not :s 1)
|
||||||
|
:W (if-not :w 1)
|
||||||
:a+ (some :a)
|
:a+ (some :a)
|
||||||
|
:d+ (some :d)
|
||||||
|
:h+ (some :h)
|
||||||
:s+ (some :s)
|
:s+ (some :s)
|
||||||
:w+ (some :w)
|
:w+ (some :w)
|
||||||
:h+ (some :h)
|
:A+ (some :A)
|
||||||
:d* (any :d)
|
:D+ (some :D)
|
||||||
|
:H+ (some :H)
|
||||||
|
:S+ (some :S)
|
||||||
|
:W+ (some :W)
|
||||||
:a* (any :a)
|
:a* (any :a)
|
||||||
:w* (any :w)
|
:d* (any :d)
|
||||||
|
:h* (any :h)
|
||||||
:s* (any :s)
|
:s* (any :s)
|
||||||
:h* (any :h)})
|
:w* (any :w)
|
||||||
|
:A* (any :A)
|
||||||
|
:D* (any :D)
|
||||||
|
:H* (any :H)
|
||||||
|
:S* (any :S)
|
||||||
|
:W* (any :W)})
|
||||||
|
|
||||||
(setdyn *peg-grammar* default-peg-grammar)
|
(setdyn *peg-grammar* default-peg-grammar)
|
||||||
|
|
||||||
@@ -2748,6 +2767,11 @@
|
|||||||
(defn- check-is-dep [x] (unless (or (string/has-prefix? "/" x) (string/has-prefix? "@" x) (string/has-prefix? "." x)) x))
|
(defn- check-is-dep [x] (unless (or (string/has-prefix? "/" x) (string/has-prefix? "@" x) (string/has-prefix? "." x)) x))
|
||||||
(defn- check-project-relative [x] (if (string/has-prefix? "/" x) x))
|
(defn- check-project-relative [x] (if (string/has-prefix? "/" x) x))
|
||||||
|
|
||||||
|
(defdyn *module/cache* "Dynamic binding for overriding `module/cache`")
|
||||||
|
(defdyn *module/paths* "Dynamic binding for overriding `module/cache`")
|
||||||
|
(defdyn *module/loading* "Dynamic binding for overriding `module/cache`")
|
||||||
|
(defdyn *module/loaders* "Dynamic binding for overriding `module/loaders`")
|
||||||
|
|
||||||
(def module/cache
|
(def module/cache
|
||||||
"A table, mapping loaded module identifiers to their environments."
|
"A table, mapping loaded module identifiers to their environments."
|
||||||
@{})
|
@{})
|
||||||
@@ -2776,24 +2800,25 @@
|
|||||||
keyword name of a loader in `module/loaders`. Returns the modified `module/paths`.
|
keyword name of a loader in `module/loaders`. Returns the modified `module/paths`.
|
||||||
```
|
```
|
||||||
[ext loader]
|
[ext loader]
|
||||||
|
(def mp (dyn *module/paths* module/paths))
|
||||||
(defn- find-prefix
|
(defn- find-prefix
|
||||||
[pre]
|
[pre]
|
||||||
(or (find-index |(and (string? ($ 0)) (string/has-prefix? pre ($ 0))) module/paths) 0))
|
(or (find-index |(and (string? ($ 0)) (string/has-prefix? pre ($ 0))) mp) 0))
|
||||||
(def dyn-index (find-prefix ":@all:"))
|
(def dyn-index (find-prefix ":@all:"))
|
||||||
(array/insert module/paths dyn-index [(string ":@all:" ext) loader check-dyn-relative])
|
(array/insert mp dyn-index [(string ":@all:" ext) loader check-dyn-relative])
|
||||||
(def all-index (find-prefix ".:all:"))
|
(def all-index (find-prefix ".:all:"))
|
||||||
(array/insert module/paths all-index [(string ".:all:" ext) loader check-project-relative])
|
(array/insert mp all-index [(string ".:all:" ext) loader check-project-relative])
|
||||||
(def sys-index (find-prefix ":sys:"))
|
(def sys-index (find-prefix ":sys:"))
|
||||||
(array/insert module/paths sys-index [(string ":sys:/:all:" ext) loader check-is-dep])
|
(array/insert mp sys-index [(string ":sys:/:all:" ext) loader check-is-dep])
|
||||||
(def curall-index (find-prefix ":cur:/:all:"))
|
(def curall-index (find-prefix ":cur:/:all:"))
|
||||||
(array/insert module/paths curall-index [(string ":cur:/:all:" ext) loader check-relative])
|
(array/insert mp curall-index [(string ":cur:/:all:" ext) loader check-relative])
|
||||||
module/paths)
|
mp)
|
||||||
|
|
||||||
(module/add-paths ":native:" :native)
|
(module/add-paths ":native:" :native)
|
||||||
(module/add-paths "/init.janet" :source)
|
(module/add-paths "/init.janet" :source)
|
||||||
(module/add-paths ".janet" :source)
|
(module/add-paths ".janet" :source)
|
||||||
(module/add-paths ".jimage" :image)
|
(module/add-paths ".jimage" :image)
|
||||||
(array/insert module/paths 0 [(fn is-cached [path] (if (in module/cache path) path)) :preload check-not-relative])
|
(array/insert module/paths 0 [(fn is-cached [path] (if (in (dyn *module/cache* module/cache) path) path)) :preload check-not-relative])
|
||||||
|
|
||||||
# Version of fexists that works even with a reduced OS
|
# Version of fexists that works even with a reduced OS
|
||||||
(defn- fexists
|
(defn- fexists
|
||||||
@@ -2823,7 +2848,8 @@
|
|||||||
```
|
```
|
||||||
[path]
|
[path]
|
||||||
(var ret nil)
|
(var ret nil)
|
||||||
(each [p mod-kind checker] module/paths
|
(def mp (dyn *module/paths* module/paths))
|
||||||
|
(each [p mod-kind checker] mp
|
||||||
(when (mod-filter checker path)
|
(when (mod-filter checker path)
|
||||||
(if (function? p)
|
(if (function? p)
|
||||||
(when-let [res (p path)]
|
(when-let [res (p path)]
|
||||||
@@ -2839,7 +2865,7 @@
|
|||||||
(when (string? t)
|
(when (string? t)
|
||||||
(when (mod-filter chk path)
|
(when (mod-filter chk path)
|
||||||
(module/expand-path path t))))
|
(module/expand-path path t))))
|
||||||
paths (filter identity (map expander module/paths))
|
paths (filter identity (map expander mp))
|
||||||
str-parts (interpose "\n " paths)]
|
str-parts (interpose "\n " paths)]
|
||||||
[nil (string "could not find module " path ":\n " ;str-parts)])))
|
[nil (string "could not find module " path ":\n " ;str-parts)])))
|
||||||
|
|
||||||
@@ -2994,13 +3020,15 @@
|
|||||||
of files as modules.``
|
of files as modules.``
|
||||||
@{:native (fn native-loader [path &] (native path (make-env)))
|
@{:native (fn native-loader [path &] (native path (make-env)))
|
||||||
:source (fn source-loader [path args]
|
:source (fn source-loader [path args]
|
||||||
(put module/loading path true)
|
(def ml (dyn *module/loading* module/loading))
|
||||||
(defer (put module/loading path nil)
|
(put ml path true)
|
||||||
|
(defer (put ml path nil)
|
||||||
(dofile path ;args)))
|
(dofile path ;args)))
|
||||||
:preload (fn preload-loader [path & args]
|
:preload (fn preload-loader [path & args]
|
||||||
(when-let [m (in module/cache path)]
|
(def mc (dyn *module/cache* module/cache))
|
||||||
|
(when-let [m (in mc path)]
|
||||||
(if (function? m)
|
(if (function? m)
|
||||||
(set (module/cache path) (m path ;args))
|
(set (mc path) (m path ;args))
|
||||||
m)))
|
m)))
|
||||||
:image (fn image-loader [path &] (load-image (slurp path)))})
|
:image (fn image-loader [path &] (load-image (slurp path)))})
|
||||||
|
|
||||||
@@ -3008,15 +3036,18 @@
|
|||||||
[path args kargs]
|
[path args kargs]
|
||||||
(def [fullpath mod-kind] (module/find path))
|
(def [fullpath mod-kind] (module/find path))
|
||||||
(unless fullpath (error mod-kind))
|
(unless fullpath (error mod-kind))
|
||||||
(if-let [check (if-not (kargs :fresh) (in module/cache fullpath))]
|
(def mc (dyn *module/cache* module/cache))
|
||||||
|
(def ml (dyn *module/loading* module/loading))
|
||||||
|
(def mls (dyn *module/loaders* module/loaders))
|
||||||
|
(if-let [check (if-not (kargs :fresh) (in mc fullpath))]
|
||||||
check
|
check
|
||||||
(if (module/loading fullpath)
|
(if (ml fullpath)
|
||||||
(error (string "circular dependency " fullpath " detected"))
|
(error (string "circular dependency " fullpath " detected"))
|
||||||
(do
|
(do
|
||||||
(def loader (if (keyword? mod-kind) (module/loaders mod-kind) mod-kind))
|
(def loader (if (keyword? mod-kind) (mls mod-kind) mod-kind))
|
||||||
(unless loader (error (string "module type " mod-kind " unknown")))
|
(unless loader (error (string "module type " mod-kind " unknown")))
|
||||||
(def env (loader fullpath args))
|
(def env (loader fullpath args))
|
||||||
(put module/cache fullpath env)
|
(put mc fullpath env)
|
||||||
env))))
|
env))))
|
||||||
|
|
||||||
(defn require
|
(defn require
|
||||||
@@ -3717,12 +3748,20 @@
|
|||||||
~(,ev/thread (fn _spawn-thread [&] ,;body) nil :n))
|
~(,ev/thread (fn _spawn-thread [&] ,;body) nil :n))
|
||||||
|
|
||||||
(defmacro ev/with-deadline
|
(defmacro ev/with-deadline
|
||||||
`Run a body of code with a deadline, such that if the code does not complete before
|
``
|
||||||
the deadline is up, it will be canceled.`
|
Create a fiber to execute `body`, schedule the event loop to cancel
|
||||||
[deadline & body]
|
the task (root fiber) associated with `body`'s fiber, and start
|
||||||
|
`body`'s fiber by resuming it.
|
||||||
|
|
||||||
|
The event loop will try to cancel the root fiber if `body`'s fiber
|
||||||
|
has not completed after at least `sec` seconds.
|
||||||
|
|
||||||
|
`sec` is a number that can have a fractional part.
|
||||||
|
``
|
||||||
|
[sec & body]
|
||||||
(with-syms [f]
|
(with-syms [f]
|
||||||
~(let [,f (coro ,;body)]
|
~(let [,f (coro ,;body)]
|
||||||
(,ev/deadline ,deadline nil ,f)
|
(,ev/deadline ,sec nil ,f)
|
||||||
(,resume ,f))))
|
(,resume ,f))))
|
||||||
|
|
||||||
(defn- cancel-all [chan fibers reason]
|
(defn- cancel-all [chan fibers reason]
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#define JANETCONF_H
|
#define JANETCONF_H
|
||||||
|
|
||||||
#define JANET_VERSION_MAJOR 1
|
#define JANET_VERSION_MAJOR 1
|
||||||
#define JANET_VERSION_MINOR 31
|
#define JANET_VERSION_MINOR 34
|
||||||
#define JANET_VERSION_PATCH 0
|
#define JANET_VERSION_PATCH 0
|
||||||
#define JANET_VERSION_EXTRA ""
|
#define JANET_VERSION_EXTRA ""
|
||||||
#define JANET_VERSION "1.31.0"
|
#define JANET_VERSION "1.34.0"
|
||||||
|
|
||||||
/* #define JANET_BUILD "local" */
|
/* #define JANET_BUILD "local" */
|
||||||
|
|
||||||
@@ -52,6 +52,9 @@
|
|||||||
/* #define JANET_EV_NO_EPOLL */
|
/* #define JANET_EV_NO_EPOLL */
|
||||||
/* #define JANET_EV_NO_KQUEUE */
|
/* #define JANET_EV_NO_KQUEUE */
|
||||||
/* #define JANET_NO_INTERPRETER_INTERRUPT */
|
/* #define JANET_NO_INTERPRETER_INTERRUPT */
|
||||||
|
/* #define JANET_NO_IPV6 */
|
||||||
|
/* #define JANET_NO_CRYPTORAND */
|
||||||
|
/* #define JANET_USE_STDATOMIC */
|
||||||
|
|
||||||
/* Custom vm allocator support */
|
/* Custom vm allocator support */
|
||||||
/* #include <mimalloc.h> */
|
/* #include <mimalloc.h> */
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
|
||||||
#include <stdatomic.h>
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -560,6 +560,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
|||||||
x = janet_get1(s, janet_ckeywordv("vararg"));
|
x = janet_get1(s, janet_ckeywordv("vararg"));
|
||||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
||||||
|
|
||||||
|
/* Initialize slotcount */
|
||||||
|
def->slotcount = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG) + def->arity;
|
||||||
|
|
||||||
/* Check structarg */
|
/* Check structarg */
|
||||||
x = janet_get1(s, janet_ckeywordv("structarg"));
|
x = janet_get1(s, janet_ckeywordv("structarg"));
|
||||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||||
@@ -784,8 +787,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the func def */
|
/* Verify the func def */
|
||||||
if (janet_verify(def)) {
|
int verify_status = janet_verify(def);
|
||||||
janet_asm_error(&a, "invalid assembly");
|
if (verify_status) {
|
||||||
|
janet_asm_errorv(&a, janet_formatc("invalid assembly (%d)", verify_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add final flags */
|
/* Add final flags */
|
||||||
|
|||||||
@@ -135,8 +135,7 @@ void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
|
|||||||
|
|
||||||
/* Push a cstring to buffer */
|
/* Push a cstring to buffer */
|
||||||
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
|
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
|
||||||
int32_t len = 0;
|
int32_t len = (int32_t) strlen(cstring);
|
||||||
while (cstring[len]) ++len;
|
|
||||||
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
|
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +320,143 @@ JANET_CORE_FN(cfun_buffer_chars,
|
|||||||
return argv[0];
|
return argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int should_reverse_bytes(const Janet *argv, int32_t argc) {
|
||||||
|
JanetKeyword order_kw = janet_getkeyword(argv, argc);
|
||||||
|
if (!janet_cstrcmp(order_kw, "le")) {
|
||||||
|
#if JANET_BIG_ENDIAN
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
} else if (!janet_cstrcmp(order_kw, "be")) {
|
||||||
|
#if JANET_LITTLE_ENDIAN
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
} else if (!janet_cstrcmp(order_kw, "native")) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
janet_panicf("expected endianness :le, :be or :native, got %v", argv[1]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_u32(uint8_t bytes[4]) {
|
||||||
|
uint8_t temp;
|
||||||
|
temp = bytes[3];
|
||||||
|
bytes[3] = bytes[0];
|
||||||
|
bytes[0] = temp;
|
||||||
|
temp = bytes[2];
|
||||||
|
bytes[2] = bytes[1];
|
||||||
|
bytes[1] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_u64(uint8_t bytes[8]) {
|
||||||
|
uint8_t temp;
|
||||||
|
temp = bytes[7];
|
||||||
|
bytes[7] = bytes[0];
|
||||||
|
bytes[0] = temp;
|
||||||
|
temp = bytes[6];
|
||||||
|
bytes[6] = bytes[1];
|
||||||
|
bytes[1] = temp;
|
||||||
|
temp = bytes[5];
|
||||||
|
bytes[5] = bytes[2];
|
||||||
|
bytes[2] = temp;
|
||||||
|
temp = bytes[4];
|
||||||
|
bytes[4] = bytes[3];
|
||||||
|
bytes[3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_buffer_push_uint16,
|
||||||
|
"(buffer/push-uint16 buffer order data)",
|
||||||
|
"Push a 16 bit unsigned integer data onto the end of the buffer. "
|
||||||
|
"Returns the modified buffer.") {
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||||
|
int reverse = should_reverse_bytes(argv, 1);
|
||||||
|
union {
|
||||||
|
uint16_t data;
|
||||||
|
uint8_t bytes[2];
|
||||||
|
} u;
|
||||||
|
u.data = (uint16_t) janet_getinteger(argv, 2);
|
||||||
|
if (reverse) {
|
||||||
|
uint8_t temp = u.bytes[1];
|
||||||
|
u.bytes[1] = u.bytes[0];
|
||||||
|
u.bytes[0] = temp;
|
||||||
|
}
|
||||||
|
janet_buffer_push_u16(buffer, *(uint16_t *) u.bytes);
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_buffer_push_uint32,
|
||||||
|
"(buffer/push-uint32 buffer order data)",
|
||||||
|
"Push a 32 bit unsigned integer data onto the end of the buffer. "
|
||||||
|
"Returns the modified buffer.") {
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||||
|
int reverse = should_reverse_bytes(argv, 1);
|
||||||
|
union {
|
||||||
|
uint32_t data;
|
||||||
|
uint8_t bytes[4];
|
||||||
|
} u;
|
||||||
|
u.data = (uint32_t) janet_getinteger(argv, 2);
|
||||||
|
if (reverse)
|
||||||
|
reverse_u32(u.bytes);
|
||||||
|
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_buffer_push_uint64,
|
||||||
|
"(buffer/push-uint64 buffer order data)",
|
||||||
|
"Push a 64 bit unsigned integer data onto the end of the buffer. "
|
||||||
|
"Returns the modified buffer.") {
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||||
|
int reverse = should_reverse_bytes(argv, 1);
|
||||||
|
union {
|
||||||
|
uint64_t data;
|
||||||
|
uint8_t bytes[8];
|
||||||
|
} u;
|
||||||
|
u.data = (uint64_t) janet_getuinteger64(argv, 2);
|
||||||
|
if (reverse)
|
||||||
|
reverse_u64(u.bytes);
|
||||||
|
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_buffer_push_float32,
|
||||||
|
"(buffer/push-float32 buffer order data)",
|
||||||
|
"Push the underlying bytes of a 32 bit float data onto the end of the buffer. "
|
||||||
|
"Returns the modified buffer.") {
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||||
|
int reverse = should_reverse_bytes(argv, 1);
|
||||||
|
union {
|
||||||
|
float data;
|
||||||
|
uint8_t bytes[4];
|
||||||
|
} u;
|
||||||
|
u.data = (float) janet_getnumber(argv, 2);
|
||||||
|
if (reverse)
|
||||||
|
reverse_u32(u.bytes);
|
||||||
|
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_buffer_push_float64,
|
||||||
|
"(buffer/push-float64 buffer order data)",
|
||||||
|
"Push the underlying bytes of a 64 bit float data onto the end of the buffer. "
|
||||||
|
"Returns the modified buffer.") {
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||||
|
int reverse = should_reverse_bytes(argv, 1);
|
||||||
|
union {
|
||||||
|
double data;
|
||||||
|
uint8_t bytes[8];
|
||||||
|
} u;
|
||||||
|
u.data = janet_getnumber(argv, 2);
|
||||||
|
if (reverse)
|
||||||
|
reverse_u64(u.bytes);
|
||||||
|
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) {
|
static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) {
|
||||||
for (int32_t i = argc_offset; i < argc; i++) {
|
for (int32_t i = argc_offset; i < argc; i++) {
|
||||||
if (janet_checktype(argv[i], JANET_NUMBER)) {
|
if (janet_checktype(argv[i], JANET_NUMBER)) {
|
||||||
@@ -529,6 +665,11 @@ void janet_lib_buffer(JanetTable *env) {
|
|||||||
JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8),
|
JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8),
|
||||||
JANET_CORE_REG("buffer/push-word", cfun_buffer_word),
|
JANET_CORE_REG("buffer/push-word", cfun_buffer_word),
|
||||||
JANET_CORE_REG("buffer/push-string", cfun_buffer_chars),
|
JANET_CORE_REG("buffer/push-string", cfun_buffer_chars),
|
||||||
|
JANET_CORE_REG("buffer/push-uint16", cfun_buffer_push_uint16),
|
||||||
|
JANET_CORE_REG("buffer/push-uint32", cfun_buffer_push_uint32),
|
||||||
|
JANET_CORE_REG("buffer/push-uint64", cfun_buffer_push_uint64),
|
||||||
|
JANET_CORE_REG("buffer/push-float32", cfun_buffer_push_float32),
|
||||||
|
JANET_CORE_REG("buffer/push-float64", cfun_buffer_push_float64),
|
||||||
JANET_CORE_REG("buffer/push", cfun_buffer_push),
|
JANET_CORE_REG("buffer/push", cfun_buffer_push),
|
||||||
JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at),
|
JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at),
|
||||||
JANET_CORE_REG("buffer/popn", cfun_buffer_popn),
|
JANET_CORE_REG("buffer/popn", cfun_buffer_popn),
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
|
|||||||
case JOP_LOAD_TRUE:
|
case JOP_LOAD_TRUE:
|
||||||
case JOP_LOAD_FALSE:
|
case JOP_LOAD_FALSE:
|
||||||
case JOP_LOAD_SELF:
|
case JOP_LOAD_SELF:
|
||||||
|
break;
|
||||||
case JOP_MAKE_ARRAY:
|
case JOP_MAKE_ARRAY:
|
||||||
case JOP_MAKE_BUFFER:
|
case JOP_MAKE_BUFFER:
|
||||||
case JOP_MAKE_STRING:
|
case JOP_MAKE_STRING:
|
||||||
@@ -233,6 +234,8 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
|
|||||||
case JOP_MAKE_TABLE:
|
case JOP_MAKE_TABLE:
|
||||||
case JOP_MAKE_TUPLE:
|
case JOP_MAKE_TUPLE:
|
||||||
case JOP_MAKE_BRACKET_TUPLE:
|
case JOP_MAKE_BRACKET_TUPLE:
|
||||||
|
/* Reads from the stack, don't remove */
|
||||||
|
janetc_regalloc_touch(&ra, DD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Read A */
|
/* Read A */
|
||||||
|
|||||||
@@ -35,6 +35,13 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JANET_USE_STDATOMIC
|
||||||
|
#include <stdatomic.h>
|
||||||
|
/* We don't need stdatomic on most compilers since we use compiler builtins for atomic operations.
|
||||||
|
* Some (TCC), explicitly require using stdatomic.h and don't have any exposed builtins (that I know of).
|
||||||
|
* For TCC and similar compilers, one would need -std=c11 or similar then to get access. */
|
||||||
|
#endif
|
||||||
|
|
||||||
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
|
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
|
||||||
#ifdef JANET_TOP_LEVEL_SIGNAL
|
#ifdef JANET_TOP_LEVEL_SIGNAL
|
||||||
JANET_TOP_LEVEL_SIGNAL(msg);
|
JANET_TOP_LEVEL_SIGNAL(msg);
|
||||||
@@ -338,7 +345,7 @@ int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const c
|
|||||||
int32_t not_raw = raw;
|
int32_t not_raw = raw;
|
||||||
if (not_raw < 0) not_raw += length + 1;
|
if (not_raw < 0) not_raw += length + 1;
|
||||||
if (not_raw < 0 || not_raw > length)
|
if (not_raw < 0 || not_raw > length)
|
||||||
janet_panicf("%s index %d out of range [%d,%d]", which, raw, -length - 1, length);
|
janet_panicf("%s index %d out of range [%d,%d]", which, (int64_t) raw, -(int64_t)length - 1, (int64_t) length);
|
||||||
return not_raw;
|
return not_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +368,7 @@ int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const ch
|
|||||||
int32_t not_raw = raw;
|
int32_t not_raw = raw;
|
||||||
if (not_raw < 0) not_raw += length;
|
if (not_raw < 0) not_raw += length;
|
||||||
if (not_raw < 0 || not_raw > length)
|
if (not_raw < 0 || not_raw > length)
|
||||||
janet_panicf("%s index %d out of range [%d,%d)", which, raw, -length, length);
|
janet_panicf("%s index %d out of range [%d,%d)", which, (int64_t)raw, -(int64_t)length, (int64_t)length);
|
||||||
return not_raw;
|
return not_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,6 +503,8 @@ void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetA
|
|||||||
JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
|
JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
return InterlockedIncrement(x);
|
return InterlockedIncrement(x);
|
||||||
|
#elif defined(JANET_USE_STDATOMIC)
|
||||||
|
return atomic_fetch_add_explicit(x, 1, memory_order_relaxed) + 1;
|
||||||
#else
|
#else
|
||||||
return __atomic_add_fetch(x, 1, __ATOMIC_RELAXED);
|
return __atomic_add_fetch(x, 1, __ATOMIC_RELAXED);
|
||||||
#endif
|
#endif
|
||||||
@@ -504,8 +513,20 @@ JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
|
|||||||
JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
|
JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
return InterlockedDecrement(x);
|
return InterlockedDecrement(x);
|
||||||
|
#elif defined(JANET_USE_STDATOMIC)
|
||||||
|
return atomic_fetch_add_explicit(x, -1, memory_order_acq_rel) - 1;
|
||||||
#else
|
#else
|
||||||
return __atomic_add_fetch(x, -1, __ATOMIC_RELAXED);
|
return __atomic_add_fetch(x, -1, __ATOMIC_ACQ_REL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x) {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
return InterlockedOr(x, 0);
|
||||||
|
#elif defined(JANET_USE_STDATOMIC)
|
||||||
|
return atomic_load_explicit(x, memory_order_acquire);
|
||||||
|
#else
|
||||||
|
return __atomic_load_n(x, __ATOMIC_ACQUIRE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,14 +110,14 @@ JANET_CORE_FN(janet_core_expand_path,
|
|||||||
"(module/expand-path path template)",
|
"(module/expand-path path template)",
|
||||||
"Expands a path template as found in `module/paths` for `module/find`. "
|
"Expands a path template as found in `module/paths` for `module/find`. "
|
||||||
"This takes in a path (the argument to require) and a template string, "
|
"This takes in a path (the argument to require) and a template string, "
|
||||||
"to expand the path to a path that can be "
|
"to expand the path to a path that can be used for importing files. "
|
||||||
"used for importing files. The replacements are as follows:\n\n"
|
"The replacements are as follows:\n\n"
|
||||||
"* :all: -- the value of path verbatim.\n\n"
|
"* :all: -- the value of path verbatim.\n\n"
|
||||||
"* :@all: -- Same as :all:, but if `path` starts with the @ character,\n"
|
"* :@all: -- Same as :all:, but if `path` starts with the @ character, "
|
||||||
" the first path segment is replaced with a dynamic binding\n"
|
"the first path segment is replaced with a dynamic binding "
|
||||||
" `(dyn <first path segment as keyword>)`.\n\n"
|
"`(dyn <first path segment as keyword>)`.\n\n"
|
||||||
"* :cur: -- the current file, or (dyn :current-file)\n\n"
|
"* :cur: -- the directory portion, if any, of (dyn :current-file)\n\n"
|
||||||
"* :dir: -- the directory containing the current file\n\n"
|
"* :dir: -- the directory portion, if any, of the path argument\n\n"
|
||||||
"* :name: -- the name component of path, with extension if given\n\n"
|
"* :name: -- the name component of path, with extension if given\n\n"
|
||||||
"* :native: -- the extension used to load natives, .so or .dll\n\n"
|
"* :native: -- the extension used to load natives, .so or .dll\n\n"
|
||||||
"* :sys: -- the system path, or (dyn :syspath)") {
|
"* :sys: -- the system path, or (dyn :syspath)") {
|
||||||
@@ -1144,17 +1144,20 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
|||||||
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 they 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. The resulting "
|
"Propagate a signal from a fiber to the current fiber and "
|
||||||
"stack trace from the current fiber will include frames from fiber. If "
|
"set the last value of the current fiber to `x`. The signal "
|
||||||
"fiber is in a state that can be resumed, resuming the current fiber will "
|
"value is then available as the status of the current fiber. "
|
||||||
"first resume fiber. This function can be used to re-raise an error without "
|
"The resulting stack trace from the current fiber will include "
|
||||||
"losing the original stack trace."));
|
"frames from fiber. If fiber is in a state that can be resumed, "
|
||||||
|
"resuming the current fiber will first resume `fiber`. "
|
||||||
|
"This function can be used to re-raise an error without losing "
|
||||||
|
"the original stack trace."));
|
||||||
janet_quick_asm(env, JANET_FUN_DEBUG,
|
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"
|
||||||
|
|||||||
@@ -388,8 +388,8 @@ JANET_CORE_FN(cfun_debug_stack,
|
|||||||
JANET_CORE_FN(cfun_debug_stacktrace,
|
JANET_CORE_FN(cfun_debug_stacktrace,
|
||||||
"(debug/stacktrace fiber &opt err prefix)",
|
"(debug/stacktrace fiber &opt err prefix)",
|
||||||
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
|
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
|
||||||
"an error value to print the stack trace with. If `err` is nil or not "
|
"an error value to print the stack trace with. If `prefix` is nil or not "
|
||||||
"provided, and no prefix is given, will skip the error line. Returns the fiber.") {
|
"provided, will skip the error line. Returns the fiber.") {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||||
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
||||||
|
|||||||
189
src/core/ev.c
189
src/core/ev.c
@@ -255,19 +255,29 @@ static void add_timeout(JanetTimeout to) {
|
|||||||
|
|
||||||
void janet_async_end(JanetFiber *fiber) {
|
void janet_async_end(JanetFiber *fiber) {
|
||||||
if (fiber->ev_callback) {
|
if (fiber->ev_callback) {
|
||||||
|
fiber->ev_callback(fiber, JANET_ASYNC_EVENT_DEINIT);
|
||||||
janet_gcunroot(janet_wrap_abstract(fiber->ev_stream));
|
janet_gcunroot(janet_wrap_abstract(fiber->ev_stream));
|
||||||
fiber->ev_callback = NULL;
|
fiber->ev_callback = NULL;
|
||||||
if (fiber->ev_state) {
|
if (!(fiber->flags & JANET_FIBER_EV_FLAG_IN_FLIGHT)) {
|
||||||
if (!(fiber->flags & JANET_FIBER_EV_FLAG_IN_FLIGHT)) {
|
if (fiber->ev_state) {
|
||||||
janet_free(fiber->ev_state);
|
janet_free(fiber->ev_state);
|
||||||
janet_ev_dec_refcount();
|
fiber->ev_state = NULL;
|
||||||
}
|
}
|
||||||
fiber->ev_state = NULL;
|
janet_ev_dec_refcount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, size_t data_size) {
|
void janet_async_in_flight(JanetFiber *fiber) {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
||||||
|
#else
|
||||||
|
(void) fiber;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_async_start(JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, void *state) {
|
||||||
|
JanetFiber *fiber = janet_vm.root_fiber;
|
||||||
janet_assert(!fiber->ev_callback, "double async on fiber");
|
janet_assert(!fiber->ev_callback, "double async on fiber");
|
||||||
if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber;
|
if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber;
|
||||||
if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber;
|
if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber;
|
||||||
@@ -275,14 +285,9 @@ void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode m
|
|||||||
fiber->ev_stream = stream;
|
fiber->ev_stream = stream;
|
||||||
janet_ev_inc_refcount();
|
janet_ev_inc_refcount();
|
||||||
janet_gcroot(janet_wrap_abstract(stream));
|
janet_gcroot(janet_wrap_abstract(stream));
|
||||||
if (data_size) {
|
fiber->ev_state = state;
|
||||||
void *data = janet_malloc(data_size);
|
callback(fiber, JANET_ASYNC_EVENT_INIT);
|
||||||
fiber->ev_state = data;
|
janet_await();
|
||||||
return data;
|
|
||||||
} else {
|
|
||||||
fiber->ev_state = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_fiber_did_resume(JanetFiber *fiber) {
|
void janet_fiber_did_resume(JanetFiber *fiber) {
|
||||||
@@ -445,6 +450,9 @@ static void *janet_stream_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
p->handle = (JanetHandle) janet_unmarshal_int64(ctx);
|
p->handle = (JanetHandle) janet_unmarshal_int64(ctx);
|
||||||
#else
|
#else
|
||||||
p->handle = (JanetHandle) janet_unmarshal_int(ctx);
|
p->handle = (JanetHandle) janet_unmarshal_int(ctx);
|
||||||
|
#endif
|
||||||
|
#ifdef JANET_EV_POLL
|
||||||
|
janet_register_stream(p);
|
||||||
#endif
|
#endif
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -1161,10 +1169,12 @@ JANET_CORE_FN(cfun_channel_close,
|
|||||||
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);
|
||||||
} else {
|
} else {
|
||||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
if (janet_fiber_can_resume(writer.fiber)) {
|
||||||
janet_schedule(writer.fiber, make_close_result(channel));
|
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||||
} else {
|
janet_schedule(writer.fiber, make_close_result(channel));
|
||||||
janet_schedule(writer.fiber, janet_wrap_nil());
|
} else {
|
||||||
|
janet_schedule(writer.fiber, janet_wrap_nil());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1180,10 +1190,12 @@ JANET_CORE_FN(cfun_channel_close,
|
|||||||
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);
|
||||||
} else {
|
} else {
|
||||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
if (janet_fiber_can_resume(reader.fiber)) {
|
||||||
janet_schedule(reader.fiber, make_close_result(channel));
|
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||||
} else {
|
janet_schedule(reader.fiber, make_close_result(channel));
|
||||||
janet_schedule(reader.fiber, janet_wrap_nil());
|
} else {
|
||||||
|
janet_schedule(reader.fiber, janet_wrap_nil());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1279,7 +1291,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout);
|
|||||||
int janet_loop_done(void) {
|
int janet_loop_done(void) {
|
||||||
return !((janet_vm.spawn.head != janet_vm.spawn.tail) ||
|
return !((janet_vm.spawn.head != janet_vm.spawn.tail) ||
|
||||||
janet_vm.tq_count ||
|
janet_vm.tq_count ||
|
||||||
janet_vm.listener_count);
|
janet_atomic_load(&janet_vm.listener_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
JanetFiber *janet_loop1(void) {
|
JanetFiber *janet_loop1(void) {
|
||||||
@@ -1341,7 +1353,7 @@ JanetFiber *janet_loop1(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Poll for events */
|
/* Poll for events */
|
||||||
if (janet_vm.tq_count || janet_vm.listener_count) {
|
if (janet_vm.tq_count || janet_atomic_load(&janet_vm.listener_count)) {
|
||||||
JanetTimeout to;
|
JanetTimeout to;
|
||||||
memset(&to, 0, sizeof(to));
|
memset(&to, 0, sizeof(to));
|
||||||
int has_timeout;
|
int has_timeout;
|
||||||
@@ -1360,7 +1372,7 @@ JanetFiber *janet_loop1(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Run polling implementation only if pending timeouts or pending events */
|
/* Run polling implementation only if pending timeouts or pending events */
|
||||||
if (janet_vm.tq_count || janet_vm.listener_count) {
|
if (janet_vm.tq_count || janet_atomic_load(&janet_vm.listener_count)) {
|
||||||
janet_loop1_impl(has_timeout, to.when);
|
janet_loop1_impl(has_timeout, to.when);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1447,7 +1459,7 @@ void janet_ev_deinit(void) {
|
|||||||
CloseHandle(janet_vm.iocp);
|
CloseHandle(janet_vm.iocp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_register_stream(JanetStream *stream) {
|
static void janet_register_stream(JanetStream *stream) {
|
||||||
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
|
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
|
||||||
janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
|
janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
|
||||||
}
|
}
|
||||||
@@ -1813,8 +1825,8 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
|||||||
JanetStream *stream = janet_vm.streams[i];
|
JanetStream *stream = janet_vm.streams[i];
|
||||||
janet_vm.fds[i + 1].events = 0;
|
janet_vm.fds[i + 1].events = 0;
|
||||||
janet_vm.fds[i + 1].revents = 0;
|
janet_vm.fds[i + 1].revents = 0;
|
||||||
if (stream->read_fiber) janet_vm.fds[i + 1].events |= POLLIN;
|
if (stream->read_fiber && stream->read_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLIN;
|
||||||
if (stream->write_fiber) janet_vm.fds[i + 1].events |= POLLOUT;
|
if (stream->write_fiber && stream->write_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Poll for events */
|
/* Poll for events */
|
||||||
@@ -2026,33 +2038,35 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) {
|
|||||||
if (return_value.fiber == NULL) {
|
if (return_value.fiber == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (return_value.tag) {
|
if (janet_fiber_can_resume(return_value.fiber)) {
|
||||||
default:
|
switch (return_value.tag) {
|
||||||
case JANET_EV_TCTAG_NIL:
|
default:
|
||||||
janet_schedule(return_value.fiber, janet_wrap_nil());
|
case JANET_EV_TCTAG_NIL:
|
||||||
break;
|
janet_schedule(return_value.fiber, janet_wrap_nil());
|
||||||
case JANET_EV_TCTAG_INTEGER:
|
break;
|
||||||
janet_schedule(return_value.fiber, janet_wrap_integer(return_value.argi));
|
case JANET_EV_TCTAG_INTEGER:
|
||||||
break;
|
janet_schedule(return_value.fiber, janet_wrap_integer(return_value.argi));
|
||||||
case JANET_EV_TCTAG_STRING:
|
break;
|
||||||
case JANET_EV_TCTAG_STRINGF:
|
case JANET_EV_TCTAG_STRING:
|
||||||
janet_schedule(return_value.fiber, janet_cstringv((const char *) return_value.argp));
|
case JANET_EV_TCTAG_STRINGF:
|
||||||
if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp);
|
janet_schedule(return_value.fiber, janet_cstringv((const char *) return_value.argp));
|
||||||
break;
|
if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp);
|
||||||
case JANET_EV_TCTAG_KEYWORD:
|
break;
|
||||||
janet_schedule(return_value.fiber, janet_ckeywordv((const char *) return_value.argp));
|
case JANET_EV_TCTAG_KEYWORD:
|
||||||
break;
|
janet_schedule(return_value.fiber, janet_ckeywordv((const char *) return_value.argp));
|
||||||
case JANET_EV_TCTAG_ERR_STRING:
|
break;
|
||||||
case JANET_EV_TCTAG_ERR_STRINGF:
|
case JANET_EV_TCTAG_ERR_STRING:
|
||||||
janet_cancel(return_value.fiber, janet_cstringv((const char *) return_value.argp));
|
case JANET_EV_TCTAG_ERR_STRINGF:
|
||||||
if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp);
|
janet_cancel(return_value.fiber, janet_cstringv((const char *) return_value.argp));
|
||||||
break;
|
if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp);
|
||||||
case JANET_EV_TCTAG_ERR_KEYWORD:
|
break;
|
||||||
janet_cancel(return_value.fiber, janet_ckeywordv((const char *) return_value.argp));
|
case JANET_EV_TCTAG_ERR_KEYWORD:
|
||||||
break;
|
janet_cancel(return_value.fiber, janet_ckeywordv((const char *) return_value.argp));
|
||||||
case JANET_EV_TCTAG_BOOLEAN:
|
break;
|
||||||
janet_schedule(return_value.fiber, janet_wrap_boolean(return_value.argi));
|
case JANET_EV_TCTAG_BOOLEAN:
|
||||||
break;
|
janet_schedule(return_value.fiber, janet_wrap_boolean(return_value.argi));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
janet_gcunroot(janet_wrap_fiber(return_value.fiber));
|
janet_gcunroot(janet_wrap_fiber(return_value.fiber));
|
||||||
}
|
}
|
||||||
@@ -2199,7 +2213,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case JANET_ASYNC_EVENT_USER: {
|
case JANET_ASYNC_EVENT_INIT: {
|
||||||
int32_t chunk_size = state->bytes_left > JANET_EV_CHUNKSIZE ? JANET_EV_CHUNKSIZE : state->bytes_left;
|
int32_t chunk_size = state->bytes_left > JANET_EV_CHUNKSIZE ? JANET_EV_CHUNKSIZE : state->bytes_left;
|
||||||
memset(&(state->overlapped), 0, sizeof(OVERLAPPED));
|
memset(&(state->overlapped), 0, sizeof(OVERLAPPED));
|
||||||
int status;
|
int status;
|
||||||
@@ -2237,7 +2251,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
janet_async_in_flight(fiber);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
@@ -2253,7 +2267,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
|
|
||||||
read_more:
|
read_more:
|
||||||
case JANET_ASYNC_EVENT_HUP:
|
case JANET_ASYNC_EVENT_HUP:
|
||||||
case JANET_ASYNC_EVENT_USER:
|
case JANET_ASYNC_EVENT_INIT:
|
||||||
case JANET_ASYNC_EVENT_READ: {
|
case JANET_ASYNC_EVENT_READ: {
|
||||||
JanetBuffer *buffer = state->buf;
|
JanetBuffer *buffer = state->buf;
|
||||||
int32_t bytes_left = state->bytes_left;
|
int32_t bytes_left = state->bytes_left;
|
||||||
@@ -2332,9 +2346,8 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int is_chunked, JanetReadMode mode, int flags) {
|
static JANET_NO_RETURN void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int is_chunked, JanetReadMode mode, int flags) {
|
||||||
JanetFiber *f = janet_vm.root_fiber;
|
StateRead *state = janet_malloc(sizeof(StateRead));
|
||||||
StateRead *state = (StateRead *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, ev_callback_read, sizeof(StateRead));
|
|
||||||
state->is_chunk = is_chunked;
|
state->is_chunk = is_chunked;
|
||||||
state->buf = buf;
|
state->buf = buf;
|
||||||
state->bytes_left = nbytes;
|
state->bytes_left = nbytes;
|
||||||
@@ -2345,23 +2358,23 @@ static void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t
|
|||||||
#else
|
#else
|
||||||
state->flags = flags;
|
state->flags = flags;
|
||||||
#endif
|
#endif
|
||||||
ev_callback_read(f, JANET_ASYNC_EVENT_USER);
|
janet_async_start(stream, JANET_ASYNC_LISTEN_READ, ev_callback_read, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
|
JANET_NO_RETURN void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
|
||||||
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_READ, 0);
|
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_READ, 0);
|
||||||
}
|
}
|
||||||
void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
|
JANET_NO_RETURN void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
|
||||||
janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_READ, 0);
|
janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_READ, 0);
|
||||||
}
|
}
|
||||||
#ifdef JANET_NET
|
#ifdef JANET_NET
|
||||||
void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
JANET_NO_RETURN void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
||||||
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECV, flags);
|
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECV, flags);
|
||||||
}
|
}
|
||||||
void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
JANET_NO_RETURN void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
||||||
janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_RECV, flags);
|
janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_RECV, flags);
|
||||||
}
|
}
|
||||||
void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
JANET_NO_RETURN void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
|
||||||
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECVFROM, flags);
|
janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECVFROM, flags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2431,7 +2444,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JANET_ASYNC_EVENT_USER: {
|
case JANET_ASYNC_EVENT_INIT: {
|
||||||
/* Begin write */
|
/* Begin write */
|
||||||
int32_t len;
|
int32_t len;
|
||||||
const uint8_t *bytes;
|
const uint8_t *bytes;
|
||||||
@@ -2461,7 +2474,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
status = WSASendTo(sock, &state->wbuf, 1, NULL, state->flags, to, tolen, &state->overlapped, NULL);
|
status = WSASendTo(sock, &state->wbuf, 1, NULL, state->flags, to, tolen, &state->overlapped, NULL);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (WSA_IO_PENDING == WSAGetLastError()) {
|
if (WSA_IO_PENDING == WSAGetLastError()) {
|
||||||
fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
janet_async_in_flight(fiber);
|
||||||
} else {
|
} else {
|
||||||
janet_cancel(fiber, janet_ev_lasterr());
|
janet_cancel(fiber, janet_ev_lasterr());
|
||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
@@ -2486,7 +2499,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
status = WriteFile(stream->handle, bytes, len, NULL, &state->overlapped);
|
status = WriteFile(stream->handle, bytes, len, NULL, &state->overlapped);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
if (ERROR_IO_PENDING == GetLastError()) {
|
if (ERROR_IO_PENDING == GetLastError()) {
|
||||||
fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
janet_async_in_flight(fiber);
|
||||||
} else {
|
} else {
|
||||||
janet_cancel(fiber, janet_ev_lasterr());
|
janet_cancel(fiber, janet_ev_lasterr());
|
||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
@@ -2505,7 +2518,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
janet_cancel(fiber, janet_cstringv("stream hup"));
|
janet_cancel(fiber, janet_cstringv("stream hup"));
|
||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
break;
|
break;
|
||||||
case JANET_ASYNC_EVENT_USER:
|
case JANET_ASYNC_EVENT_INIT:
|
||||||
case JANET_ASYNC_EVENT_WRITE: {
|
case JANET_ASYNC_EVENT_WRITE: {
|
||||||
int32_t start, len;
|
int32_t start, len;
|
||||||
const uint8_t *bytes;
|
const uint8_t *bytes;
|
||||||
@@ -2570,10 +2583,8 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_abst, JanetWriteMode mode, int is_buffer, int flags) {
|
static JANET_NO_RETURN void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_abst, JanetWriteMode mode, int is_buffer, int flags) {
|
||||||
JanetFiber *f = janet_vm.root_fiber;
|
StateWrite *state = janet_malloc(sizeof(StateWrite));
|
||||||
StateWrite *state = (StateWrite *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE,
|
|
||||||
ev_callback_write, sizeof(StateWrite));
|
|
||||||
state->is_buffer = is_buffer;
|
state->is_buffer = is_buffer;
|
||||||
state->src.buf = buf;
|
state->src.buf = buf;
|
||||||
state->dest_abst = dest_abst;
|
state->dest_abst = dest_abst;
|
||||||
@@ -2584,31 +2595,31 @@ static void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_ab
|
|||||||
state->flags = flags;
|
state->flags = flags;
|
||||||
state->start = 0;
|
state->start = 0;
|
||||||
#endif
|
#endif
|
||||||
ev_callback_write(f, JANET_ASYNC_EVENT_USER);
|
janet_async_start(stream, JANET_ASYNC_LISTEN_WRITE, ev_callback_write, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf) {
|
JANET_NO_RETURN void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf) {
|
||||||
janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_WRITE, 1, 0);
|
janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_WRITE, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_write_string(JanetStream *stream, JanetString str) {
|
JANET_NO_RETURN void janet_ev_write_string(JanetStream *stream, JanetString str) {
|
||||||
janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_WRITE, 0, 0);
|
janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_WRITE, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JANET_NET
|
#ifdef JANET_NET
|
||||||
void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags) {
|
JANET_NO_RETURN void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags) {
|
||||||
janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_SEND, 1, flags);
|
janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_SEND, 1, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_send_string(JanetStream *stream, JanetString str, int flags) {
|
JANET_NO_RETURN void janet_ev_send_string(JanetStream *stream, JanetString str, int flags) {
|
||||||
janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_SEND, 0, flags);
|
janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_SEND, 0, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags) {
|
JANET_NO_RETURN void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags) {
|
||||||
janet_ev_write_generic(stream, buf, dest, JANET_ASYNC_WRITEMODE_SENDTO, 1, flags);
|
janet_ev_write_generic(stream, buf, dest, JANET_ASYNC_WRITEMODE_SENDTO, 1, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags) {
|
JANET_NO_RETURN void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags) {
|
||||||
janet_ev_write_generic(stream, (void *) str, dest, JANET_ASYNC_WRITEMODE_SENDTO, 0, flags);
|
janet_ev_write_generic(stream, (void *) str, dest, JANET_ASYNC_WRITEMODE_SENDTO, 0, flags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2941,10 +2952,15 @@ JANET_CORE_FN(cfun_ev_sleep,
|
|||||||
|
|
||||||
JANET_CORE_FN(cfun_ev_deadline,
|
JANET_CORE_FN(cfun_ev_deadline,
|
||||||
"(ev/deadline sec &opt tocancel tocheck)",
|
"(ev/deadline sec &opt tocancel tocheck)",
|
||||||
"Set a deadline for a fiber `tocheck`. If `tocheck` is not finished after `sec` seconds, "
|
"Schedules the event loop to try to cancel the `tocancel` "
|
||||||
"`tocancel` will be canceled as with `ev/cancel`. "
|
"task as with `ev/cancel`. After `sec` seconds, the event "
|
||||||
"If `tocancel` and `tocheck` are not given, they default to `(fiber/root)` and "
|
"loop will attempt cancellation of `tocancel` if the "
|
||||||
"`(fiber/current)` respectively. Returns `tocancel`.") {
|
"`tocheck` fiber is resumable. `sec` is a number that can "
|
||||||
|
"have a fractional part. `tocancel` defaults to "
|
||||||
|
"`(fiber/root)`, but if specified, must be a task (root "
|
||||||
|
"fiber). `tocheck` defaults to `(fiber/current)`, but if "
|
||||||
|
"specified, should be a fiber. Returns `tocancel` "
|
||||||
|
"immediately.") {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
double sec = janet_getnumber(argv, 0);
|
double sec = janet_getnumber(argv, 0);
|
||||||
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber);
|
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber);
|
||||||
@@ -2999,7 +3015,6 @@ JANET_CORE_FN(janet_cfun_stream_read,
|
|||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_read(stream, buffer, n);
|
janet_ev_read(stream, buffer, n);
|
||||||
}
|
}
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(janet_cfun_stream_chunk,
|
JANET_CORE_FN(janet_cfun_stream_chunk,
|
||||||
@@ -3014,7 +3029,6 @@ JANET_CORE_FN(janet_cfun_stream_chunk,
|
|||||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_readchunk(stream, buffer, n);
|
janet_ev_readchunk(stream, buffer, n);
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(janet_cfun_stream_write,
|
JANET_CORE_FN(janet_cfun_stream_write,
|
||||||
@@ -3034,7 +3048,6 @@ JANET_CORE_FN(janet_cfun_stream_write,
|
|||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_write_string(stream, bytes.bytes);
|
janet_ev_write_string(stream, bytes.bytes);
|
||||||
}
|
}
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mutexgc(void *p, size_t size) {
|
static int mutexgc(void *p, size_t size) {
|
||||||
|
|||||||
@@ -239,8 +239,8 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
|||||||
fiber->data + tuplehead,
|
fiber->data + tuplehead,
|
||||||
oldtop - tuplehead)
|
oldtop - tuplehead)
|
||||||
: janet_wrap_tuple(janet_tuple_n(
|
: janet_wrap_tuple(janet_tuple_n(
|
||||||
fiber->data + tuplehead,
|
fiber->data + tuplehead,
|
||||||
oldtop - tuplehead));
|
oldtop - tuplehead));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,8 +370,8 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
|||||||
fiber->data + tuplehead,
|
fiber->data + tuplehead,
|
||||||
fiber->stacktop - tuplehead)
|
fiber->stacktop - tuplehead)
|
||||||
: janet_wrap_tuple(janet_tuple_n(
|
: janet_wrap_tuple(janet_tuple_n(
|
||||||
fiber->data + tuplehead,
|
fiber->data + tuplehead,
|
||||||
fiber->stacktop - tuplehead));
|
fiber->stacktop - tuplehead));
|
||||||
}
|
}
|
||||||
stacksize = tuplehead - fiber->stackstart + 1;
|
stacksize = tuplehead - fiber->stackstart + 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -662,7 +662,7 @@ JANET_CORE_FN(cfun_fiber_can_resume,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_fiber_last_value,
|
JANET_CORE_FN(cfun_fiber_last_value,
|
||||||
"(fiber/last-value)",
|
"(fiber/last-value fiber)",
|
||||||
"Get the last value returned or signaled from the fiber.") {
|
"Get the last value returned or signaled from the fiber.") {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||||
|
|||||||
@@ -185,6 +185,19 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags);
|
|||||||
/* Prevent stack overflows */
|
/* Prevent stack overflows */
|
||||||
#define MARSH_STACKCHECK if ((flags & 0xFFFF) > JANET_RECURSION_GUARD) janet_panic("stack overflow")
|
#define MARSH_STACKCHECK if ((flags & 0xFFFF) > JANET_RECURSION_GUARD) janet_panic("stack overflow")
|
||||||
|
|
||||||
|
/* Quick check if a fiber cannot be marshalled. This is will
|
||||||
|
* have no false positives, but may have false negatives. */
|
||||||
|
static int fiber_cannot_be_marshalled(JanetFiber *fiber) {
|
||||||
|
if (janet_fiber_status(fiber) == JANET_STATUS_ALIVE) return 1;
|
||||||
|
int32_t i = fiber->frame;
|
||||||
|
while (i > 0) {
|
||||||
|
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||||
|
if (!frame->func) return 1; /* has cfunction on stack */
|
||||||
|
i = frame->prevframe;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Marshal a function env */
|
/* Marshal a function env */
|
||||||
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
||||||
MARSH_STACKCHECK;
|
MARSH_STACKCHECK;
|
||||||
@@ -197,7 +210,9 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
|||||||
}
|
}
|
||||||
janet_env_valid(env);
|
janet_env_valid(env);
|
||||||
janet_v_push(st->seen_envs, env);
|
janet_v_push(st->seen_envs, env);
|
||||||
if (env->offset > 0 && (JANET_STATUS_ALIVE == janet_fiber_status(env->as.fiber))) {
|
|
||||||
|
/* Special case for early detachment */
|
||||||
|
if (env->offset > 0 && fiber_cannot_be_marshalled(env->as.fiber)) {
|
||||||
pushint(st, 0);
|
pushint(st, 0);
|
||||||
pushint(st, env->length);
|
pushint(st, env->length);
|
||||||
Janet *values = env->as.fiber->data + env->offset;
|
Janet *values = env->as.fiber->data + env->offset;
|
||||||
@@ -328,7 +343,7 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
|
|||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||||
if (frame->env) frame->flags |= JANET_STACKFRAME_HASENV;
|
if (frame->env) frame->flags |= JANET_STACKFRAME_HASENV;
|
||||||
if (!frame->func) janet_panic("cannot marshal fiber with c stackframe");
|
if (!frame->func) janet_panicf("cannot marshal fiber with c stackframe (%v)", janet_wrap_cfunction((JanetCFunction) frame->pc));
|
||||||
pushint(st, frame->flags);
|
pushint(st, frame->flags);
|
||||||
pushint(st, frame->prevframe);
|
pushint(st, frame->prevframe);
|
||||||
int32_t pcdiff = (int32_t)(frame->pc - frame->func->def->bytecode);
|
int32_t pcdiff = (int32_t)(frame->pc - frame->func->def->bytecode);
|
||||||
|
|||||||
@@ -79,12 +79,20 @@ const JanetAbstractType janet_address_type = {
|
|||||||
|
|
||||||
/* maximum number of bytes in a socket address host (post name resolution) */
|
/* maximum number of bytes in a socket address host (post name resolution) */
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
|
#ifdef JANET_NO_IPV6
|
||||||
|
#define SA_ADDRSTRLEN (INET_ADDRSTRLEN + 1)
|
||||||
|
#else
|
||||||
#define SA_ADDRSTRLEN (INET6_ADDRSTRLEN + 1)
|
#define SA_ADDRSTRLEN (INET6_ADDRSTRLEN + 1)
|
||||||
|
#endif
|
||||||
typedef unsigned short in_port_t;
|
typedef unsigned short in_port_t;
|
||||||
#else
|
#else
|
||||||
#define JANET_SA_MAX(a, b) (((a) > (b))? (a) : (b))
|
#define JANET_SA_MAX(a, b) (((a) > (b))? (a) : (b))
|
||||||
|
#ifdef JANET_NO_IPV6
|
||||||
|
#define SA_ADDRSTRLEN JANET_SA_MAX(INET_ADDRSTRLEN + 1, (sizeof ((struct sockaddr_un *)0)->sun_path) + 1)
|
||||||
|
#else
|
||||||
#define SA_ADDRSTRLEN JANET_SA_MAX(INET6_ADDRSTRLEN + 1, (sizeof ((struct sockaddr_un *)0)->sun_path) + 1)
|
#define SA_ADDRSTRLEN JANET_SA_MAX(INET6_ADDRSTRLEN + 1, (sizeof ((struct sockaddr_un *)0)->sun_path) + 1)
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static JanetStream *make_stream(JSock handle, uint32_t flags);
|
static JanetStream *make_stream(JSock handle, uint32_t flags);
|
||||||
|
|
||||||
@@ -114,16 +122,18 @@ static void janet_net_socknoblock(JSock s) {
|
|||||||
|
|
||||||
/* State machine for async connect */
|
/* State machine for async connect */
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int did_connect;
|
|
||||||
} NetStateConnect;
|
|
||||||
|
|
||||||
void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
|
void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
|
||||||
JanetStream *stream = fiber->ev_stream;
|
JanetStream *stream = fiber->ev_stream;
|
||||||
NetStateConnect *state = (NetStateConnect *)fiber->ev_state;
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
#ifndef JANET_WINDOWS
|
||||||
|
/* Wait until we have an actual event before checking.
|
||||||
|
* Windows doesn't support async connect with this, just try immediately.*/
|
||||||
|
case JANET_ASYNC_EVENT_INIT:
|
||||||
|
#endif
|
||||||
|
case JANET_ASYNC_EVENT_DEINIT:
|
||||||
|
return;
|
||||||
case JANET_ASYNC_EVENT_CLOSE:
|
case JANET_ASYNC_EVENT_CLOSE:
|
||||||
janet_cancel(fiber, janet_cstringv("stream closed"));
|
janet_cancel(fiber, janet_cstringv("stream closed"));
|
||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
@@ -140,7 +150,6 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
#endif
|
#endif
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
state->did_connect = 1;
|
|
||||||
janet_schedule(fiber, janet_wrap_abstract(stream));
|
janet_schedule(fiber, janet_wrap_abstract(stream));
|
||||||
} else {
|
} else {
|
||||||
janet_cancel(fiber, janet_cstringv(strerror(res)));
|
janet_cancel(fiber, janet_cstringv(strerror(res)));
|
||||||
@@ -153,13 +162,8 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_sched_connect(JanetStream *stream) {
|
static JANET_NO_RETURN void net_sched_connect(JanetStream *stream) {
|
||||||
JanetFiber *f = janet_vm.root_fiber;
|
janet_async_start(stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, NULL);
|
||||||
NetStateConnect *state = (NetStateConnect *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, sizeof(NetStateConnect));
|
|
||||||
state->did_connect = 0;
|
|
||||||
#ifdef JANET_WINDOWS
|
|
||||||
net_callback_connect(f, JANET_ASYNC_EVENT_USER);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* State machine for accepting connections. */
|
/* State machine for accepting connections. */
|
||||||
@@ -229,14 +233,16 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
|
|
||||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
||||||
Janet err;
|
Janet err;
|
||||||
JanetFiber *f = janet_vm.root_fiber;
|
NetStateAccept *state = janet_malloc(sizeof(NetStateAccept));
|
||||||
NetStateAccept *state = (NetStateAccept *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, sizeof(NetStateAccept));
|
|
||||||
memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED));
|
memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED));
|
||||||
memset(&state->buf, 0, 1024);
|
memset(&state->buf, 0, 1024);
|
||||||
state->function = fun;
|
state->function = fun;
|
||||||
state->lstream = stream;
|
state->lstream = stream;
|
||||||
if (net_sched_accept_impl(state, f, &err)) janet_panicv(err);
|
if (net_sched_accept_impl(state, janet_root_fiber(), &err)) {
|
||||||
janet_await();
|
janet_free(state);
|
||||||
|
janet_panicv(err);
|
||||||
|
}
|
||||||
|
janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err) {
|
static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err) {
|
||||||
@@ -253,7 +259,7 @@ static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet
|
|||||||
int code = WSAGetLastError();
|
int code = WSAGetLastError();
|
||||||
if (code == WSA_IO_PENDING) {
|
if (code == WSA_IO_PENDING) {
|
||||||
/* indicates io is happening async */
|
/* indicates io is happening async */
|
||||||
fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
|
janet_async_in_flight(fiber);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*err = janet_ev_lasterr();
|
*err = janet_ev_lasterr();
|
||||||
@@ -282,7 +288,7 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
janet_schedule(fiber, janet_wrap_nil());
|
janet_schedule(fiber, janet_wrap_nil());
|
||||||
janet_async_end(fiber);
|
janet_async_end(fiber);
|
||||||
return;
|
return;
|
||||||
case JANET_ASYNC_EVENT_USER:
|
case JANET_ASYNC_EVENT_INIT:
|
||||||
case JANET_ASYNC_EVENT_READ: {
|
case JANET_ASYNC_EVENT_READ: {
|
||||||
#if defined(JANET_LINUX)
|
#if defined(JANET_LINUX)
|
||||||
JSock connfd = accept4(stream->handle, NULL, NULL, SOCK_CLOEXEC);
|
JSock connfd = accept4(stream->handle, NULL, NULL, SOCK_CLOEXEC);
|
||||||
@@ -310,11 +316,10 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
|
||||||
JanetFiber *f = janet_vm.root_fiber;
|
NetStateAccept *state = janet_malloc(sizeof(NetStateAccept));
|
||||||
NetStateAccept *state = (NetStateAccept *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, sizeof(NetStateAccept));
|
memset(state, 0, sizeof(NetStateAccept));
|
||||||
state->function = fun;
|
state->function = fun;
|
||||||
net_callback_accept(f, JANET_ASYNC_EVENT_USER);
|
janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state);
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -570,7 +575,6 @@ JANET_CORE_FN(cfun_net_connect,
|
|||||||
}
|
}
|
||||||
|
|
||||||
net_sched_connect(stream);
|
net_sched_connect(stream);
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *serverify_socket(JSock sfd) {
|
static const char *serverify_socket(JSock sfd) {
|
||||||
@@ -741,6 +745,7 @@ static Janet janet_so_getname(const void *sa_any) {
|
|||||||
Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai->sin_port))};
|
Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai->sin_port))};
|
||||||
return janet_wrap_tuple(janet_tuple_n(pair, 2));
|
return janet_wrap_tuple(janet_tuple_n(pair, 2));
|
||||||
}
|
}
|
||||||
|
#ifndef JANET_NO_IPV6
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
const struct sockaddr_in6 *sai6 = sa_any;
|
const struct sockaddr_in6 *sai6 = sa_any;
|
||||||
if (!inet_ntop(AF_INET6, &(sai6->sin6_addr), buffer, sizeof(buffer))) {
|
if (!inet_ntop(AF_INET6, &(sai6->sin6_addr), buffer, sizeof(buffer))) {
|
||||||
@@ -749,6 +754,7 @@ static Janet janet_so_getname(const void *sa_any) {
|
|||||||
Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai6->sin6_port))};
|
Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai6->sin6_port))};
|
||||||
return janet_wrap_tuple(janet_tuple_n(pair, 2));
|
return janet_wrap_tuple(janet_tuple_n(pair, 2));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#ifndef JANET_WINDOWS
|
#ifndef JANET_WINDOWS
|
||||||
case AF_UNIX: {
|
case AF_UNIX: {
|
||||||
const struct sockaddr_un *sun = sa_any;
|
const struct sockaddr_un *sun = sa_any;
|
||||||
@@ -815,6 +821,7 @@ JANET_CORE_FN(cfun_stream_accept_loop,
|
|||||||
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
|
||||||
janet_stream_flags(stream, JANET_STREAM_ACCEPTABLE | JANET_STREAM_SOCKET);
|
janet_stream_flags(stream, JANET_STREAM_ACCEPTABLE | JANET_STREAM_SOCKET);
|
||||||
JanetFunction *fun = janet_getfunction(argv, 1);
|
JanetFunction *fun = janet_getfunction(argv, 1);
|
||||||
|
if (fun->def->min_arity < 1) janet_panic("handler function must take at least 1 argument");
|
||||||
janet_sched_accept(stream, fun);
|
janet_sched_accept(stream, fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,7 +858,6 @@ JANET_CORE_FN(cfun_stream_read,
|
|||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_recv(stream, buffer, n, MSG_NOSIGNAL);
|
janet_ev_recv(stream, buffer, n, MSG_NOSIGNAL);
|
||||||
}
|
}
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_stream_chunk,
|
JANET_CORE_FN(cfun_stream_chunk,
|
||||||
@@ -866,7 +872,6 @@ JANET_CORE_FN(cfun_stream_chunk,
|
|||||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_recvchunk(stream, buffer, n, MSG_NOSIGNAL);
|
janet_ev_recvchunk(stream, buffer, n, MSG_NOSIGNAL);
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_stream_recv_from,
|
JANET_CORE_FN(cfun_stream_recv_from,
|
||||||
@@ -881,7 +886,6 @@ JANET_CORE_FN(cfun_stream_recv_from,
|
|||||||
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
double to = janet_optnumber(argv, argc, 3, INFINITY);
|
||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_recvfrom(stream, buffer, n, MSG_NOSIGNAL);
|
janet_ev_recvfrom(stream, buffer, n, MSG_NOSIGNAL);
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_stream_write,
|
JANET_CORE_FN(cfun_stream_write,
|
||||||
@@ -901,7 +905,6 @@ JANET_CORE_FN(cfun_stream_write,
|
|||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_send_string(stream, bytes.bytes, MSG_NOSIGNAL);
|
janet_ev_send_string(stream, bytes.bytes, MSG_NOSIGNAL);
|
||||||
}
|
}
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_stream_send_to,
|
JANET_CORE_FN(cfun_stream_send_to,
|
||||||
@@ -922,7 +925,6 @@ JANET_CORE_FN(cfun_stream_send_to,
|
|||||||
if (to != INFINITY) janet_addtimeout(to);
|
if (to != INFINITY) janet_addtimeout(to);
|
||||||
janet_ev_sendto_string(stream, bytes.bytes, dest, MSG_NOSIGNAL);
|
janet_ev_sendto_string(stream, bytes.bytes, dest, MSG_NOSIGNAL);
|
||||||
}
|
}
|
||||||
janet_await();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_stream_flush,
|
JANET_CORE_FN(cfun_stream_flush,
|
||||||
@@ -956,8 +958,10 @@ static const struct sockopt_type sockopt_type_list[] = {
|
|||||||
{ "ip-multicast-ttl", IPPROTO_IP, IP_MULTICAST_TTL, JANET_NUMBER },
|
{ "ip-multicast-ttl", IPPROTO_IP, IP_MULTICAST_TTL, JANET_NUMBER },
|
||||||
{ "ip-add-membership", IPPROTO_IP, IP_ADD_MEMBERSHIP, JANET_POINTER },
|
{ "ip-add-membership", IPPROTO_IP, IP_ADD_MEMBERSHIP, JANET_POINTER },
|
||||||
{ "ip-drop-membership", IPPROTO_IP, IP_DROP_MEMBERSHIP, JANET_POINTER },
|
{ "ip-drop-membership", IPPROTO_IP, IP_DROP_MEMBERSHIP, JANET_POINTER },
|
||||||
|
#ifndef JANET_NO_IPV6
|
||||||
{ "ipv6-join-group", IPPROTO_IPV6, IPV6_JOIN_GROUP, JANET_POINTER },
|
{ "ipv6-join-group", IPPROTO_IPV6, IPV6_JOIN_GROUP, JANET_POINTER },
|
||||||
{ "ipv6-leave-group", IPPROTO_IPV6, IPV6_LEAVE_GROUP, JANET_POINTER },
|
{ "ipv6-leave-group", IPPROTO_IPV6, IPV6_LEAVE_GROUP, JANET_POINTER },
|
||||||
|
#endif
|
||||||
{ NULL, 0, 0, JANET_POINTER }
|
{ NULL, 0, 0, JANET_POINTER }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -994,7 +998,9 @@ JANET_CORE_FN(cfun_net_setsockopt,
|
|||||||
union {
|
union {
|
||||||
int v_int;
|
int v_int;
|
||||||
struct ip_mreq v_mreq;
|
struct ip_mreq v_mreq;
|
||||||
|
#ifndef JANET_NO_IPV6
|
||||||
struct ipv6_mreq v_mreq6;
|
struct ipv6_mreq v_mreq6;
|
||||||
|
#endif
|
||||||
} val;
|
} val;
|
||||||
|
|
||||||
void *optval = (void *)&val;
|
void *optval = (void *)&val;
|
||||||
@@ -1012,12 +1018,14 @@ JANET_CORE_FN(cfun_net_setsockopt,
|
|||||||
val.v_mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
val.v_mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
inet_pton(AF_INET, addr, &val.v_mreq.imr_multiaddr.s_addr);
|
inet_pton(AF_INET, addr, &val.v_mreq.imr_multiaddr.s_addr);
|
||||||
optlen = sizeof(val.v_mreq);
|
optlen = sizeof(val.v_mreq);
|
||||||
|
#ifndef JANET_NO_IPV6
|
||||||
} else if (st->optname == IPV6_JOIN_GROUP || st->optname == IPV6_LEAVE_GROUP) {
|
} else if (st->optname == IPV6_JOIN_GROUP || st->optname == IPV6_LEAVE_GROUP) {
|
||||||
const char *addr = janet_getcstring(argv, 2);
|
const char *addr = janet_getcstring(argv, 2);
|
||||||
memset(&val.v_mreq6, 0, sizeof val.v_mreq6);
|
memset(&val.v_mreq6, 0, sizeof val.v_mreq6);
|
||||||
val.v_mreq6.ipv6mr_interface = 0;
|
val.v_mreq6.ipv6mr_interface = 0;
|
||||||
inet_pton(AF_INET6, addr, &val.v_mreq6.ipv6mr_multiaddr);
|
inet_pton(AF_INET6, addr, &val.v_mreq6.ipv6mr_multiaddr);
|
||||||
optlen = sizeof(val.v_mreq6);
|
optlen = sizeof(val.v_mreq6);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
janet_panicf("invalid socket option type");
|
janet_panicf("invalid socket option type");
|
||||||
}
|
}
|
||||||
|
|||||||
227
src/core/os.c
227
src/core/os.c
@@ -229,10 +229,11 @@ JANET_CORE_FN(os_compiler,
|
|||||||
#undef janet_stringify
|
#undef janet_stringify
|
||||||
|
|
||||||
JANET_CORE_FN(os_exit,
|
JANET_CORE_FN(os_exit,
|
||||||
"(os/exit &opt x)",
|
"(os/exit &opt x force)",
|
||||||
"Exit from janet with an exit code equal to x. If x is not an integer, "
|
"Exit from janet with an exit code equal to x. If x is not an integer, "
|
||||||
"the exit with status equal the hash of x.") {
|
"the exit with status equal the hash of x. If `force` is truthy will exit immediately and "
|
||||||
janet_arity(argc, 0, 1);
|
"skip cleanup code.") {
|
||||||
|
janet_arity(argc, 0, 2);
|
||||||
int status;
|
int status;
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
status = EXIT_SUCCESS;
|
status = EXIT_SUCCESS;
|
||||||
@@ -242,7 +243,11 @@ JANET_CORE_FN(os_exit,
|
|||||||
status = EXIT_FAILURE;
|
status = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
janet_deinit();
|
janet_deinit();
|
||||||
exit(status);
|
if (argc >= 2 && janet_truthy(argv[1])) {
|
||||||
|
_exit(status);
|
||||||
|
} else {
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,8 +505,11 @@ static int proc_get_status(JanetProc *proc) {
|
|||||||
status = WEXITSTATUS(status);
|
status = WEXITSTATUS(status);
|
||||||
} else if (WIFSTOPPED(status)) {
|
} else if (WIFSTOPPED(status)) {
|
||||||
status = WSTOPSIG(status) + 128;
|
status = WSTOPSIG(status) + 128;
|
||||||
} else {
|
} else if (WIFSIGNALED(status)) {
|
||||||
status = WTERMSIG(status) + 128;
|
status = WTERMSIG(status) + 128;
|
||||||
|
} else {
|
||||||
|
/* Could possibly return -1 but for now, just panic */
|
||||||
|
janet_panicf("Undefined status code for process termination, %d.", status);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -529,7 +537,9 @@ static void janet_proc_wait_cb(JanetEVGenericMessage args) {
|
|||||||
JanetString s = janet_formatc("command failed with non-zero exit code %d", status);
|
JanetString s = janet_formatc("command failed with non-zero exit code %d", status);
|
||||||
janet_cancel(args.fiber, janet_wrap_string(s));
|
janet_cancel(args.fiber, janet_wrap_string(s));
|
||||||
} else {
|
} else {
|
||||||
janet_schedule(args.fiber, janet_wrap_integer(status));
|
if (janet_fiber_can_resume(args.fiber)) {
|
||||||
|
janet_schedule(args.fiber, janet_wrap_integer(status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,7 +621,11 @@ os_proc_wait_impl(JanetProc *proc) {
|
|||||||
|
|
||||||
JANET_CORE_FN(os_proc_wait,
|
JANET_CORE_FN(os_proc_wait,
|
||||||
"(os/proc-wait proc)",
|
"(os/proc-wait proc)",
|
||||||
"Block until the subprocess completes. Returns the subprocess return code.") {
|
"Suspend the current fiber until the subprocess completes. Returns the subprocess return code. "
|
||||||
|
"os/proc-wait cannot be called twice on the same process. If `ev/with-deadline` cancels `os/proc-wait` "
|
||||||
|
"with an error or os/proc-wait is cancelled with any error caused by anything else, os/proc-wait still "
|
||||||
|
"finishes in the background. Only after os/proc-wait finishes, a process is cleaned up by the operating "
|
||||||
|
"system. Thus, a process becomes a zombie process if os/proc-wait is not called.") {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
@@ -640,7 +654,7 @@ static const struct keyword_signal signal_keywords[] = {
|
|||||||
#ifdef SIGTERM
|
#ifdef SIGTERM
|
||||||
{"term", SIGTERM},
|
{"term", SIGTERM},
|
||||||
#endif
|
#endif
|
||||||
#ifdef SIGARLM
|
#ifdef SIGALRM
|
||||||
{"alrm", SIGALRM},
|
{"alrm", SIGALRM},
|
||||||
#endif
|
#endif
|
||||||
#ifdef SIGHUP
|
#ifdef SIGHUP
|
||||||
@@ -722,10 +736,11 @@ static int get_signal_kw(const Janet *argv, int32_t n) {
|
|||||||
JANET_CORE_FN(os_proc_kill,
|
JANET_CORE_FN(os_proc_kill,
|
||||||
"(os/proc-kill proc &opt wait signal)",
|
"(os/proc-kill proc &opt wait signal)",
|
||||||
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
|
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
|
||||||
"handle on windows. If `wait` is truthy, will wait for the process to finish and "
|
"handle on windows. If os/proc-wait already finished for proc, os/proc-kill raises an error. After "
|
||||||
"returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead."
|
"sending signal to proc, if `wait` is truthy, will wait for the process to finish and return the exit "
|
||||||
"Signal keywords are named after their C counterparts but in lowercase with the leading "
|
"code by calling os/proc-wait. Otherwise, returns `proc`. If signal is specified, send it instead. "
|
||||||
"`SIG` stripped. Signals are ignored on windows.") {
|
"Signal keywords are named after their C counterparts but in lowercase with the leading `SIG` stripped. "
|
||||||
|
"Signals are ignored on windows.") {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||||
if (proc->flags & JANET_PROC_WAITED) {
|
if (proc->flags & JANET_PROC_WAITED) {
|
||||||
@@ -764,8 +779,9 @@ JANET_CORE_FN(os_proc_kill,
|
|||||||
|
|
||||||
JANET_CORE_FN(os_proc_close,
|
JANET_CORE_FN(os_proc_close,
|
||||||
"(os/proc-close proc)",
|
"(os/proc-close proc)",
|
||||||
"Wait on a process if it has not been waited on, and close pipes created by `os/spawn` "
|
"Close pipes created by `os/spawn` if they have not been closed. Then, if os/proc-wait was not already "
|
||||||
"if they have not been closed. Returns nil.") {
|
"called on proc, os/proc-wait is called on it, and it returns the exit code returned by os/proc-wait. "
|
||||||
|
"Otherwise, returns nil.") {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
@@ -875,8 +891,9 @@ JANET_CORE_FN(os_sigaction,
|
|||||||
}
|
}
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigfillset(&mask);
|
sigaddset(&mask, sig);
|
||||||
memset(&action, 0, sizeof(action));
|
memset(&action, 0, sizeof(action));
|
||||||
|
action.sa_flags |= SA_RESTART;
|
||||||
if (can_interrupt) {
|
if (can_interrupt) {
|
||||||
#ifdef JANET_NO_INTERPRETER_INTERRUPT
|
#ifdef JANET_NO_INTERPRETER_INTERRUPT
|
||||||
janet_panic("interpreter interrupt not enabled");
|
janet_panic("interpreter interrupt not enabled");
|
||||||
@@ -1081,11 +1098,18 @@ static JanetFile *get_stdio_for_handle(JanetHandle handle, void *orig, int iswri
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
|
typedef enum {
|
||||||
|
JANET_EXECUTE_EXECUTE,
|
||||||
|
JANET_EXECUTE_SPAWN,
|
||||||
|
JANET_EXECUTE_EXEC
|
||||||
|
} JanetExecuteMode;
|
||||||
|
|
||||||
|
static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||||
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
|
|
||||||
/* Get flags */
|
/* Get flags */
|
||||||
|
int is_spawn = mode == JANET_EXECUTE_SPAWN;
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
flags = janet_getflags(argv, 1, "epxd");
|
flags = janet_getflags(argv, 1, "epxd");
|
||||||
@@ -1109,7 +1133,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
|
|||||||
int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0;
|
int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0;
|
||||||
|
|
||||||
/* Get optional redirections */
|
/* Get optional redirections */
|
||||||
if (argc > 2) {
|
if (argc > 2 && (mode != JANET_EXECUTE_EXEC)) {
|
||||||
JanetDictView tab = janet_getdictionary(argv, 2);
|
JanetDictView tab = janet_getdictionary(argv, 2);
|
||||||
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
|
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
|
||||||
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
|
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
|
||||||
@@ -1230,12 +1254,32 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
|
|||||||
* of posix_spawn would modify the argv array passed in. */
|
* of posix_spawn would modify the argv array passed in. */
|
||||||
char *const *cargv = (char *const *)child_argv;
|
char *const *cargv = (char *const *)child_argv;
|
||||||
|
|
||||||
/* Use posix_spawn to spawn new process */
|
|
||||||
|
|
||||||
if (use_environ) {
|
if (use_environ) {
|
||||||
janet_lock_environ();
|
janet_lock_environ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* exec mode */
|
||||||
|
if (mode == JANET_EXECUTE_EXEC) {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
janet_panic("not supported on windows");
|
||||||
|
#else
|
||||||
|
int status;
|
||||||
|
if (!use_environ) {
|
||||||
|
environ = envp;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if (janet_flag_at(flags, 1)) {
|
||||||
|
status = execvp(cargv[0], cargv);
|
||||||
|
} else {
|
||||||
|
status = execv(cargv[0], cargv);
|
||||||
|
}
|
||||||
|
} while (status == -1 && errno == EINTR);
|
||||||
|
janet_panicf("%p: %s", cargv[0], strerror(errno ? errno : ENOENT));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use posix_spawn to spawn new process */
|
||||||
|
|
||||||
/* Posix spawn setup */
|
/* Posix spawn setup */
|
||||||
posix_spawn_file_actions_t actions;
|
posix_spawn_file_actions_t actions;
|
||||||
posix_spawn_file_actions_init(&actions);
|
posix_spawn_file_actions_init(&actions);
|
||||||
@@ -1342,22 +1386,63 @@ JANET_CORE_FN(os_execute,
|
|||||||
"* :d - Don't try and terminate the process on garbage collection (allow spawning zombies).\n"
|
"* :d - Don't try and terminate the process on garbage collection (allow spawning zombies).\n"
|
||||||
"`env` is a table or struct mapping environment variables to values. It can also "
|
"`env` is a table or struct mapping environment variables to values. It can also "
|
||||||
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
|
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
|
||||||
"These arguments should be core/file values. "
|
":in, :out, and :err should be core/file values or core/stream values. core/file values and core/stream "
|
||||||
"Returns the exit status of the program.") {
|
"values passed to :in, :out, and :err should be closed manually because os/execute doesn't close them. "
|
||||||
return os_execute_impl(argc, argv, 0);
|
"Returns the exit code of the program.") {
|
||||||
|
return os_execute_impl(argc, argv, JANET_EXECUTE_EXECUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(os_spawn,
|
JANET_CORE_FN(os_spawn,
|
||||||
"(os/spawn args &opt flags env)",
|
"(os/spawn args &opt flags env)",
|
||||||
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
||||||
"same arguments as `os/execute`. Does not wait for the process. "
|
"same arguments as `os/execute`. Does not wait for the process. For each of the :in, :out, and :err keys "
|
||||||
"For each of the :in, :out, and :err keys to the `env` argument, one "
|
"of the `env` argument, one can also pass in the keyword `:pipe` to get streams for standard IO of the "
|
||||||
"can also pass in the keyword `:pipe` "
|
"subprocess that can be read from and written to. The returned value `proc` has the fields :in, :out, "
|
||||||
"to get streams for standard IO of the subprocess that can be read from and written to. "
|
":err, and the additional field :pid on unix-like platforms. `(os/proc-wait proc)` must be called to "
|
||||||
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
|
"rejoin the subprocess. After `(os/proc-wait proc)` finishes, proc gains a new field, :return-code. "
|
||||||
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
|
"If :x flag is passed to os/spawn, non-zero exit code will cause os/proc-wait to raise an error. "
|
||||||
"subprocess or `(os/proc-kill proc)`.") {
|
"If pipe streams created with :pipe keyword are not closed in time, janet can run out of file "
|
||||||
return os_execute_impl(argc, argv, 1);
|
"descriptors. They can be closed individually, or `os/proc-close` can close all pipe streams on proc. "
|
||||||
|
"If pipe streams aren't read before `os/proc-wait` finishes, then pipe buffers become full, and the "
|
||||||
|
"process cannot finish because the process cannot print more on pipe buffers which are already full. "
|
||||||
|
"If the process cannot finish, os/proc-wait cannot finish, either.") {
|
||||||
|
return os_execute_impl(argc, argv, JANET_EXECUTE_SPAWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(os_posix_exec,
|
||||||
|
"(os/posix-exec args &opt flags env)",
|
||||||
|
"Use the execvpe or execve system calls to replace the current process with an interface similar to os/execute. "
|
||||||
|
"Hoever, instead of creating a subprocess, the current process is replaced. Is not supported on windows, and "
|
||||||
|
"does not allow redirection of stdio.") {
|
||||||
|
return os_execute_impl(argc, argv, JANET_EXECUTE_EXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(os_posix_fork,
|
||||||
|
"(os/posix-fork)",
|
||||||
|
"Make a `fork` system call and create a new process. Return nil if in the new process, otherwise a core/process object (as returned by os/spawn). "
|
||||||
|
"Not supported on all systems (POSIX only).") {
|
||||||
|
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
||||||
|
janet_fixarity(argc, 0);
|
||||||
|
(void) argv;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
janet_panic("not supported");
|
||||||
|
#else
|
||||||
|
pid_t result;
|
||||||
|
do {
|
||||||
|
result = fork();
|
||||||
|
} while (result == -1 && errno == EINTR);
|
||||||
|
if (result == -1) {
|
||||||
|
janet_panic(strerror(errno));
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
JanetProc *proc = janet_abstract(&ProcAT, sizeof(JanetProc));
|
||||||
|
memset(proc, 0, sizeof(JanetProc));
|
||||||
|
proc->pid = result;
|
||||||
|
proc->flags = JANET_PROC_ALLOW_ZOMBIE;
|
||||||
|
return janet_wrap_abstract(proc);
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
@@ -1479,34 +1564,51 @@ JANET_CORE_FN(os_time,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(os_clock,
|
JANET_CORE_FN(os_clock,
|
||||||
"(os/clock &opt source)",
|
"(os/clock &opt source format)",
|
||||||
"Return the number of whole + fractional seconds of the requested clock source.\n\n"
|
"Return the current time of the requested clock source.\n\n"
|
||||||
"The `source` argument selects the clock source to use, when not specified the default "
|
"The `source` argument selects the clock source to use, when not specified the default "
|
||||||
"is `:realtime`:\n"
|
"is `:realtime`:\n"
|
||||||
"- :realtime: Return the real (i.e., wall-clock) time. This clock is affected by discontinuous "
|
"- :realtime: Return the real (i.e., wall-clock) time. This clock is affected by discontinuous "
|
||||||
" jumps in the system time\n"
|
" jumps in the system time\n"
|
||||||
"- :monotonic: Return the number of whole + fractional seconds since some fixed point in "
|
"- :monotonic: Return the number of whole + fractional seconds since some fixed point in "
|
||||||
" time. The clock is guaranteed to be non-decreasing in real time.\n"
|
" time. The clock is guaranteed to be non-decreasing in real time.\n"
|
||||||
"- :cputime: Return the CPU time consumed by this process (i.e. all threads in the process)\n") {
|
"- :cputime: Return the CPU time consumed by this process (i.e. all threads in the process)\n"
|
||||||
|
"The `format` argument selects the type of output, when not specified the default is `:double`:\n"
|
||||||
|
"- :double: Return the number of seconds + fractional seconds as a double\n"
|
||||||
|
"- :int: Return the number of seconds as an integer\n"
|
||||||
|
"- :tuple: Return a 2 integer tuple [seconds, nanoseconds]\n") {
|
||||||
|
enum JanetTimeSource source;
|
||||||
janet_sandbox_assert(JANET_SANDBOX_HRTIME);
|
janet_sandbox_assert(JANET_SANDBOX_HRTIME);
|
||||||
janet_arity(argc, 0, 1);
|
janet_arity(argc, 0, 2);
|
||||||
enum JanetTimeSource source = JANET_TIME_REALTIME;
|
|
||||||
if (argc == 1) {
|
JanetKeyword sourcestr = janet_optkeyword(argv, argc, 0, (const uint8_t *) "realtime");
|
||||||
JanetKeyword sourcestr = janet_getkeyword(argv, 0);
|
if (janet_cstrcmp(sourcestr, "realtime") == 0) {
|
||||||
if (janet_cstrcmp(sourcestr, "realtime") == 0) {
|
source = JANET_TIME_REALTIME;
|
||||||
source = JANET_TIME_REALTIME;
|
} else if (janet_cstrcmp(sourcestr, "monotonic") == 0) {
|
||||||
} else if (janet_cstrcmp(sourcestr, "monotonic") == 0) {
|
source = JANET_TIME_MONOTONIC;
|
||||||
source = JANET_TIME_MONOTONIC;
|
} else if (janet_cstrcmp(sourcestr, "cputime") == 0) {
|
||||||
} else if (janet_cstrcmp(sourcestr, "cputime") == 0) {
|
source = JANET_TIME_CPUTIME;
|
||||||
source = JANET_TIME_CPUTIME;
|
} else {
|
||||||
} else {
|
janet_panicf("expected :realtime, :monotonic, or :cputime, got %v", argv[0]);
|
||||||
janet_panicf("expected :realtime, :monotonic, or :cputime, got %v", argv[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec tv;
|
struct timespec tv;
|
||||||
if (janet_gettime(&tv, source)) janet_panic("could not get time");
|
if (janet_gettime(&tv, source)) janet_panic("could not get time");
|
||||||
double dtime = tv.tv_sec + (tv.tv_nsec / 1E9);
|
|
||||||
return janet_wrap_number(dtime);
|
JanetKeyword formatstr = janet_optkeyword(argv, argc, 1, (const uint8_t *) "double");
|
||||||
|
if (janet_cstrcmp(formatstr, "double") == 0) {
|
||||||
|
double dtime = tv.tv_sec + (tv.tv_nsec / 1E9);
|
||||||
|
return janet_wrap_number(dtime);
|
||||||
|
} else if (janet_cstrcmp(formatstr, "int") == 0) {
|
||||||
|
return janet_wrap_number(tv.tv_sec);
|
||||||
|
} else if (janet_cstrcmp(formatstr, "tuple") == 0) {
|
||||||
|
Janet tup[2] = {janet_wrap_integer(tv.tv_sec),
|
||||||
|
janet_wrap_integer(tv.tv_nsec)
|
||||||
|
};
|
||||||
|
return janet_wrap_tuple(janet_tuple_n(tup, 2));
|
||||||
|
} else {
|
||||||
|
janet_panicf("expected :double, :int, or :tuple, got %v", argv[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(os_sleep,
|
JANET_CORE_FN(os_sleep,
|
||||||
@@ -2336,34 +2438,6 @@ JANET_CORE_FN(os_permission_int,
|
|||||||
return janet_wrap_integer(os_get_unix_mode(argv, 0));
|
return janet_wrap_integer(os_get_unix_mode(argv, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(os_posix_fork,
|
|
||||||
"(os/posix-fork)",
|
|
||||||
"Make a `fork` system call and create a new process. Return nil if in the new process, otherwise a core/process object (as returned by os/spawn). "
|
|
||||||
"Not supported on all systems (POSIX only).") {
|
|
||||||
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
|
||||||
janet_fixarity(argc, 0);
|
|
||||||
(void) argv;
|
|
||||||
#ifdef JANET_WINDOWS
|
|
||||||
janet_panic("not supported");
|
|
||||||
#else
|
|
||||||
pid_t result;
|
|
||||||
do {
|
|
||||||
result = fork();
|
|
||||||
} while (result == -1 && errno == EINTR);
|
|
||||||
if (result == -1) {
|
|
||||||
janet_panic(strerror(errno));
|
|
||||||
}
|
|
||||||
if (result) {
|
|
||||||
JanetProc *proc = janet_abstract(&ProcAT, sizeof(JanetProc));
|
|
||||||
memset(proc, 0, sizeof(JanetProc));
|
|
||||||
proc->pid = result;
|
|
||||||
proc->flags = JANET_PROC_ALLOW_ZOMBIE;
|
|
||||||
return janet_wrap_abstract(proc);
|
|
||||||
}
|
|
||||||
return janet_wrap_nil();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2651,6 +2725,7 @@ void janet_lib_os(JanetTable *env) {
|
|||||||
JANET_CORE_REG("os/spawn", os_spawn),
|
JANET_CORE_REG("os/spawn", os_spawn),
|
||||||
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),
|
||||||
/* 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),
|
||||||
|
|||||||
106
src/core/peg.c
106
src/core/peg.c
@@ -39,6 +39,10 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t *text_start;
|
const uint8_t *text_start;
|
||||||
const uint8_t *text_end;
|
const uint8_t *text_end;
|
||||||
|
/* text_end can be restricted by some rules, but
|
||||||
|
outer_text_end will always contain the real end of
|
||||||
|
input, which we need to generate a line mapping */
|
||||||
|
const uint8_t *outer_text_end;
|
||||||
const uint32_t *bytecode;
|
const uint32_t *bytecode;
|
||||||
const Janet *constants;
|
const Janet *constants;
|
||||||
JanetArray *captures;
|
JanetArray *captures;
|
||||||
@@ -114,12 +118,12 @@ static LineCol get_linecol_from_position(PegState *s, int32_t position) {
|
|||||||
/* Generate if not made yet */
|
/* Generate if not made yet */
|
||||||
if (s->linemaplen < 0) {
|
if (s->linemaplen < 0) {
|
||||||
int32_t newline_count = 0;
|
int32_t newline_count = 0;
|
||||||
for (const uint8_t *c = s->text_start; c < s->text_end; c++) {
|
for (const uint8_t *c = s->text_start; c < s->outer_text_end; c++) {
|
||||||
if (*c == '\n') newline_count++;
|
if (*c == '\n') newline_count++;
|
||||||
}
|
}
|
||||||
int32_t *mem = janet_smalloc(sizeof(int32_t) * newline_count);
|
int32_t *mem = janet_smalloc(sizeof(int32_t) * newline_count);
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (const uint8_t *c = s->text_start; c < s->text_end; c++) {
|
for (const uint8_t *c = s->text_start; c < s->outer_text_end; c++) {
|
||||||
if (*c == '\n') mem[index++] = (int32_t)(c - s->text_start);
|
if (*c == '\n') mem[index++] = (int32_t)(c - s->text_start);
|
||||||
}
|
}
|
||||||
s->linemaplen = newline_count;
|
s->linemaplen = newline_count;
|
||||||
@@ -179,7 +183,7 @@ static const uint8_t *peg_rule(
|
|||||||
const uint32_t *rule,
|
const uint32_t *rule,
|
||||||
const uint8_t *text) {
|
const uint8_t *text) {
|
||||||
tail:
|
tail:
|
||||||
switch (*rule & 0x1F) {
|
switch (*rule) {
|
||||||
default:
|
default:
|
||||||
janet_panic("unexpected opcode");
|
janet_panic("unexpected opcode");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -482,6 +486,68 @@ tail:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case RULE_SUB: {
|
||||||
|
const uint8_t *text_start = text;
|
||||||
|
const uint32_t *rule_window = s->bytecode + rule[1];
|
||||||
|
const uint32_t *rule_subpattern = s->bytecode + rule[2];
|
||||||
|
down1(s);
|
||||||
|
const uint8_t *window_end = peg_rule(s, rule_window, text);
|
||||||
|
up1(s);
|
||||||
|
if (!window_end) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const uint8_t *saved_end = s->text_end;
|
||||||
|
s->text_end = window_end;
|
||||||
|
down1(s);
|
||||||
|
const uint8_t *next_text = peg_rule(s, rule_subpattern, text_start);
|
||||||
|
up1(s);
|
||||||
|
s->text_end = saved_end;
|
||||||
|
|
||||||
|
if (!next_text) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RULE_SPLIT: {
|
||||||
|
const uint8_t *saved_end = s->text_end;
|
||||||
|
const uint32_t *rule_separator = s->bytecode + rule[1];
|
||||||
|
const uint32_t *rule_subpattern = s->bytecode + rule[2];
|
||||||
|
|
||||||
|
const uint8_t *separator_end = NULL;
|
||||||
|
do {
|
||||||
|
const uint8_t *text_start = text;
|
||||||
|
CapState cs = cap_save(s);
|
||||||
|
down1(s);
|
||||||
|
while (text <= s->text_end) {
|
||||||
|
separator_end = peg_rule(s, rule_separator, text);
|
||||||
|
cap_load(s, cs);
|
||||||
|
if (separator_end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
text++;
|
||||||
|
}
|
||||||
|
up1(s);
|
||||||
|
|
||||||
|
if (separator_end) {
|
||||||
|
s->text_end = text;
|
||||||
|
text = separator_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
down1(s);
|
||||||
|
const uint8_t *subpattern_end = peg_rule(s, rule_subpattern, text_start);
|
||||||
|
up1(s);
|
||||||
|
s->text_end = saved_end;
|
||||||
|
|
||||||
|
if (!subpattern_end) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} while (separator_end);
|
||||||
|
|
||||||
|
return s->text_end;
|
||||||
|
}
|
||||||
|
|
||||||
case RULE_REPLACE:
|
case RULE_REPLACE:
|
||||||
case RULE_MATCHTIME: {
|
case RULE_MATCHTIME: {
|
||||||
uint32_t tag = rule[3];
|
uint32_t tag = rule[3];
|
||||||
@@ -1107,6 +1173,22 @@ static void spec_matchtime(Builder *b, int32_t argc, const Janet *argv) {
|
|||||||
emit_3(r, RULE_MATCHTIME, subrule, cindex, tag);
|
emit_3(r, RULE_MATCHTIME, subrule, cindex, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spec_sub(Builder *b, int32_t argc, const Janet *argv) {
|
||||||
|
peg_fixarity(b, argc, 2);
|
||||||
|
Reserve r = reserve(b, 3);
|
||||||
|
uint32_t subrule1 = peg_compile1(b, argv[0]);
|
||||||
|
uint32_t subrule2 = peg_compile1(b, argv[1]);
|
||||||
|
emit_2(r, RULE_SUB, subrule1, subrule2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spec_split(Builder *b, int32_t argc, const Janet *argv) {
|
||||||
|
peg_fixarity(b, argc, 2);
|
||||||
|
Reserve r = reserve(b, 3);
|
||||||
|
uint32_t subrule1 = peg_compile1(b, argv[0]);
|
||||||
|
uint32_t subrule2 = peg_compile1(b, argv[1]);
|
||||||
|
emit_2(r, RULE_SPLIT, subrule1, subrule2);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef JANET_INT_TYPES
|
#ifdef JANET_INT_TYPES
|
||||||
#define JANET_MAX_READINT_WIDTH 8
|
#define JANET_MAX_READINT_WIDTH 8
|
||||||
#else
|
#else
|
||||||
@@ -1190,6 +1272,8 @@ static const SpecialPair peg_specials[] = {
|
|||||||
{"sequence", spec_sequence},
|
{"sequence", spec_sequence},
|
||||||
{"set", spec_set},
|
{"set", spec_set},
|
||||||
{"some", spec_some},
|
{"some", spec_some},
|
||||||
|
{"split", spec_split},
|
||||||
|
{"sub", spec_sub},
|
||||||
{"thru", spec_thru},
|
{"thru", spec_thru},
|
||||||
{"to", spec_to},
|
{"to", spec_to},
|
||||||
{"uint", spec_uint_le},
|
{"uint", spec_uint_le},
|
||||||
@@ -1431,7 +1515,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
uint32_t instr = bytecode[i];
|
uint32_t instr = bytecode[i];
|
||||||
uint32_t *rule = bytecode + i;
|
uint32_t *rule = bytecode + i;
|
||||||
op_flags[i] |= 0x02;
|
op_flags[i] |= 0x02;
|
||||||
switch (instr & 0x1F) {
|
switch (instr) {
|
||||||
case RULE_LITERAL:
|
case RULE_LITERAL:
|
||||||
i += 2 + ((rule[1] + 3) >> 2);
|
i += 2 + ((rule[1] + 3) >> 2);
|
||||||
break;
|
break;
|
||||||
@@ -1524,6 +1608,15 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
op_flags[rule[1]] |= 0x01;
|
op_flags[rule[1]] |= 0x01;
|
||||||
i += 4;
|
i += 4;
|
||||||
break;
|
break;
|
||||||
|
case RULE_SUB:
|
||||||
|
case RULE_SPLIT:
|
||||||
|
/* [rule, rule] */
|
||||||
|
if (rule[1] >= blen) goto bad;
|
||||||
|
if (rule[2] >= blen) goto bad;
|
||||||
|
op_flags[rule[1]] |= 0x01;
|
||||||
|
op_flags[rule[2]] |= 0x01;
|
||||||
|
i += 3;
|
||||||
|
break;
|
||||||
case RULE_ERROR:
|
case RULE_ERROR:
|
||||||
case RULE_DROP:
|
case RULE_DROP:
|
||||||
case RULE_NOT:
|
case RULE_NOT:
|
||||||
@@ -1652,7 +1745,7 @@ typedef struct {
|
|||||||
static PegCall peg_cfun_init(int32_t argc, Janet *argv, int get_replace) {
|
static PegCall peg_cfun_init(int32_t argc, Janet *argv, int get_replace) {
|
||||||
PegCall ret;
|
PegCall ret;
|
||||||
int32_t min = get_replace ? 3 : 2;
|
int32_t min = get_replace ? 3 : 2;
|
||||||
janet_arity(argc, get_replace, -1);
|
janet_arity(argc, min, -1);
|
||||||
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
||||||
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
|
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
|
||||||
ret.peg = janet_unwrap_abstract(argv[0]);
|
ret.peg = janet_unwrap_abstract(argv[0]);
|
||||||
@@ -1677,6 +1770,7 @@ static PegCall peg_cfun_init(int32_t argc, Janet *argv, int get_replace) {
|
|||||||
ret.s.mode = PEG_MODE_NORMAL;
|
ret.s.mode = PEG_MODE_NORMAL;
|
||||||
ret.s.text_start = ret.bytes.bytes;
|
ret.s.text_start = ret.bytes.bytes;
|
||||||
ret.s.text_end = ret.bytes.bytes + ret.bytes.len;
|
ret.s.text_end = ret.bytes.bytes + ret.bytes.len;
|
||||||
|
ret.s.outer_text_end = ret.s.text_end;
|
||||||
ret.s.depth = JANET_RECURSION_GUARD;
|
ret.s.depth = JANET_RECURSION_GUARD;
|
||||||
ret.s.captures = janet_array(0);
|
ret.s.captures = janet_array(0);
|
||||||
ret.s.tagged_captures = janet_array(0);
|
ret.s.tagged_captures = janet_array(0);
|
||||||
@@ -1771,7 +1865,7 @@ JANET_CORE_FN(cfun_peg_replace_all,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_peg_replace,
|
JANET_CORE_FN(cfun_peg_replace,
|
||||||
"(peg/replace peg repl text &opt start & args)",
|
"(peg/replace peg subst text &opt start & args)",
|
||||||
"Replace first match of `peg` in `text` with `subst`, returning a new buffer. "
|
"Replace first match of `peg` in `text` with `subst`, returning a new buffer. "
|
||||||
"The peg does not need to make captures to do replacement. "
|
"The peg does not need to make captures to do replacement. "
|
||||||
"If `subst` is a function, it will be called with the "
|
"If `subst` is a function, it will be called with the "
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
/* Implements a pretty printer for Janet. The pretty printer
|
/* Implements a pretty printer for Janet. The pretty printer
|
||||||
* is simple and not that flexible, but fast. */
|
* is simple and not that flexible, but fast. */
|
||||||
@@ -38,11 +39,15 @@
|
|||||||
/* Temporary buffer size */
|
/* Temporary buffer size */
|
||||||
#define BUFSIZE 64
|
#define BUFSIZE 64
|
||||||
|
|
||||||
|
/* Preprocessor hacks */
|
||||||
|
#define STR_HELPER(x) #x
|
||||||
|
#define STR(x) STR_HELPER(x)
|
||||||
|
|
||||||
static void number_to_string_b(JanetBuffer *buffer, double x) {
|
static void number_to_string_b(JanetBuffer *buffer, double x) {
|
||||||
janet_buffer_ensure(buffer, buffer->count + BUFSIZE, 2);
|
janet_buffer_ensure(buffer, buffer->count + BUFSIZE, 2);
|
||||||
const char *fmt = (x == floor(x) &&
|
const char *fmt = (x == floor(x) &&
|
||||||
x <= JANET_INTMAX_DOUBLE &&
|
x <= JANET_INTMAX_DOUBLE &&
|
||||||
x >= JANET_INTMIN_DOUBLE) ? "%.0f" : "%g";
|
x >= JANET_INTMIN_DOUBLE) ? "%.0f" : ("%." STR(DBL_DIG) "g");
|
||||||
int count;
|
int count;
|
||||||
if (x == 0.0) {
|
if (x == 0.0) {
|
||||||
/* Prevent printing of '-0' */
|
/* Prevent printing of '-0' */
|
||||||
@@ -772,6 +777,8 @@ struct FmtMapping {
|
|||||||
/* Janet uses fixed width integer types for most things, so map
|
/* Janet uses fixed width integer types for most things, so map
|
||||||
* format specifiers to these fixed sizes */
|
* format specifiers to these fixed sizes */
|
||||||
static const struct FmtMapping format_mappings[] = {
|
static const struct FmtMapping format_mappings[] = {
|
||||||
|
{'D', PRId64},
|
||||||
|
{'I', PRIi64},
|
||||||
{'d', PRId64},
|
{'d', PRId64},
|
||||||
{'i', PRIi64},
|
{'i', PRIi64},
|
||||||
{'o', PRIo64},
|
{'o', PRIo64},
|
||||||
@@ -850,13 +857,19 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
|
|||||||
c = scanformat(c, form, width, precision);
|
c = scanformat(c, form, width, precision);
|
||||||
switch (*c++) {
|
switch (*c++) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
int n = va_arg(args, long);
|
int n = va_arg(args, int);
|
||||||
nb = snprintf(item, MAX_ITEM, form, n);
|
nb = snprintf(item, MAX_ITEM, form, n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i': {
|
case 'i': {
|
||||||
int64_t n = va_arg(args, int);
|
int64_t n = (int64_t) va_arg(args, int32_t);
|
||||||
|
nb = snprintf(item, MAX_ITEM, form, n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'D':
|
||||||
|
case 'I': {
|
||||||
|
int64_t n = va_arg(args, int64_t);
|
||||||
nb = snprintf(item, MAX_ITEM, form, n);
|
nb = snprintf(item, MAX_ITEM, form, n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -864,7 +877,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
|
|||||||
case 'X':
|
case 'X':
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'u': {
|
case 'u': {
|
||||||
uint64_t n = va_arg(args, unsigned int);
|
uint64_t n = va_arg(args, uint64_t);
|
||||||
nb = snprintf(item, MAX_ITEM, form, n);
|
nb = snprintf(item, MAX_ITEM, form, n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -908,7 +921,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
|
|||||||
janet_buffer_push_cstring(b, typestr(va_arg(args, Janet)));
|
janet_buffer_push_cstring(b, typestr(va_arg(args, Janet)));
|
||||||
break;
|
break;
|
||||||
case 'T': {
|
case 'T': {
|
||||||
int types = va_arg(args, long);
|
int types = va_arg(args, int);
|
||||||
pushtypes(b, types);
|
pushtypes(b, types);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1017,6 +1030,8 @@ void janet_buffer_format(
|
|||||||
janet_getinteger(argv, arg));
|
janet_getinteger(argv, arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'D':
|
||||||
|
case 'I':
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i': {
|
case 'i': {
|
||||||
int64_t n = janet_getinteger64(argv, arg);
|
int64_t n = janet_getinteger64(argv, arg);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
int errflags = 0, done = 0;
|
int errflags = 0, done = 0;
|
||||||
int32_t index = 0;
|
int32_t index = 0;
|
||||||
Janet ret = janet_wrap_nil();
|
Janet ret = janet_wrap_nil();
|
||||||
|
JanetFiber *fiber = NULL;
|
||||||
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
|
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
|
||||||
|
|
||||||
if (where) janet_gcroot(janet_wrap_string(where));
|
if (where) janet_gcroot(janet_wrap_string(where));
|
||||||
@@ -47,7 +48,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
JanetCompileResult cres = janet_compile(form, env, where);
|
JanetCompileResult cres = janet_compile(form, env, where);
|
||||||
if (cres.status == JANET_COMPILE_OK) {
|
if (cres.status == JANET_COMPILE_OK) {
|
||||||
JanetFunction *f = janet_thunk(cres.funcdef);
|
JanetFunction *f = janet_thunk(cres.funcdef);
|
||||||
JanetFiber *fiber = janet_fiber(f, 64, 0, NULL);
|
fiber = janet_fiber(f, 64, 0, NULL);
|
||||||
fiber->env = env;
|
fiber->env = env;
|
||||||
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) {
|
||||||
@@ -112,9 +113,14 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
|||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
/* Enter the event loop if we are not already in it */
|
/* Enter the event loop if we are not already in it */
|
||||||
if (janet_vm.stackn == 0) {
|
if (janet_vm.stackn == 0) {
|
||||||
janet_gcroot(ret);
|
if (fiber) {
|
||||||
|
janet_gcroot(janet_wrap_fiber(fiber));
|
||||||
|
}
|
||||||
janet_loop();
|
janet_loop();
|
||||||
janet_gcunroot(ret);
|
if (fiber) {
|
||||||
|
janet_gcunroot(janet_wrap_fiber(fiber));
|
||||||
|
ret = fiber->last_value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (out) *out = ret;
|
if (out) *out = ret;
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ static int destructure(JanetCompiler *c,
|
|||||||
JanetTable *attr) {
|
JanetTable *attr) {
|
||||||
switch (janet_type(left)) {
|
switch (janet_type(left)) {
|
||||||
default:
|
default:
|
||||||
janetc_error(c, janet_formatc("unexpected type in destruction, got %v", left));
|
janetc_error(c, janet_formatc("unexpected type in destructuring, got %v", left));
|
||||||
return 1;
|
return 1;
|
||||||
case JANET_SYMBOL:
|
case JANET_SYMBOL:
|
||||||
/* Leaf, assign right to left */
|
/* Leaf, assign right to left */
|
||||||
@@ -531,17 +531,11 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if a form matches the pattern (= nil _) or (not= nil _) */
|
/* Check if a form matches the pattern (= nil _) or (not= nil _) */
|
||||||
static int janetc_check_nil_form(JanetFopts opts, Janet x, Janet *capture, uint32_t fun_tag) {
|
static int janetc_check_nil_form(Janet x, Janet *capture, uint32_t fun_tag) {
|
||||||
if (!janet_checktype(x, JANET_TUPLE)) return 0;
|
if (!janet_checktype(x, JANET_TUPLE)) return 0;
|
||||||
JanetTuple tup = janet_unwrap_tuple(x);
|
JanetTuple tup = janet_unwrap_tuple(x);
|
||||||
if (3 != janet_tuple_length(tup)) return 0;
|
if (3 != janet_tuple_length(tup)) return 0;
|
||||||
Janet op1 = tup[0];
|
Janet op1 = tup[0];
|
||||||
if (janet_checktype(op1, JANET_SYMBOL)) {
|
|
||||||
Janet entry = janet_table_get(opts.compiler->env, op1);
|
|
||||||
if (janet_checktype(entry, JANET_TABLE)) {
|
|
||||||
op1 = janet_table_get(janet_unwrap_table(entry), janet_ckeywordv("value"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!janet_checktype(op1, JANET_FUNCTION)) return 0;
|
if (!janet_checktype(op1, JANET_FUNCTION)) return 0;
|
||||||
JanetFunction *fun = janet_unwrap_function(op1);
|
JanetFunction *fun = janet_unwrap_function(op1);
|
||||||
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
|
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
|
||||||
@@ -601,10 +595,9 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
|
|||||||
janetc_scope(&condscope, c, 0, "if");
|
janetc_scope(&condscope, c, 0, "if");
|
||||||
|
|
||||||
Janet condform = argv[0];
|
Janet condform = argv[0];
|
||||||
if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_EQ)) {
|
if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
|
||||||
ifnjmp = JOP_JUMP_IF_NOT_NIL;
|
ifnjmp = JOP_JUMP_IF_NOT_NIL;
|
||||||
}
|
} else if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
|
||||||
if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_NEQ)) {
|
|
||||||
ifnjmp = JOP_JUMP_IF_NIL;
|
ifnjmp = JOP_JUMP_IF_NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,7 +606,11 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
|
|||||||
/* Check constant condition. */
|
/* Check constant condition. */
|
||||||
/* TODO: Use type info for more short circuits */
|
/* TODO: Use type info for more short circuits */
|
||||||
if (cond.flags & JANET_SLOT_CONSTANT) {
|
if (cond.flags & JANET_SLOT_CONSTANT) {
|
||||||
if (!janet_truthy(cond.constant)) {
|
int swap_condition = 0;
|
||||||
|
if (ifnjmp == JOP_JUMP_IF_NOT && !janet_truthy(cond.constant)) swap_condition = 1;
|
||||||
|
if (ifnjmp == JOP_JUMP_IF_NIL && janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
|
||||||
|
if (ifnjmp == JOP_JUMP_IF_NOT_NIL && !janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
|
||||||
|
if (swap_condition) {
|
||||||
/* Swap the true and false bodies */
|
/* Swap the true and false bodies */
|
||||||
Janet temp = falsebody;
|
Janet temp = falsebody;
|
||||||
falsebody = truebody;
|
falsebody = truebody;
|
||||||
@@ -808,12 +805,12 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
|
|||||||
* jmpnl or jmpnn instructions. This let's us implement `(each ...)`
|
* jmpnl or jmpnn instructions. This let's us implement `(each ...)`
|
||||||
* more efficiently. */
|
* more efficiently. */
|
||||||
Janet condform = argv[0];
|
Janet condform = argv[0];
|
||||||
if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_EQ)) {
|
if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
|
||||||
is_nil_form = 1;
|
is_nil_form = 1;
|
||||||
ifjmp = JOP_JUMP_IF_NIL;
|
ifjmp = JOP_JUMP_IF_NIL;
|
||||||
ifnjmp = JOP_JUMP_IF_NOT_NIL;
|
ifnjmp = JOP_JUMP_IF_NOT_NIL;
|
||||||
}
|
}
|
||||||
if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_NEQ)) {
|
if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
|
||||||
is_notnil_form = 1;
|
is_notnil_form = 1;
|
||||||
ifjmp = JOP_JUMP_IF_NOT_NIL;
|
ifjmp = JOP_JUMP_IF_NOT_NIL;
|
||||||
ifnjmp = JOP_JUMP_IF_NIL;
|
ifnjmp = JOP_JUMP_IF_NIL;
|
||||||
|
|||||||
@@ -549,8 +549,8 @@ JANET_CORE_FN(cfun_string_format,
|
|||||||
"- `a`, `A`: floating point number, formatted as a hexadecimal number.\n"
|
"- `a`, `A`: floating point number, formatted as a hexadecimal number.\n"
|
||||||
"- `s`: formatted as a string, precision indicates padding and maximum length.\n"
|
"- `s`: formatted as a string, precision indicates padding and maximum length.\n"
|
||||||
"- `t`: emit the type of the given value.\n"
|
"- `t`: emit the type of the given value.\n"
|
||||||
"- `v`: format with (describe x)"
|
"- `v`: format with (describe x)\n"
|
||||||
"- `V`: format with (string x)"
|
"- `V`: format with (string x)\n"
|
||||||
"- `j`: format to jdn (Janet data notation).\n"
|
"- `j`: format to jdn (Janet data notation).\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The following conversion specifiers are used for \"pretty-printing\", where the upper-case "
|
"The following conversion specifiers are used for \"pretty-printing\", where the upper-case "
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ const uint8_t *janet_symbol_gen(void) {
|
|||||||
head->hash = hash;
|
head->hash = hash;
|
||||||
sym = (uint8_t *)(head->data);
|
sym = (uint8_t *)(head->data);
|
||||||
memcpy(sym, janet_vm.gensym_counter, sizeof(janet_vm.gensym_counter));
|
memcpy(sym, janet_vm.gensym_counter, sizeof(janet_vm.gensym_counter));
|
||||||
|
sym[head->length] = 0;
|
||||||
janet_symcache_put((const uint8_t *)sym, bucket);
|
janet_symcache_put((const uint8_t *)sym, bucket);
|
||||||
return (const uint8_t *)sym;
|
return (const uint8_t *)sym;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -960,6 +960,7 @@ void arc4random_buf(void *buf, size_t nbytes);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int janet_cryptorand(uint8_t *out, size_t n) {
|
int janet_cryptorand(uint8_t *out, size_t n) {
|
||||||
|
#ifndef JANET_NO_CRYPTORAND
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
for (size_t i = 0; i < n; i += sizeof(unsigned int)) {
|
for (size_t i = 0; i < n; i += sizeof(unsigned int)) {
|
||||||
unsigned int v;
|
unsigned int v;
|
||||||
@@ -971,7 +972,10 @@ int janet_cryptorand(uint8_t *out, size_t n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#elif defined(JANET_LINUX) || defined(JANET_CYGWIN) || ( defined(JANET_APPLE) && !defined(MAC_OS_X_VERSION_10_7) )
|
#elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
|
||||||
|
arc4random_buf(out, n);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
/* We should be able to call getrandom on linux, but it doesn't seem
|
/* We should be able to call getrandom on linux, but it doesn't seem
|
||||||
to be uniformly supported on linux distros.
|
to be uniformly supported on linux distros.
|
||||||
On Mac, arc4random_buf wasn't available on until 10.7.
|
On Mac, arc4random_buf wasn't available on until 10.7.
|
||||||
@@ -993,12 +997,10 @@ int janet_cryptorand(uint8_t *out, size_t n) {
|
|||||||
}
|
}
|
||||||
RETRY_EINTR(rc, close(randfd));
|
RETRY_EINTR(rc, close(randfd));
|
||||||
return 0;
|
return 0;
|
||||||
#elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
|
#endif
|
||||||
arc4random_buf(out, n);
|
|
||||||
return 0;
|
|
||||||
#else
|
#else
|
||||||
(void) n;
|
|
||||||
(void) out;
|
(void) out;
|
||||||
|
(void) n;
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,11 +49,11 @@
|
|||||||
#ifndef JANET_EXIT
|
#ifndef JANET_EXIT
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define JANET_EXIT(m) do { \
|
#define JANET_EXIT(m) do { \
|
||||||
fprintf(stderr, "janet interpreter runtime error at line %d in file %s: %s\n",\
|
fprintf(stderr, "janet internal error at line %d in file %s: %s\n",\
|
||||||
__LINE__,\
|
__LINE__,\
|
||||||
__FILE__,\
|
__FILE__,\
|
||||||
(m));\
|
(m));\
|
||||||
exit(1);\
|
abort();\
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -596,8 +596,7 @@ typedef enum {
|
|||||||
JANET_ASYNC_EVENT_READ = 6,
|
JANET_ASYNC_EVENT_READ = 6,
|
||||||
JANET_ASYNC_EVENT_WRITE = 7,
|
JANET_ASYNC_EVENT_WRITE = 7,
|
||||||
JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */
|
JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */
|
||||||
JANET_ASYNC_EVENT_FAILED = 9, /* Used on windows for IOCP */
|
JANET_ASYNC_EVENT_FAILED = 9 /* Used on windows for IOCP */
|
||||||
JANET_ASYNC_EVENT_USER = 10
|
|
||||||
} JanetAsyncEvent;
|
} JanetAsyncEvent;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -606,9 +605,7 @@ typedef enum {
|
|||||||
JANET_ASYNC_LISTEN_BOTH
|
JANET_ASYNC_LISTEN_BOTH
|
||||||
} JanetAsyncMode;
|
} JanetAsyncMode;
|
||||||
|
|
||||||
/* Typedefs */
|
|
||||||
typedef struct JanetStream JanetStream;
|
typedef struct JanetStream JanetStream;
|
||||||
typedef void (*JanetEVCallback)(JanetFiber *fiber, JanetAsyncEvent event);
|
|
||||||
|
|
||||||
/* Wrapper around file descriptors and HANDLEs that can be polled. */
|
/* Wrapper around file descriptors and HANDLEs that can be polled. */
|
||||||
struct JanetStream {
|
struct JanetStream {
|
||||||
@@ -620,9 +617,24 @@ struct JanetStream {
|
|||||||
const void *methods; /* Methods for this stream */
|
const void *methods; /* Methods for this stream */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*JanetEVCallback)(JanetFiber *fiber, JanetAsyncEvent event);
|
||||||
|
|
||||||
|
/* Start listening for events from a stream on the current root fiber. After
|
||||||
|
* calling this, users should call janet_await() before returning from the
|
||||||
|
* current C Function. This also will call janet_await.
|
||||||
|
* mode is which events to listen for, and callback is the function pointer to
|
||||||
|
* call when ever an event is sent from the event loop. state is an optional (can be NULL)
|
||||||
|
* pointer to data allocated with janet_malloc. This pointer will be passed to callback as
|
||||||
|
* fiber->ev_state. It will also be freed for you by the runtime when the event loop determines
|
||||||
|
* it can no longer be referenced. On windows, the contents of state MUST contained an OVERLAPPED struct. */
|
||||||
|
JANET_API JANET_NO_RETURN void janet_async_start(JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, void *state);
|
||||||
|
|
||||||
|
/* Do not send any more events to the given callback. Call this after scheduling fiber to be resume
|
||||||
|
* or canceled. */
|
||||||
JANET_API void janet_async_end(JanetFiber *fiber);
|
JANET_API void janet_async_end(JanetFiber *fiber);
|
||||||
JANET_API void *janet_async_start(JanetFiber *fiber, JanetStream *stream,
|
|
||||||
JanetAsyncMode mode, JanetEVCallback callback, size_t data_size);
|
/* Needed for windows to mark a fiber as waiting for an IOCP completion event. Noop on other platforms. */
|
||||||
|
JANET_API void janet_async_in_flight(JanetFiber *fiber);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -635,6 +647,7 @@ typedef int32_t JanetAtomicInt;
|
|||||||
#endif
|
#endif
|
||||||
JANET_API JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x);
|
JANET_API JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x);
|
||||||
JANET_API JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x);
|
JANET_API JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x);
|
||||||
|
JANET_API JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x);
|
||||||
|
|
||||||
/* We provide three possible implementations of Janets. The preferred
|
/* We provide three possible implementations of Janets. The preferred
|
||||||
* nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
|
* nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
|
||||||
@@ -1488,22 +1501,22 @@ JANET_API void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGeneric
|
|||||||
JANET_API void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value);
|
JANET_API void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value);
|
||||||
|
|
||||||
/* Read async from a stream */
|
/* Read async from a stream */
|
||||||
JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
|
JANET_NO_RETURN JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
|
||||||
JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
|
JANET_NO_RETURN JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
|
||||||
#ifdef JANET_NET
|
#ifdef JANET_NET
|
||||||
JANET_API void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
||||||
JANET_API void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
||||||
JANET_API void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Write async to a stream */
|
/* Write async to a stream */
|
||||||
JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf);
|
JANET_NO_RETURN JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf);
|
||||||
JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str);
|
JANET_NO_RETURN JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str);
|
||||||
#ifdef JANET_NET
|
#ifdef JANET_NET
|
||||||
JANET_API void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags);
|
||||||
JANET_API void janet_ev_send_string(JanetStream *stream, JanetString str, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_send_string(JanetStream *stream, JanetString str, int flags);
|
||||||
JANET_API void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags);
|
||||||
JANET_API void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags);
|
JANET_NO_RETURN JANET_API void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2127,7 +2140,9 @@ typedef enum {
|
|||||||
RULE_LINE, /* [tag] */
|
RULE_LINE, /* [tag] */
|
||||||
RULE_COLUMN, /* [tag] */
|
RULE_COLUMN, /* [tag] */
|
||||||
RULE_UNREF, /* [rule, tag] */
|
RULE_UNREF, /* [rule, tag] */
|
||||||
RULE_CAPTURE_NUM /* [rule, tag] */
|
RULE_CAPTURE_NUM, /* [rule, tag] */
|
||||||
|
RULE_SUB, /* [rule, rule] */
|
||||||
|
RULE_SPLIT /* [rule, rule] */
|
||||||
} JanetPegOpcod;
|
} JanetPegOpcod;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -502,10 +502,10 @@ static void kright(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void krightw(void) {
|
static void krightw(void) {
|
||||||
while (gbl_pos != gbl_len && !isspace(gbl_buf[gbl_pos])) {
|
while (gbl_pos != gbl_len && isspace(gbl_buf[gbl_pos])) {
|
||||||
gbl_pos++;
|
gbl_pos++;
|
||||||
}
|
}
|
||||||
while (gbl_pos != gbl_len && isspace(gbl_buf[gbl_pos])) {
|
while (gbl_pos != gbl_len && !isspace(gbl_buf[gbl_pos])) {
|
||||||
gbl_pos++;
|
gbl_pos++;
|
||||||
}
|
}
|
||||||
refresh();
|
refresh();
|
||||||
|
|||||||
@@ -51,5 +51,13 @@
|
|||||||
(def f (asm (disasm (fn [x] (fn [y] (+ x y))))))
|
(def f (asm (disasm (fn [x] (fn [y] (+ x y))))))
|
||||||
(assert (= ((f 10) 37) 47) "asm environment tables")
|
(assert (= ((f 10) 37) 47) "asm environment tables")
|
||||||
|
|
||||||
|
# issue #1424
|
||||||
|
(assert-no-error "arity > used slots (issue #1424)"
|
||||||
|
(asm
|
||||||
|
(disasm
|
||||||
|
(fn []
|
||||||
|
(def foo (fn [one two] one))
|
||||||
|
(foo 100 200)))))
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
|||||||
@@ -241,6 +241,16 @@
|
|||||||
(assert (pos? (% x 4)) "generate in loop"))
|
(assert (pos? (% x 4)) "generate in loop"))
|
||||||
(assert (= gencount 75) "generate loop count")
|
(assert (= gencount 75) "generate loop count")
|
||||||
|
|
||||||
|
# more loop checks
|
||||||
|
(assert (deep= (seq [i :range [0 10]] i) @[0 1 2 3 4 5 6 7 8 9]) "seq 1")
|
||||||
|
(assert (deep= (seq [i :range [0 10 2]] i) @[0 2 4 6 8]) "seq 2")
|
||||||
|
(assert (deep= (seq [i :range [10]] i) @[0 1 2 3 4 5 6 7 8 9]) "seq 3")
|
||||||
|
(assert (deep= (seq [i :range-to [10]] i) @[0 1 2 3 4 5 6 7 8 9 10]) "seq 4")
|
||||||
|
(def gen (generate [x :range-to [0 nil 2]] x))
|
||||||
|
(assert (deep= (take 5 gen) @[0 2 4 6 8]) "generate nil limit")
|
||||||
|
(def gen (generate [x :range [0 nil 2]] x))
|
||||||
|
(assert (deep= (take 5 gen) @[0 2 4 6 8]) "generate nil limit 2")
|
||||||
|
|
||||||
# Even and odd
|
# Even and odd
|
||||||
# ff163a5ae
|
# ff163a5ae
|
||||||
(assert (odd? 9) "odd? 1")
|
(assert (odd? 9) "odd? 1")
|
||||||
@@ -945,10 +955,25 @@
|
|||||||
(defn case-4 [&]
|
(defn case-4 [&]
|
||||||
(def x (break (break (break)))))
|
(def x (break (break (break)))))
|
||||||
(bytecode-roundtrip case-4)
|
(bytecode-roundtrip case-4)
|
||||||
|
(defn case-5 []
|
||||||
|
(def foo (fn [one two] one))
|
||||||
|
(foo 100 200))
|
||||||
|
(bytecode-roundtrip case-5)
|
||||||
|
|
||||||
# Debug bytecode of these functions
|
# Debug bytecode of these functions
|
||||||
# (pp (disasm case-1))
|
# (pp (disasm case-1))
|
||||||
# (pp (disasm case-2))
|
# (pp (disasm case-2))
|
||||||
# (pp (disasm case-3))
|
# (pp (disasm case-3))
|
||||||
|
|
||||||
|
# Regression #1330
|
||||||
|
(defn regress-1330 [&]
|
||||||
|
(def a [1 2 3])
|
||||||
|
(def b [;a])
|
||||||
|
(identity a))
|
||||||
|
(assert (= [1 2 3] (regress-1330)) "regression 1330")
|
||||||
|
|
||||||
|
# Issue 1341
|
||||||
|
(assert (= () '() (macex '())) "macex ()")
|
||||||
|
(assert (= '[] (macex '[])) "macex []")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|||||||
@@ -77,6 +77,46 @@
|
|||||||
(buffer/push-string b5 "456" @"789")
|
(buffer/push-string b5 "456" @"789")
|
||||||
(assert (= "123456789" (string b5)) "buffer/push-buffer 2")
|
(assert (= "123456789" (string b5)) "buffer/push-buffer 2")
|
||||||
|
|
||||||
|
(def buffer-uint16-be @"")
|
||||||
|
(buffer/push-uint16 buffer-uint16-be :be 0x0102)
|
||||||
|
(assert (= "\x01\x02" (string buffer-uint16-be)) "buffer/push-uint16 big endian")
|
||||||
|
|
||||||
|
(def buffer-uint16-le @"")
|
||||||
|
(buffer/push-uint16 buffer-uint16-le :le 0x0102)
|
||||||
|
(assert (= "\x02\x01" (string buffer-uint16-le)) "buffer/push-uint16 little endian")
|
||||||
|
|
||||||
|
(def buffer-uint16-negative @"")
|
||||||
|
(buffer/push-uint16 buffer-uint16-negative :be -1)
|
||||||
|
(assert (= "\xff\xff" (string buffer-uint16-negative)) "buffer/push-uint16 negative")
|
||||||
|
|
||||||
|
(def buffer-uint32-be @"")
|
||||||
|
(buffer/push-uint32 buffer-uint32-be :be 0x01020304)
|
||||||
|
(assert (= "\x01\x02\x03\x04" (string buffer-uint32-be)) "buffer/push-uint32 big endian")
|
||||||
|
|
||||||
|
(def buffer-uint32-le @"")
|
||||||
|
(buffer/push-uint32 buffer-uint32-le :le 0x01020304)
|
||||||
|
(assert (= "\x04\x03\x02\x01" (string buffer-uint32-le)) "buffer/push-uint32 little endian")
|
||||||
|
|
||||||
|
(def buffer-uint32-negative @"")
|
||||||
|
(buffer/push-uint32 buffer-uint32-negative :be -1)
|
||||||
|
(assert (= "\xff\xff\xff\xff" (string buffer-uint32-negative)) "buffer/push-uint32 negative")
|
||||||
|
|
||||||
|
(def buffer-float32-be @"")
|
||||||
|
(buffer/push-float32 buffer-float32-be :be 1.234)
|
||||||
|
(assert (= "\x3f\x9d\xf3\xb6" (string buffer-float32-be)) "buffer/push-float32 big endian")
|
||||||
|
|
||||||
|
(def buffer-float32-le @"")
|
||||||
|
(buffer/push-float32 buffer-float32-le :le 1.234)
|
||||||
|
(assert (= "\xb6\xf3\x9d\x3f" (string buffer-float32-le)) "buffer/push-float32 little endian")
|
||||||
|
|
||||||
|
(def buffer-float64-be @"")
|
||||||
|
(buffer/push-float64 buffer-float64-be :be 1.234)
|
||||||
|
(assert (= "\x3f\xf3\xbe\x76\xc8\xb4\x39\x58" (string buffer-float64-be)) "buffer/push-float64 big endian")
|
||||||
|
|
||||||
|
(def buffer-float64-le @"")
|
||||||
|
(buffer/push-float64 buffer-float64-le :le 1.234)
|
||||||
|
(assert (= "\x58\x39\xb4\xc8\x76\xbe\xf3\x3f" (string buffer-float64-le)) "buffer/push-float64 little endian")
|
||||||
|
|
||||||
# Buffer from bytes
|
# Buffer from bytes
|
||||||
(assert (deep= @"" (buffer/from-bytes)) "buffer/from-bytes 1")
|
(assert (deep= @"" (buffer/from-bytes)) "buffer/from-bytes 1")
|
||||||
(assert (deep= @"ABC" (buffer/from-bytes 65 66 67)) "buffer/from-bytes 2")
|
(assert (deep= @"ABC" (buffer/from-bytes 65 66 67)) "buffer/from-bytes 2")
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
(import ./helper :prefix "" :exit true)
|
(import ./helper :prefix "" :exit true)
|
||||||
(start-suite)
|
(start-suite)
|
||||||
|
|
||||||
|
(def test-port (os/getenv "JANET_TEST_PORT" "8761"))
|
||||||
|
(def test-host (os/getenv "JANET_TEST_HOST" "127.0.0.1"))
|
||||||
|
|
||||||
# Subprocess
|
# Subprocess
|
||||||
# 5e1a8c86f
|
# 5e1a8c86f
|
||||||
(def janet (dyn *executable*))
|
(def janet (dyn *executable*))
|
||||||
@@ -192,11 +195,11 @@
|
|||||||
(net/write stream b)
|
(net/write stream b)
|
||||||
(buffer/clear b)))
|
(buffer/clear b)))
|
||||||
|
|
||||||
(def s (net/server "127.0.0.1" "8000" handler))
|
(def s (net/server test-host test-port handler))
|
||||||
(assert s "made server 1")
|
(assert s "made server 1")
|
||||||
|
|
||||||
(defn test-echo [msg]
|
(defn test-echo [msg]
|
||||||
(with [conn (net/connect "127.0.0.1" "8000")]
|
(with [conn (net/connect test-host test-port)]
|
||||||
(net/write conn msg)
|
(net/write conn msg)
|
||||||
(def res (net/read conn 1024))
|
(def res (net/read conn 1024))
|
||||||
(assert (= (string res) msg) (string "echo " msg))))
|
(assert (= (string res) msg) (string "echo " msg))))
|
||||||
@@ -216,18 +219,18 @@
|
|||||||
# prevent immediate close
|
# prevent immediate close
|
||||||
(ev/read stream 1)
|
(ev/read stream 1)
|
||||||
(def [host port] (net/localname stream))
|
(def [host port] (net/localname stream))
|
||||||
(assert (= host "127.0.0.1") "localname host server")
|
(assert (= host test-host) "localname host server")
|
||||||
(assert (= port 8000) "localname port server")))
|
(assert (= port (scan-number test-port)) "localname port server")))
|
||||||
|
|
||||||
# Test localname and peername
|
# Test localname and peername
|
||||||
# 077bf5eba
|
# 077bf5eba
|
||||||
(repeat 10
|
(repeat 10
|
||||||
(with [s (net/server "127.0.0.1" "8000" names-handler)]
|
(with [s (net/server test-host test-port names-handler)]
|
||||||
(repeat 10
|
(repeat 10
|
||||||
(with [conn (net/connect "127.0.0.1" "8000")]
|
(with [conn (net/connect test-host test-port)]
|
||||||
(def [host port] (net/peername conn))
|
(def [host port] (net/peername conn))
|
||||||
(assert (= host "127.0.0.1") "peername host client ")
|
(assert (= host test-host) "peername host client ")
|
||||||
(assert (= port 8000) "peername port client")
|
(assert (= port (scan-number test-port)) "peername port client")
|
||||||
# let server close
|
# let server close
|
||||||
(ev/write conn " "))))
|
(ev/write conn " "))))
|
||||||
(gccollect))
|
(gccollect))
|
||||||
@@ -366,4 +369,10 @@
|
|||||||
(exec-slurp ;run janet "-e" "(print :hi)")))
|
(exec-slurp ;run janet "-e" "(print :hi)")))
|
||||||
"exec-slurp 1"))
|
"exec-slurp 1"))
|
||||||
|
|
||||||
|
# valgrind-able check for #1337
|
||||||
|
(def superv (ev/chan 10))
|
||||||
|
(def f (ev/go |(ev/sleep 1e9) nil superv))
|
||||||
|
(ev/cancel f (gensym))
|
||||||
|
(ev/take superv)
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|||||||
@@ -96,11 +96,23 @@
|
|||||||
(assert (= (in buf 0) 0) "cryptorand doesn't overwrite buffer")
|
(assert (= (in buf 0) 0) "cryptorand doesn't overwrite buffer")
|
||||||
(assert (= (length buf) 2) "cryptorand appends to buffer"))
|
(assert (= (length buf) 2) "cryptorand appends to buffer"))
|
||||||
|
|
||||||
|
(assert-no-error "realtime clock" (os/clock))
|
||||||
|
(assert-no-error "realtime clock" (os/clock nil))
|
||||||
|
(assert-no-error "realtime clock" (os/clock nil nil))
|
||||||
|
|
||||||
# 80db68210
|
# 80db68210
|
||||||
(assert-no-error "realtime clock" (os/clock :realtime))
|
(assert-no-error "realtime clock" (os/clock :realtime))
|
||||||
(assert-no-error "cputime clock" (os/clock :cputime))
|
(assert-no-error "cputime clock" (os/clock :cputime))
|
||||||
(assert-no-error "monotonic clock" (os/clock :monotonic))
|
(assert-no-error "monotonic clock" (os/clock :monotonic))
|
||||||
|
|
||||||
|
(assert-no-error "realtime clock double output" (os/clock nil :double))
|
||||||
|
(assert-no-error "realtime clock int output" (os/clock nil :int))
|
||||||
|
(assert-no-error "realtime clock tuple output" (os/clock nil :tuple))
|
||||||
|
|
||||||
|
(assert-error "invalid clock" (os/clock :a))
|
||||||
|
(assert-error "invalid output" (os/clock :realtime :b))
|
||||||
|
(assert-error "invalid clock and output" (os/clock :a :b))
|
||||||
|
|
||||||
(def before (os/clock :monotonic))
|
(def before (os/clock :monotonic))
|
||||||
(def after (os/clock :monotonic))
|
(def after (os/clock :monotonic))
|
||||||
(assert (>= after before) "monotonic clock is monotonic")
|
(assert (>= after before) "monotonic clock is monotonic")
|
||||||
@@ -148,4 +160,3 @@
|
|||||||
{:out dn :err dn})))
|
{:out dn :err dn})))
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
|||||||
@@ -263,6 +263,9 @@
|
|||||||
(marshpeg '(if-not "abcdf" 123))
|
(marshpeg '(if-not "abcdf" 123))
|
||||||
(marshpeg ~(cmt "abcdf" ,identity))
|
(marshpeg ~(cmt "abcdf" ,identity))
|
||||||
(marshpeg '(group "abc"))
|
(marshpeg '(group "abc"))
|
||||||
|
(marshpeg '(sub "abcdf" "abc"))
|
||||||
|
(marshpeg '(* (sub 1 1)))
|
||||||
|
(marshpeg '(split "," (+ "a" "b" "c")))
|
||||||
|
|
||||||
# Peg swallowing errors
|
# Peg swallowing errors
|
||||||
# 159651117
|
# 159651117
|
||||||
@@ -660,5 +663,98 @@
|
|||||||
(peg/match '(if (not (* (constant 7) "a")) "hello") "hello")
|
(peg/match '(if (not (* (constant 7) "a")) "hello") "hello")
|
||||||
@[]) "peg if not")
|
@[]) "peg if not")
|
||||||
|
|
||||||
|
(defn test [name peg input expected]
|
||||||
|
(assert (deep= (peg/match peg input) expected) name))
|
||||||
|
|
||||||
|
(test "sub: matches the same input twice"
|
||||||
|
~(sub "abcd" "abc")
|
||||||
|
"abcdef"
|
||||||
|
@[])
|
||||||
|
|
||||||
|
(test "sub: second pattern cannot match more than the first pattern"
|
||||||
|
~(sub "abcd" "abcde")
|
||||||
|
"abcdef"
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(test "sub: fails if first pattern fails"
|
||||||
|
~(sub "x" "abc")
|
||||||
|
"abcdef"
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(test "sub: fails if second pattern fails"
|
||||||
|
~(sub "abc" "x")
|
||||||
|
"abcdef"
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(test "sub: keeps captures from both patterns"
|
||||||
|
~(sub '"abcd" '"abc")
|
||||||
|
"abcdef"
|
||||||
|
@["abcd" "abc"])
|
||||||
|
|
||||||
|
(test "sub: second pattern can reference captures from first"
|
||||||
|
~(* (constant 5 :tag) (sub (capture "abc" :tag) (backref :tag)))
|
||||||
|
"abcdef"
|
||||||
|
@[5 "abc" "abc"])
|
||||||
|
|
||||||
|
(test "sub: second pattern can't see past what the first pattern matches"
|
||||||
|
~(sub "abc" (* "abc" -1))
|
||||||
|
"abcdef"
|
||||||
|
@[])
|
||||||
|
|
||||||
|
(test "sub: positions inside second match are still relative to the entire input"
|
||||||
|
~(* "one\ntw" (sub "o" (* ($) (line) (column))))
|
||||||
|
"one\ntwo\nthree\n"
|
||||||
|
@[6 2 3])
|
||||||
|
|
||||||
|
(test "sub: advances to the end of the first pattern's match"
|
||||||
|
~(* (sub "abc" "ab") "d")
|
||||||
|
"abcdef"
|
||||||
|
@[])
|
||||||
|
|
||||||
|
(test "split: basic functionality"
|
||||||
|
~(split "," '1)
|
||||||
|
"a,b,c"
|
||||||
|
@["a" "b" "c"])
|
||||||
|
|
||||||
|
(test "split: drops captures from separator pattern"
|
||||||
|
~(split '"," '1)
|
||||||
|
"a,b,c"
|
||||||
|
@["a" "b" "c"])
|
||||||
|
|
||||||
|
(test "split: can match empty subpatterns"
|
||||||
|
~(split "," ':w*)
|
||||||
|
",a,,bar,,,c,,"
|
||||||
|
@["" "a" "" "bar" "" "" "c" "" ""])
|
||||||
|
|
||||||
|
(test "split: subpattern is limited to only text before the separator"
|
||||||
|
~(split "," '(to -1))
|
||||||
|
"a,,bar,c"
|
||||||
|
@["a" "" "bar" "c"])
|
||||||
|
|
||||||
|
(test "split: fails if any subpattern fails"
|
||||||
|
~(split "," '"a")
|
||||||
|
"a,a,b"
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(test "split: separator does not have to match anything"
|
||||||
|
~(split "x" '(to -1))
|
||||||
|
"a,a,b"
|
||||||
|
@["a,a,b"])
|
||||||
|
|
||||||
|
(test "split: always consumes entire input"
|
||||||
|
~(split 1 '"")
|
||||||
|
"abc"
|
||||||
|
@["" "" "" ""])
|
||||||
|
|
||||||
|
(test "split: separator can be an arbitrary PEG"
|
||||||
|
~(split :s+ '(to -1))
|
||||||
|
"a b c"
|
||||||
|
@["a" "b" "c"])
|
||||||
|
|
||||||
|
(test "split: does not advance past the end of the input"
|
||||||
|
~(* (split "," ':w+) 0)
|
||||||
|
"a,b,c"
|
||||||
|
@["a" "b" "c"])
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
|||||||
@@ -198,5 +198,9 @@
|
|||||||
|
|
||||||
(assert (= (test) '(1 ())) "issue #919")
|
(assert (= (test) '(1 ())) "issue #919")
|
||||||
|
|
||||||
(end-suite)
|
# Regression #1327
|
||||||
|
(def x "A")
|
||||||
|
(def x (if (= nil x) "B" x))
|
||||||
|
(assert (= x "A"))
|
||||||
|
|
||||||
|
(end-suite)
|
||||||
|
|||||||
Reference in New Issue
Block a user