1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-21 09:44:49 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Calvin Rose
1808c923bf Make negative indexing work like python.
This would break a lot of code :|
2023-07-14 17:18:20 -05:00
66 changed files with 1307 additions and 2729 deletions

View File

@@ -1,4 +1,4 @@
image: freebsd/14.x image: freebsd/12.x
sources: sources:
- https://git.sr.ht/~bakpakin/janet - https://git.sr.ht/~bakpakin/janet
packages: packages:
@@ -9,4 +9,3 @@ tasks:
gmake gmake
gmake test gmake test
sudo gmake install sudo gmake install
sudo gmake uninstall

View File

@@ -11,7 +11,6 @@ tasks:
gmake test gmake test
doas gmake install doas gmake install
gmake test-install gmake test-install
doas gmake uninstall
- meson_min: | - meson_min: |
cd janet cd janet
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
@@ -30,3 +29,4 @@ tasks:
ninja ninja
ninja test ninja test
doas ninja install doas ninja install

View File

@@ -56,7 +56,7 @@ jobs:
gcc gcc
- name: Build the project - name: Build the project
shell: cmd shell: cmd
run: make -j4 CC=gcc JANET_NO_AMALG=1 run: make -j CC=gcc
test-mingw-linux: test-mingw-linux:
name: Build and test with Mingw on Linux + Wine name: Build and test with Mingw on Linux + Wine

6
.gitignore vendored
View File

@@ -34,11 +34,8 @@ local
# Common test files I use. # Common test files I use.
temp.janet temp.janet
temp.c temp*.janet
temp*janet
temp*.c
scratch.janet scratch.janet
scratch.c
# Emscripten # Emscripten
*.bc *.bc
@@ -60,7 +57,6 @@ xxd.exe
# VSCode # VSCode
.vs .vs
.clangd .clangd
.cache
# Swap files # Swap files
*.swp *.swp

View File

@@ -1,67 +1,7 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## 1.34.0 - 2024-03-22 ## Unreleased - ???
- 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
- Add `array/weak` for weak references in arrays
- Add support for weak tables via `table/weak`, `table/weak-keys`, and `table/weak-values`.
- Fix compiler bug with using the result of `(break x)` expression in some contexts.
- Rework internal event loop code to be better behaved on Windows
- Update meson build to work better on windows
## 1.31.0 - 2023-09-17
- Report line and column when using `janet_dobytes`
- Add `:unless` loop modifier
- Allow calling `reverse` on generators.
- Improve performance of a number of core functions including `partition`, `mean`, `keys`, `values`, `pairs`, `interleave`.
- Add `lengthable?`
- Add `os/sigaction`
- Change `every?` and `any?` to behave like the functional versions of the `and` and `or` macros.
- Fix bug with garbage collecting threaded abstract types.
- Add `:signal` to the `sandbox` function to allow intercepting signals.
## 1.30.0 - 2023-08-05
- Change indexing of `array/remove` to start from -1 at the end instead of -2.
- Add new string escape sequences `\\a`, `\\b`, `\\?`, and `\\'`. - Add new string escape sequences `\\a`, `\\b`, `\\?`, and `\\'`.
- Fix bug with marshalling channels - Fix bug with marshalling channels
- Add `div` for floored division - Add `div` for floored division

View File

@@ -33,7 +33,6 @@ 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
@@ -43,17 +42,14 @@ 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,
# For cross compilation # For cross compilation
HOSTCC?=$(CC) HOSTCC?=$(CC)
HOSTAR?=$(AR) HOSTAR?=$(AR)
# 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
@@ -96,17 +92,12 @@ 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_STATIC_LIBRARY) build/janet.h all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.h
ifeq ($(HAS_SHARED), 1)
all: $(JANET_LIBRARY)
endif
###################### ######################
##### Name Files ##### ##### Name Files #####
@@ -204,9 +195,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
######################## ########################
ifeq ($(UNAME), Darwin) ifeq ($(UNAME), Darwin)
SONAME=libjanet.1.34.dylib SONAME=libjanet.1.29.dylib
else else
SONAME=libjanet.so.1.34 SONAME=libjanet.so.1.29
endif endif
build/c/shell.c: src/mainclient/shell.c build/c/shell.c: src/mainclient/shell.c
@@ -228,7 +219,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) $(LIBJANET_LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS) $(HOSTCC) $(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 $@ $^
@@ -271,25 +262,20 @@ 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_STATIC_LIBRARY) \ janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(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/
strip -x -S 'build/$(JANET_DIST_DIR)/bin/janet'
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_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/ cp $(JANET_LIBRARY) $(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 #####
@@ -343,7 +329,6 @@ 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)
@@ -379,7 +364,7 @@ build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
$(RUN) $(JANET_TARGET) $< > $@ $(RUN) $(JANET_TARGET) $< > $@
compile-commands: compile-commands:
# Requires pip install compiledb # Requires pip install copmiledb
compiledb make compiledb make
clean: clean:

View File

@@ -383,7 +383,7 @@ Usually, one of a few reasons:
### Can I bind to Rust/Zig/Go/Java/Nim/C++/D/Pascal/Fortran/Odin/Jai/(Some new "Systems" Programming Language)? ### Can I bind to Rust/Zig/Go/Java/Nim/C++/D/Pascal/Fortran/Odin/Jai/(Some new "Systems" Programming Language)?
Probably, if that language has a good interface with C. But the programmer may need to do Probably, if that language has a good interface with C. But the programmer may need to do
some extra work to map Janet's internal memory model to that of the bound language. Janet some extra work to map Janet's internal memory model may need some to that of the bound language. Janet
also uses `setjmp`/`longjmp` for non-local returns internally. This also uses `setjmp`/`longjmp` for non-local returns internally. This
approach is out of favor with many programmers now and doesn't always play well with other languages approach is out of favor with many programmers now and doesn't always play well with other languages
that have exceptions or stack-unwinding. that have exceptions or stack-unwinding.

View File

@@ -41,32 +41,32 @@ if not exist build\boot mkdir build\boot
@rem Build the bootstrap interpreter @rem Build the bootstrap interpreter
for %%f in (src\core\*.c) do ( for %%f in (src\core\*.c) do (
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f %JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
) )
for %%f in (src\boot\*.c) do ( for %%f in (src\boot\*.c) do (
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f %JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
) )
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj %JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
build\janet_boot . > build\c\janet.c build\janet_boot . > build\c\janet.c
@rem Build the sources @rem Build the sources
%JANET_COMPILE% /Fobuild\janet.obj build\c\janet.c %JANET_COMPILE% /Fobuild\janet.obj build\c\janet.c
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
%JANET_COMPILE% /Fobuild\shell.obj src\mainclient\shell.c %JANET_COMPILE% /Fobuild\shell.obj src\mainclient\shell.c
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
@rem Build the resources @rem Build the resources
rc /nologo /fobuild\janet_win.res janet_win.rc rc /nologo /fobuild\janet_win.res janet_win.rc
@rem Link everything to main client @rem Link everything to main client
%JANET_LINK% /out:janet.exe build\janet.obj build\shell.obj build\janet_win.res %JANET_LINK% /out:janet.exe build\janet.obj build\shell.obj build\janet_win.res
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
@rem Build static library (libjanet.lib) @rem Build static library (libjanet.a)
%JANET_LINK_STATIC% /out:build\libjanet.lib build\janet.obj %JANET_LINK_STATIC% /out:build\libjanet.lib build\janet.obj
@if not errorlevel 0 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
echo === Successfully built janet.exe for Windows === echo === Successfully built janet.exe for Windows ===
echo === Run 'build_win test' to run tests. == echo === Run 'build_win test' to run tests. ==
@@ -91,16 +91,14 @@ exit /b 0
:CLEAN :CLEAN
del *.exe *.lib *.exp del *.exe *.lib *.exp
rd /s /q build rd /s /q build
if exist dist ( rd /s /q dist
rd /s /q dist
)
exit /b 0 exit /b 0
@rem Run tests @rem Run tests
:TEST :TEST
for %%f in (test/suite*.janet) do ( for %%f in (test/suite*.janet) do (
janet.exe test\%%f janet.exe test\%%f
@if not errorlevel 0 goto TESTFAIL @if errorlevel 1 goto TESTFAIL
) )
exit /b 0 exit /b 0
@@ -119,7 +117,6 @@ copy README.md dist\README.md
copy janet.lib dist\janet.lib copy janet.lib dist\janet.lib
copy janet.exp dist\janet.exp copy janet.exp dist\janet.exp
copy janet.def dist\janet.def
janet.exe tools\patch-header.janet src\include\janet.h src\conf\janetconf.h build\janet.h janet.exe tools\patch-header.janet src\include\janet.h src\conf\janetconf.h build\janet.h
copy build\janet.h dist\janet.h copy build\janet.h dist\janet.h

View File

@@ -1,5 +0,0 @@
# Switch to python
(print "running in Janet")
(os/posix-exec ["python"] :p)
(print "will not print")

View File

@@ -1,41 +0,0 @@
###
### Usage: janet examples/sigaction.janet 1|2|3|4 &
###
### Then at shell: kill -s SIGTERM $!
###
(defn action
[]
(print "Handled SIGTERM!")
(flush)
(os/exit 1))
(defn main1
[]
(os/sigaction :term action true)
(forever))
(defn main2
[]
(os/sigaction :term action)
(forever))
(defn main3
[]
(os/sigaction :term action true)
(forever (ev/sleep math/inf)))
(defn main4
[]
(os/sigaction :term action)
(forever (ev/sleep math/inf)))
(defn main
[& args]
(def which (scan-number (get args 1 "1")))
(case which
1 (main1) # should work
2 (main2) # will not work
3 (main3) # should work
4 (main4) # should work
(error "bad main")))

View File

@@ -1,20 +0,0 @@
(def weak-k (table/weak-keys 10))
(def weak-v (table/weak-values 10))
(def weak-kv (table/weak 10))
(put weak-kv (gensym) 10)
(put weak-kv :hello :world)
(put weak-k :abc123zz77asda :stuff)
(put weak-k true :abc123zz77asda)
(put weak-k :zyzzyz false)
(put weak-v (gensym) 10)
(put weak-v 20 (gensym))
(print "before gc")
(tracev weak-k)
(tracev weak-v)
(tracev weak-kv)
(gccollect)
(print "after gc")
(tracev weak-k)
(tracev weak-v)
(tracev weak-kv)

View File

@@ -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.34.0') version : '1.29.1')
# Global settings # Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet') janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
@@ -61,7 +61,6 @@ 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'))
@@ -79,7 +78,6 @@ 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
@@ -171,7 +169,7 @@ janet_boot = executable('janet-boot', core_src, boot_src,
# Build janet.c # Build janet.c
janetc = custom_target('janetc', janetc = custom_target('janetc',
input : [janet_boot, 'src/boot/boot.janet'], input : [janet_boot],
output : 'janet.c', output : 'janet.c',
capture : true, capture : true,
command : [ command : [
@@ -184,41 +182,25 @@ if not get_option('single_threaded')
janet_dependencies += thread_dep janet_dependencies += thread_dep
endif endif
# Allow building with no shared library libjanet = library('janet', janetc,
if cc.has_argument('-fvisibility=hidden') include_directories : incdir,
lib_cflags = ['-fvisibility=hidden'] dependencies : janet_dependencies,
else version: meson.project_version(),
lib_cflags = [] soversion: version_parts[0] + '.' + version_parts[1],
endif install : true)
if get_option('shared')
libjanet = library('janet', janetc,
include_directories : incdir,
dependencies : janet_dependencies,
version: meson.project_version(),
soversion: version_parts[0] + '.' + version_parts[1],
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']
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
# No shared library extra_cflags = []
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', janetc, mainclient_src,
include_directories : incdir,
dependencies : janet_dependencies,
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)
@@ -282,15 +264,14 @@ 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)
if get_option('shared') janet_dep = declare_dependency(include_directories : incdir,
janet_dep = declare_dependency(include_directories : incdir, link_with : libjanet)
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')
@@ -300,12 +281,11 @@ patched_janet = custom_target('patched-janeth',
install : true, install : true,
install_dir : join_paths(get_option('includedir'), 'janet'), install_dir : join_paths(get_option('includedir'), 'janet'),
build_by_default : true, build_by_default : true,
output : ['janet_' + meson.project_version() + '.h'], output : ['janet.h'],
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@']) command : [janet_nativeclient, '@INPUT@', '@OUTPUT@'])
# Create a version of the janet.h header that matches what jpm often expects # Create a version of the janet.h header that matches what jpm often expects
if meson.version().version_compare('>=0.61') if meson.version().version_compare('>=0.61')
install_symlink('janet.h', pointing_to: 'janet/janet_' + meson.project_version() + '.h', install_dir: get_option('includedir')) install_symlink('janet.h', pointing_to: 'janet/janet.h', install_dir: get_option('includedir'))
install_symlink('janet.h', pointing_to: 'janet_' + meson.project_version() + '.h', install_dir: join_paths(get_option('includedir'), 'janet'))
endif endif

View File

@@ -11,15 +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 : true) option('epoll', type : 'boolean', value : false)
option('kqueue', type : 'boolean', value : true) option('kqueue', type : 'boolean', value : false)
option('interpreter_interrupt', type : 'boolean', value : true) option('interpreter_interrupt', type : 'boolean', value : false)
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)
@@ -30,5 +29,3 @@ 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)

View File

@@ -103,13 +103,23 @@
(defn symbol? "Check if x is a symbol." [x] (= (type x) :symbol)) (defn symbol? "Check if x is a symbol." [x] (= (type x) :symbol))
(defn keyword? "Check if x is a keyword." [x] (= (type x) :keyword)) (defn keyword? "Check if x is a keyword." [x] (= (type x) :keyword))
(defn buffer? "Check if x is a buffer." [x] (= (type x) :buffer)) (defn buffer? "Check if x is a buffer." [x] (= (type x) :buffer))
(defn function? "Check if x is a function (not a cfunction)." [x] (= (type x) :function)) (defn function? "Check if x is a function (not a cfunction)." [x]
(= (type x) :function))
(defn cfunction? "Check if x a cfunction." [x] (= (type x) :cfunction)) (defn cfunction? "Check if x a cfunction." [x] (= (type x) :cfunction))
(defn table? "Check if x a table." [x] (= (type x) :table)) (defn table? "Check if x a table." [x] (= (type x) :table))
(defn struct? "Check if x a struct." [x] (= (type x) :struct)) (defn struct? "Check if x a struct." [x] (= (type x) :struct))
(defn array? "Check if x is an array." [x] (= (type x) :array)) (defn array? "Check if x is an array." [x] (= (type x) :array))
(defn tuple? "Check if x is a tuple." [x] (= (type x) :tuple)) (defn tuple? "Check if x is a tuple." [x] (= (type x) :tuple))
(defn boolean? "Check if x is a boolean." [x] (= (type x) :boolean)) (defn boolean? "Check if x is a boolean." [x] (= (type x) :boolean))
(defn bytes? "Check if x is a string, symbol, keyword, or buffer." [x]
(def t (type x))
(if (= t :string) true (if (= t :symbol) true (if (= t :keyword) true (= t :buffer)))))
(defn dictionary? "Check if x is a table or struct." [x]
(def t (type x))
(if (= t :table) true (= t :struct)))
(defn indexed? "Check if x is an array or tuple." [x]
(def t (type x))
(if (= t :array) true (= t :tuple)))
(defn truthy? "Check if x is truthy." [x] (if x true false)) (defn truthy? "Check if x is truthy." [x] (if x true false))
(defn true? "Check if x is true." [x] (= x true)) (defn true? "Check if x is true." [x] (= x true))
(defn false? "Check if x is false." [x] (= x false)) (defn false? "Check if x is false." [x] (= x false))
@@ -162,7 +172,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."
@@ -419,15 +429,9 @@
(error (string "expected tuple for range, got " x)))) (error (string "expected tuple for range, got " x))))
(defn- range-template (defn- range-template
[binding object kind rest op comparison] [binding object rest op comparison]
(check-indexed object) (let [[start stop step] (check-indexed object)]
(def [a b c] object) (for-template binding start stop (or step 1) comparison op [rest])))
(def [start stop step]
(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]
@@ -477,17 +481,16 @@
:repeat (with-syms [iter] :repeat (with-syms [iter]
~(do (var ,iter ,verb) (while (> ,iter 0) ,rest (-- ,iter)))) ~(do (var ,iter ,verb) (while (> ,iter 0) ,rest (-- ,iter))))
:when ~(when ,verb ,rest) :when ~(when ,verb ,rest)
:unless ~(unless ,verb ,rest)
(error (string "unexpected loop modifier " binding)))))) (error (string "unexpected loop modifier " binding))))))
# 3 term expression # 3 term expression
(def {(+ i 2) object} head) (def {(+ i 2) object} head)
(let [rest (loop1 body head (+ i 3))] (let [rest (loop1 body head (+ i 3))]
(case verb (case verb
:range (range-template binding object :range rest + <) :range (range-template binding object rest + <)
:range-to (range-template binding object :range rest + <=) :range-to (range-template binding object rest + <=)
:down (range-template binding object :down rest - >) :down (range-template binding object rest - >)
:down-to (range-template binding object :down rest - >=) :down-to (range-template binding object rest - >=)
:keys (each-template binding object :keys [rest]) :keys (each-template binding object :keys [rest])
:pairs (each-template binding object :pairs [rest]) :pairs (each-template binding object :pairs [rest])
:in (each-template binding object :each [rest]) :in (each-template binding object :each [rest])
@@ -594,10 +597,7 @@
* `:repeat n` -- repeats the next inner loop `n` times. * `:repeat n` -- repeats the next inner loop `n` times.
* `:when condition` -- only evaluates the current loop body when `condition` * `:when condition` -- only evaluates the current loop body when `condition`
is truthy. is true.
* `:unless condition` -- only evaluates the current loop body when `condition`
is falsey.
The `loop` macro always evaluates to nil. The `loop` macro always evaluates to nil.
``` ```
@@ -651,12 +651,7 @@
(defn mean (defn mean
"Returns the mean of xs. If empty, returns NaN." "Returns the mean of xs. If empty, returns NaN."
[xs] [xs]
(if (lengthable? xs) (/ (sum xs) (length xs)))
(/ (sum xs) (length xs))
(do
(var [accum total] [0 0])
(each x xs (+= accum x) (++ total))
(/ accum total))))
(defn product (defn product
"Returns the product of xs. If xs is empty, returns 1." "Returns the product of xs. If xs is empty, returns 1."
@@ -665,9 +660,6 @@
(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
@@ -676,19 +668,20 @@
(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 fal2 (if macexvar (macexvar fal) fal)) (def res (gensym))
(defn aux [i] (defn aux [i]
(if (>= i len) (if (>= i len)
tru ~(do (set ,res ,tru) true)
(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)) ,fal2) ~(if (def ,bl ,br) ,(aux (+ 2 i)))
~(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))))))))
,fal2))))) ~(do
(aux 0)) (var ,res nil)
(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))`."
@@ -707,7 +700,7 @@
4 (let [[f g h i] functions] (fn [& x] (f (g (h (i ;x)))))) 4 (let [[f g h i] functions] (fn [& x] (f (g (h (i ;x))))))
(let [[f g h i] functions] (let [[f g h i] functions]
(comp (fn [x] (f (g (h (i x))))) (comp (fn [x] (f (g (h (i x)))))
;(tuple/slice functions 4 -1))))) ;(tuple/slice functions 4)))))
(defn identity (defn identity
"A function that returns its argument." "A function that returns its argument."
@@ -719,38 +712,30 @@
[f] [f]
(fn [x] (not (f x)))) (fn [x] (not (f x))))
(defmacro- do-extreme
[order args]
~(do
(def ds ,args)
(var k (next ds nil))
(var ret (get ds k))
(while (,not= nil (set k (next ds k)))
(def x (in ds k))
(if (,order x ret) (set ret x)))
ret))
(defn extreme (defn extreme
``Returns the most extreme value in `args` based on the function `order`. ``Returns the most extreme value in `args` based on the function `order`.
`order` should take two values and return true or false (a comparison). `order` should take two values and return true or false (a comparison).
Returns nil if `args` is empty.`` Returns nil if `args` is empty.``
[order args] (do-extreme order args)) [order args]
(var [ret] args)
(each x args (if (order x ret) (set ret x)))
ret)
(defn max (defn max
"Returns the numeric maximum of the arguments." "Returns the numeric maximum of the arguments."
[& args] (do-extreme > args)) [& args] (extreme > args))
(defn min (defn min
"Returns the numeric minimum of the arguments." "Returns the numeric minimum of the arguments."
[& args] (do-extreme < args)) [& args] (extreme < args))
(defn max-of (defn max-of
"Returns the numeric maximum of the argument sequence." "Returns the numeric maximum of the argument sequence."
[args] (do-extreme > args)) [args] (extreme > args))
(defn min-of (defn min-of
"Returns the numeric minimum of the argument sequence." "Returns the numeric minimum of the argument sequence."
[args] (do-extreme < args)) [args] (extreme < args))
(defn first (defn first
"Get the first element from an indexed data structure." "Get the first element from an indexed data structure."
@@ -764,14 +749,6 @@
## Polymorphic comparisons ## Polymorphic comparisons
(defmacro- do-compare
[x y]
~(if (def f (get ,x :compare))
(f ,x ,y)
(if (def f (get ,y :compare))
(- (f ,y ,x))
(cmp ,x ,y))))
(defn compare (defn compare
``Polymorphic compare. Returns -1, 0, 1 for x < y, x = y, x > y respectively. ``Polymorphic compare. Returns -1, 0, 1 for x < y, x = y, x > y respectively.
Differs from the primitive comparators in that it first checks to Differs from the primitive comparators in that it first checks to
@@ -779,18 +756,20 @@
compare x and y. If so, it uses that method. If not, it compare x and y. If so, it uses that method. If not, it
delegates to the primitive comparators.`` delegates to the primitive comparators.``
[x y] [x y]
(do-compare x y)) (or
(when-let [f (get x :compare)] (f x y))
(when-let [f (get y :compare)] (- (f y x)))
(cmp x y)))
(defmacro- compare-reduce [op xs] (defn- compare-reduce [op xs]
~(do (var r true)
(var res true) (loop [i :range [0 (- (length xs) 1)]
(var x (get ,xs 0)) :let [c (compare (xs i) (xs (+ i 1)))
(forv i 1 (length ,xs) ok (op c 0)]
(let [y (in ,xs i)] :when (not ok)]
(if (,op (do-compare x y) 0) (set r false)
(set x y) (break))
(do (set res false) (break))))) r)
res))
(defn compare= (defn compare=
``Equivalent of `=` but using polymorphic `compare` instead of primitive comparator.`` ``Equivalent of `=` but using polymorphic `compare` instead of primitive comparator.``
@@ -830,31 +809,21 @@
### ###
### ###
(defmacro- median-of-three (defn- median-of-three [a b c]
[x y z] (if (not= (> a b) (> a c))
~(if (<= ,x ,y) a
(if (<= ,y ,z) ,y (if (<= ,z ,x) ,x ,z)) (if (not= (> b a) (> b c)) b c)))
(if (<= ,z ,y) ,y (if (<= ,x ,z) ,x ,z))))
(defmacro- sort-partition-template
[ind before? left right pivot]
~(do
(while (,before? (in ,ind ,left) ,pivot) (++ ,left))
(while (,before? ,pivot (in ,ind ,right)) (-- ,right))))
(defn- sort-help [a lo hi before?] (defn- sort-help [a lo hi before?]
(when (< lo hi) (when (< lo hi)
(def [x y z] [(in a lo) (def pivot
(in a (div (+ lo hi) 2)) (median-of-three (in a hi) (in a lo)
(in a hi)]) (in a (math/floor (/ (+ lo hi) 2)))))
(def pivot (median-of-three x y z))
(var left lo) (var left lo)
(var right hi) (var right hi)
(while true (while true
(case before? (while (before? (in a left) pivot) (++ left))
< (sort-partition-template a < left right pivot) (while (before? pivot (in a right)) (-- right))
> (sort-partition-template a > left right pivot)
(sort-partition-template a before? left right pivot))
(when (<= left right) (when (<= left right)
(def tmp (in a left)) (def tmp (in a left))
(set (a left) (in a right)) (set (a left) (in a right))
@@ -862,10 +831,8 @@
(++ left) (++ left)
(-- right)) (-- right))
(if (>= left right) (break))) (if (>= left right) (break)))
(if (< lo right) (sort-help a lo right before?)
(sort-help a lo right before?)) (sort-help a left hi before?))
(if (< left hi)
(sort-help a left hi before?)))
a) a)
(defn sort (defn sort
@@ -873,8 +840,7 @@
If a `before?` comparator function is provided, sorts elements using that, If a `before?` comparator function is provided, sorts elements using that,
otherwise uses `<`.`` otherwise uses `<`.``
[ind &opt before?] [ind &opt before?]
(default before? <) (sort-help ind 0 (- (length ind) 1) (or before? <)))
(sort-help ind 0 (- (length ind) 1) before?))
(defn sort-by (defn sort-by
``Sorts `ind` in-place by calling a function `f` on each element and ``Sorts `ind` in-place by calling a function `f` on each element and
@@ -981,6 +947,7 @@
1 (map-n 1 ,maptype ,res ,f ,ind ,inds) 1 (map-n 1 ,maptype ,res ,f ,ind ,inds)
2 (map-n 2 ,maptype ,res ,f ,ind ,inds) 2 (map-n 2 ,maptype ,res ,f ,ind ,inds)
3 (map-n 3 ,maptype ,res ,f ,ind ,inds) 3 (map-n 3 ,maptype ,res ,f ,ind ,inds)
4 (map-n 4 ,maptype ,res ,f ,ind ,inds)
(do (do
(def iter-keys (array/new-filled ninds)) (def iter-keys (array/new-filled ninds))
(def call-buffer (array/new-filled ninds)) (def call-buffer (array/new-filled ninds))
@@ -1040,6 +1007,30 @@
(map-template :keep res pred ind inds) (map-template :keep res pred ind inds)
res) res)
(defn range
`Create an array of values [start, end) with a given step.
With one argument, returns a range [0, end). With two arguments, returns
a range [start, end). With three, returns a range with optional step size.`
[& args]
(case (length args)
1 (do
(def [n] args)
(def arr (array/new n))
(forv i 0 n (put arr i i))
arr)
2 (do
(def [n m] args)
(def arr (array/new (- m n)))
(forv i n m (put arr (- i n) i))
arr)
3 (do
(def [n m s] args)
(cond
(zero? s) @[]
(neg? s) (seq [i :down [n m (- s)]] i)
(seq [i :range [n m s]] i)))
(error "expected 1 to 3 arguments to range")))
(defn find-index (defn find-index
``Find the index of indexed type for which `pred` is true. Returns `dflt` if not found.`` ``Find the index of indexed type for which `pred` is true. Returns `dflt` if not found.``
[pred ind &opt dflt] [pred ind &opt dflt]
@@ -1217,7 +1208,7 @@
(assert (symbol? alias) "alias must be a symbol") (assert (symbol? alias) "alias must be a symbol")
(assert (and (> (length alias) 2) (= 42 (first alias) (last alias))) "name must have leading and trailing '*' characters") (assert (and (> (length alias) 2) (= 42 (first alias) (last alias))) "name must have leading and trailing '*' characters")
(def prefix (dyn :defdyn-prefix)) (def prefix (dyn :defdyn-prefix))
(def kw (keyword prefix (slice alias 1 -2))) (def kw (keyword prefix (slice alias 1 -1)))
~(def ,alias :dyn ,;more ,kw)) ~(def ,alias :dyn ,;more ,kw))
(defn has-key? (defn has-key?
@@ -1238,7 +1229,7 @@
(defdyn *debug* "Enables a built in debugger on errors and other useful features for debugging in a repl.") (defdyn *debug* "Enables a built in debugger on errors and other useful features for debugging in a repl.")
(defdyn *exit* "When set, will cause the current context to complete. Can be set to exit from repl (or file), for example.") (defdyn *exit* "When set, will cause the current context to complete. Can be set to exit from repl (or file), for example.")
(defdyn *exit-value* "Set the return value from `run-context` upon an exit. By default, `run-context` will return nil.") (defdyn *exit-value* "Set the return value from `run-context` upon an exit. By default, `run-context` will return nil.")
(defdyn *task-id* "When spawning a thread or fiber, the task-id can be assigned for concurrency control.") (defdyn *task-id* "When spawning a thread or fiber, the task-id can be assigned for concurrecny control.")
(defdyn *macro-form* (defdyn *macro-form*
"Inside a macro, is bound to the source form that invoked the macro") "Inside a macro, is bound to the source form that invoked the macro")
@@ -1273,7 +1264,7 @@
(defn keep-syntax (defn keep-syntax
``Creates a tuple with the tuple type and sourcemap of `before` but the ``Creates a tuple with the tuple type and sourcemap of `before` but the
elements of `after`. If either one of its arguments is not a tuple, returns elements of `after`. If either one of its argements is not a tuple, returns
`after` unmodified. Useful to preserve syntactic information when transforming `after` unmodified. Useful to preserve syntactic information when transforming
an ast in macros.`` an ast in macros.``
[before after] [before after]
@@ -1448,50 +1439,48 @@
(fn [& r] (f ;more ;r)))) (fn [& r] (f ;more ;r))))
(defn every? (defn every?
``Evaluates to the last element of `ind` if all preceding elements are truthy, ``Returns true if each value in `ind` is truthy, otherwise returns the first
otherwise evaluates to the first falsey element.`` falsey value.``
[ind] [ind]
(var res true) (var res true)
(loop [x :in ind :while res] (loop [x :in ind :while res]
(set res x)) (if x nil (set res x)))
res) res)
(defn any? (defn any?
``Evaluates to the last element of `ind` if all preceding elements are falsey, ``Returns the first truthy value in `ind`, otherwise nil.``
otherwise evaluates to the first truthy element.``
[ind] [ind]
(var res nil) (var res nil)
(loop [x :in ind :until res] (loop [x :in ind :until res]
(set res x)) (if x (set res x)))
res) res)
(defn reverse! (defn reverse!
`Reverses the order of the elements in a given array or buffer and returns it `Reverses the order of the elements in a given array or buffer and returns it
mutated.` mutated.`
[t] [t]
(var i 0) (def len-1 (- (length t) 1))
(var j (length t)) (def half (/ len-1 2))
(while (< i (-- j)) (forv i 0 half
(def ti (in t i)) (def j (- len-1 i))
(put t i (in t j)) (def l (in t i))
(put t j ti) (def r (in t j))
(++ i)) (put t i r)
(put t j l))
t) t)
(defn reverse (defn reverse
`Reverses the order of the elements in a given array or tuple and returns `Reverses the order of the elements in a given array or tuple and returns
a new array. If a string or buffer is provided, returns a buffer instead.` a new array. If a string or buffer is provided, returns an array of its
byte values, reversed.`
[t] [t]
(if (lengthable? t) (def len (length t))
(do (var n (- len 1))
(var n (length t)) (def ret (array/new len))
(def ret (if (bytes? t) (while (>= n 0)
(buffer/new-filled n) (array/push ret (in t n))
(array/new-filled n))) (-- n))
(each v t ret)
(put ret (-- n) v))
ret)
(reverse! (seq [v :in t] v))))
(defn invert (defn invert
``Given an associative data structure `ds`, returns a new table where the ``Given an associative data structure `ds`, returns a new table where the
@@ -1601,41 +1590,32 @@
(defn keys (defn keys
"Get the keys of an associative data structure." "Get the keys of an associative data structure."
[x] [x]
(if (lengthable? x) (def arr @[])
(do (var k (next x nil))
(def arr (array/new-filled (length x))) (while (not= nil k)
(var i 0) (array/push arr k)
(eachk k x (set k (next x k)))
(put arr i k) arr)
(++ i))
arr)
(seq [k :keys x] k)))
(defn values (defn values
"Get the values of an associative data structure." "Get the values of an associative data structure."
[x] [x]
(if (lengthable? x) (def arr @[])
(do (var k (next x nil))
(def arr (array/new-filled (length x))) (while (not= nil k)
(var i 0) (array/push arr (in x k))
(each v x (set k (next x k)))
(put arr i v) arr)
(++ i))
arr)
(seq [v :in x] v)))
(defn pairs (defn pairs
"Get the key-value pairs of an associative data structure." "Get the key-value pairs of an associative data structure."
[x] [x]
(if (lengthable? x) (def arr @[])
(do (var k (next x nil))
(def arr (array/new-filled (length x))) (while (not= nil k)
(var i 0) (array/push arr (tuple k (in x k)))
(eachp p x (set k (next x k)))
(put arr i p) arr)
(++ i))
arr)
(seq [p :pairs x] p)))
(defn frequencies (defn frequencies
"Get the number of occurrences of each value in an indexed data structure." "Get the number of occurrences of each value in an indexed data structure."
@@ -1680,7 +1660,14 @@
(defn interleave (defn interleave
"Returns an array of the first elements of each col, then the second elements, etc." "Returns an array of the first elements of each col, then the second elements, etc."
[& cols] [& cols]
(mapcat tuple ;cols)) (def res @[])
(def ncol (length cols))
(when (> ncol 0)
(def len (min ;(map length cols)))
(loop [i :range [0 len]
ci :range [0 ncol]]
(array/push res (in (in cols ci) i))))
res)
(defn distinct (defn distinct
"Returns an array of the deduplicated values in `xs`." "Returns an array of the deduplicated values in `xs`."
@@ -1727,46 +1714,29 @@
``Returns a sequence of the elements of `ind` separated by ``Returns a sequence of the elements of `ind` separated by
`sep`. Returns a new array.`` `sep`. Returns a new array.``
[sep ind] [sep ind]
(var k (next ind nil))
(if (not= nil k)
(if (lengthable? ind)
(do
(def ret (array/new-filled (- (* 2 (length ind)) 1) sep))
(var i 0)
(while (not= nil k)
(put ret i (in ind k))
(set k (next ind k))
(+= i 2))
ret)
(do
(def ret @[(in ind k)])
(while (not= nil (set k (next ind k)))
(array/push ret sep (in ind k)))
ret))
@[]))
(defn- partition-slice
[f n ind]
(var [start end] [0 n])
(def len (length ind)) (def len (length ind))
(def parts (div len n)) (def ret (array/new (- (* 2 len) 1)))
(def ret (array/new-filled parts)) (if (> len 0) (put ret 0 (in ind 0)))
(forv k 0 parts (var i 1)
(put ret k (f ind start end)) (while (< i len)
(set start end) (array/push ret sep (in ind i))
(+= end n)) (++ i))
(if (< start len)
(array/push ret (f ind start)))
ret) ret)
(defn partition (defn partition
``Partition an indexed data structure `ind` into tuples ``Partition an indexed data structure `ind` into tuples
of size `n`. Returns a new array.`` of size `n`. Returns a new array.``
[n ind] [n ind]
(cond (var i 0) (var nextn n)
(indexed? ind) (partition-slice tuple/slice n ind) (def len (length ind))
(bytes? ind) (partition-slice string/slice n ind) (def ret (array/new (math/ceil (/ len n))))
(partition-slice tuple/slice n (values ind)))) (def slicer (if (bytes? ind) string/slice tuple/slice))
(while (<= nextn len)
(array/push ret (slicer ind i nextn))
(set i nextn)
(+= nextn n))
(if (not= i len) (array/push ret (slicer ind i)))
ret)
### ###
### ###
@@ -1851,7 +1821,7 @@
# Partition body into sections. # Partition body into sections.
(def oddlen (odd? (length cases))) (def oddlen (odd? (length cases)))
(def else (if oddlen (last cases))) (def else (if oddlen (last cases)))
(def patterns (partition 2 (if oddlen (slice cases 0 -2) cases))) (def patterns (partition 2 (if oddlen (slice cases 0 -1) cases)))
# Keep an array for accumulating the compilation output # Keep an array for accumulating the compilation output
(def x-sym (if (idempotent? x) x (gensym))) (def x-sym (if (idempotent? x) x (gensym)))
@@ -2082,7 +2052,7 @@
(tuple/slice (tuple/slice
(array/concat (array/concat
@[(in t 0) (expand-bindings bound)] @[(in t 0) (expand-bindings bound)]
(tuple/slice t 2 -2) (tuple/slice t 2 -1)
@[(recur last)]))) @[(recur last)])))
(defn expandall [t] (defn expandall [t]
@@ -2129,22 +2099,21 @@
'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 (keep-syntax t (s t)) s (s t)
m? (do (setdyn *macro-form* t) (m ;(tuple/slice t 1))) m? (do (setdyn *macro-form* t) (m ;(tuple/slice t 1)))
(keep-syntax! t (map recur t)))) (tuple/slice (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)
@@ -2250,8 +2219,6 @@
(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`
@@ -2260,7 +2227,7 @@
[name & body] [name & body]
(def expansion (apply defn name body)) (def expansion (apply defn name body))
(def fbody (last expansion)) (def fbody (last expansion))
(def modifiers (tuple/slice expansion 2 -2)) (def modifiers (tuple/slice expansion 2 -1))
(def metadata @{}) (def metadata @{})
(each m modifiers (each m modifiers
(cond (cond
@@ -2342,36 +2309,26 @@
(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.`
~@{:a (range "az" "AZ") ~@{:d (range "09")
:d (range "09") :a (range "az" "AZ")
: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)
:S (if-not :s 1)
:W (if-not :w 1)
:a+ (some :a)
:d+ (some :d) :d+ (some :d)
:h+ (some :h) :a+ (some :a)
:s+ (some :s) :s+ (some :s)
:w+ (some :w) :w+ (some :w)
:A+ (some :A) :h+ (some :h)
:D+ (some :D)
:H+ (some :H)
:S+ (some :S)
:W+ (some :W)
:a* (any :a)
:d* (any :d) :d* (any :d)
:h* (any :h) :a* (any :a)
:s* (any :s)
:w* (any :w) :w* (any :w)
:A* (any :A) :s* (any :s)
:D* (any :D) :h* (any :h)})
:H* (any :H)
:S* (any :S)
:W* (any :W)})
(setdyn *peg-grammar* default-peg-grammar) (setdyn *peg-grammar* default-peg-grammar)
@@ -2767,11 +2724,6 @@
(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."
@{}) @{})
@@ -2800,25 +2752,24 @@
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))) mp) 0)) (or (find-index |(and (string? ($ 0)) (string/has-prefix? pre ($ 0))) module/paths) 0))
(def dyn-index (find-prefix ":@all:")) (def dyn-index (find-prefix ":@all:"))
(array/insert mp dyn-index [(string ":@all:" ext) loader check-dyn-relative]) (array/insert module/paths dyn-index [(string ":@all:" ext) loader check-dyn-relative])
(def all-index (find-prefix ".:all:")) (def all-index (find-prefix ".:all:"))
(array/insert mp all-index [(string ".:all:" ext) loader check-project-relative]) (array/insert module/paths all-index [(string ".:all:" ext) loader check-project-relative])
(def sys-index (find-prefix ":sys:")) (def sys-index (find-prefix ":sys:"))
(array/insert mp sys-index [(string ":sys:/:all:" ext) loader check-is-dep]) (array/insert module/paths 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 mp curall-index [(string ":cur:/:all:" ext) loader check-relative]) (array/insert module/paths curall-index [(string ":cur:/:all:" ext) loader check-relative])
mp) module/paths)
(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 (dyn *module/cache* module/cache) path) path)) :preload check-not-relative]) (array/insert module/paths 0 [(fn is-cached [path] (if (in 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
@@ -2848,8 +2799,7 @@
``` ```
[path] [path]
(var ret nil) (var ret nil)
(def mp (dyn *module/paths* module/paths)) (each [p mod-kind checker] 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)]
@@ -2865,7 +2815,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 mp)) paths (filter identity (map expander module/paths))
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)])))
@@ -2933,12 +2883,7 @@
(if (= :dead fs) (if (= :dead fs)
(when is-repl (when is-repl
(put env '_ @{:value x}) (put env '_ @{:value x})
(def pf (get env *pretty-format* "%q")) (printf (get env *pretty-format* "%q") x)
(try
(printf pf x)
([e]
(eprintf "bad pretty format %v: %v" pf e)
(eflush)))
(flush)) (flush))
(do (do
(debug/stacktrace f x "") (debug/stacktrace f x "")
@@ -2972,7 +2917,7 @@
(def buf @"") (def buf @"")
(with-dyns [*err* buf *err-color* false] (with-dyns [*err* buf *err-color* false]
(bad-parse x y)) (bad-parse x y))
(set exit-error (string/slice buf 0 -2))) (set exit-error (string/slice buf 0 -1)))
(defn bc [&opt x y z a b] (defn bc [&opt x y z a b]
(when exit (when exit
(bad-compile x y z a b) (bad-compile x y z a b)
@@ -2981,7 +2926,7 @@
(def buf @"") (def buf @"")
(with-dyns [*err* buf *err-color* false] (with-dyns [*err* buf *err-color* false]
(bad-compile x nil z a b)) (bad-compile x nil z a b))
(set exit-error (string/slice buf 0 -2)) (set exit-error (string/slice buf 0 -1))
(set exit-fiber y)) (set exit-fiber y))
(unless f (unless f
(error (string "could not find file " path))) (error (string "could not find file " path)))
@@ -3020,15 +2965,13 @@
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]
(def ml (dyn *module/loading* module/loading)) (put module/loading path true)
(put ml path true) (defer (put module/loading path nil)
(defer (put ml path nil)
(dofile path ;args))) (dofile path ;args)))
:preload (fn preload-loader [path & args] :preload (fn preload-loader [path & args]
(def mc (dyn *module/cache* module/cache)) (when-let [m (in module/cache path)]
(when-let [m (in mc path)]
(if (function? m) (if (function? m)
(set (mc path) (m path ;args)) (set (module/cache path) (m path ;args))
m))) m)))
:image (fn image-loader [path &] (load-image (slurp path)))}) :image (fn image-loader [path &] (load-image (slurp path)))})
@@ -3036,18 +2979,15 @@
[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))
(def mc (dyn *module/cache* module/cache)) (if-let [check (if-not (kargs :fresh) (in module/cache fullpath))]
(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 (ml fullpath) (if (module/loading fullpath)
(error (string "circular dependency " fullpath " detected")) (error (string "circular dependency " fullpath " detected"))
(do (do
(def loader (if (keyword? mod-kind) (mls mod-kind) mod-kind)) (def loader (if (keyword? mod-kind) (module/loaders 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 mc fullpath env) (put module/cache fullpath env)
env)))) env))))
(defn require (defn require
@@ -3748,20 +3688,12 @@
~(,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
Create a fiber to execute `body`, schedule the event loop to cancel the deadline is up, it will be canceled.`
the task (root fiber) associated with `body`'s fiber, and start [deadline & body]
`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 ,sec nil ,f) (,ev/deadline ,deadline nil ,f)
(,resume ,f)))) (,resume ,f))))
(defn- cancel-all [chan fibers reason] (defn- cancel-all [chan fibers reason]
@@ -3805,7 +3737,7 @@
[host port &opt handler type] [host port &opt handler type]
(def s (net/listen host port type)) (def s (net/listen host port type))
(if handler (if handler
(ev/go (fn [] (net/accept-loop s handler)))) (ev/call (fn [] (net/accept-loop s handler))))
s)) s))
### ###
@@ -3857,7 +3789,7 @@
"Generate bindings for native functions in a convenient manner." "Generate bindings for native functions in a convenient manner."
[name ret-type & body] [name ret-type & body]
(def real-ret-type (eval ret-type)) (def real-ret-type (eval ret-type))
(def meta (slice body 0 -2)) (def meta (slice body 0 -1))
(def arg-pairs (partition 2 (last body))) (def arg-pairs (partition 2 (last body)))
(def formal-args (map 0 arg-pairs)) (def formal-args (map 0 arg-pairs))
(def type-args (map 1 arg-pairs)) (def type-args (map 1 arg-pairs))

View File

@@ -4,10 +4,10 @@
#define JANETCONF_H #define JANETCONF_H
#define JANET_VERSION_MAJOR 1 #define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 34 #define JANET_VERSION_MINOR 29
#define JANET_VERSION_PATCH 0 #define JANET_VERSION_PATCH 1
#define JANET_VERSION_EXTRA "" #define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.34.0" #define JANET_VERSION "1.29.1"
/* #define JANET_BUILD "local" */ /* #define JANET_BUILD "local" */
@@ -52,9 +52,6 @@
/* #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> */

View File

@@ -31,6 +31,8 @@
#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
@@ -95,6 +97,14 @@ size_t janet_os_rwlock_size(void) {
return sizeof(void *); return sizeof(void *);
} }
static int32_t janet_incref(JanetAbstractHead *ab) {
return InterlockedIncrement((LONG volatile *) &ab->gc.data.refcount);
}
static int32_t janet_decref(JanetAbstractHead *ab) {
return InterlockedDecrement((LONG volatile *) &ab->gc.data.refcount);
}
void janet_os_mutex_init(JanetOSMutex *mutex) { void janet_os_mutex_init(JanetOSMutex *mutex) {
InitializeCriticalSection((CRITICAL_SECTION *) mutex); InitializeCriticalSection((CRITICAL_SECTION *) mutex);
} }
@@ -147,6 +157,14 @@ size_t janet_os_rwlock_size(void) {
return sizeof(pthread_rwlock_t); return sizeof(pthread_rwlock_t);
} }
static int32_t janet_incref(JanetAbstractHead *ab) {
return __atomic_add_fetch(&ab->gc.data.refcount, 1, __ATOMIC_RELAXED);
}
static int32_t janet_decref(JanetAbstractHead *ab) {
return __atomic_add_fetch(&ab->gc.data.refcount, -1, __ATOMIC_RELAXED);
}
void janet_os_mutex_init(JanetOSMutex *mutex) { void janet_os_mutex_init(JanetOSMutex *mutex) {
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); pthread_mutexattr_init(&attr);
@@ -194,11 +212,11 @@ void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
#endif #endif
int32_t janet_abstract_incref(void *abst) { int32_t janet_abstract_incref(void *abst) {
return janet_atomic_inc(&janet_abstract_head(abst)->gc.data.refcount); return janet_incref(janet_abstract_head(abst));
} }
int32_t janet_abstract_decref(void *abst) { int32_t janet_abstract_decref(void *abst) {
return janet_atomic_dec(&janet_abstract_head(abst)->gc.data.refcount); return janet_decref(janet_abstract_head(abst));
} }
#endif #endif

View File

@@ -30,7 +30,9 @@
#include <string.h> #include <string.h>
static void janet_array_impl(JanetArray *array, int32_t capacity) { /* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
Janet *data = NULL; Janet *data = NULL;
if (capacity > 0) { if (capacity > 0) {
janet_vm.next_collection += capacity * sizeof(Janet); janet_vm.next_collection += capacity * sizeof(Janet);
@@ -42,19 +44,6 @@ static void janet_array_impl(JanetArray *array, int32_t capacity) {
array->count = 0; array->count = 0;
array->capacity = capacity; array->capacity = capacity;
array->data = data; array->data = data;
}
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
janet_array_impl(array, capacity);
return array;
}
/* Creates a new array with weak references */
JanetArray *janet_array_weak(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY_WEAK, sizeof(JanetArray));
janet_array_impl(array, capacity);
return array; return array;
} }
@@ -143,15 +132,6 @@ JANET_CORE_FN(cfun_array_new,
return janet_wrap_array(array); return janet_wrap_array(array);
} }
JANET_CORE_FN(cfun_array_weak,
"(array/weak capacity)",
"Creates a new empty array with a pre-allocated capacity and support for weak references. Similar to `array/new`.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array_weak(cap);
return janet_wrap_array(array);
}
JANET_CORE_FN(cfun_array_new_filled, JANET_CORE_FN(cfun_array_new_filled,
"(array/new-filled count &opt value)", "(array/new-filled count &opt value)",
"Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") { "Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
@@ -197,8 +177,8 @@ JANET_CORE_FN(cfun_array_peek,
} }
JANET_CORE_FN(cfun_array_push, JANET_CORE_FN(cfun_array_push,
"(array/push arr & xs)", "(array/push arr x)",
"Push all the elements of xs to the end of an array. Modifies the input array and returns it.") { "Insert an element in the end of an array. Modifies the input array and returns it.") {
janet_arity(argc, 1, -1); janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0); JanetArray *array = janet_getarray(argv, 0);
if (INT32_MAX - argc + 1 <= array->count) { if (INT32_MAX - argc + 1 <= array->count) {
@@ -231,7 +211,7 @@ JANET_CORE_FN(cfun_array_slice,
"Takes a slice of array or tuple from `start` to `end`. The range is half open, " "Takes a slice of array or tuple from `start` to `end`. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the " "[start, end). Indexes can also be negative, indicating indexing from the "
"end of the array. By default, `start` is 0 and `end` is the length of the array. " "end of the array. By default, `start` is 0 and `end` is the length of the array. "
"Note that if the range is negative, it is taken as (start, end] to allow a full " "Note that index -1 is synonymous with index `(length arrtup)` to allow a full "
"negative slice range. Returns a new array.") { "negative slice range. Returns a new array.") {
JanetView view = janet_getindexed(argv, 0); JanetView view = janet_getindexed(argv, 0);
JanetRange range = janet_getslice(argc, argv); JanetRange range = janet_getslice(argc, argv);
@@ -279,8 +259,8 @@ JANET_CORE_FN(cfun_array_insert,
"(array/insert arr at & xs)", "(array/insert arr at & xs)",
"Insert all `xs` into array `arr` at index `at`. `at` should be an integer between " "Insert all `xs` into array `arr` at index `at`. `at` should be an integer between "
"0 and the length of the array. A negative value for `at` will index backwards from " "0 and the length of the array. A negative value for `at` will index backwards from "
"the end of the array, inserting after the index such that inserting at -1 appends to " "the end of the array, such that inserting at -1 appends to the array. "
"the array. Returns the array.") { "Returns the array.") {
size_t chunksize, restsize; size_t chunksize, restsize;
janet_arity(argc, 2, -1); janet_arity(argc, 2, -1);
JanetArray *array = janet_getarray(argv, 0); JanetArray *array = janet_getarray(argv, 0);
@@ -372,7 +352,6 @@ JANET_CORE_FN(cfun_array_clear,
void janet_lib_array(JanetTable *env) { void janet_lib_array(JanetTable *env) {
JanetRegExt array_cfuns[] = { JanetRegExt array_cfuns[] = {
JANET_CORE_REG("array/new", cfun_array_new), JANET_CORE_REG("array/new", cfun_array_new),
JANET_CORE_REG("array/weak", cfun_array_weak),
JANET_CORE_REG("array/new-filled", cfun_array_new_filled), JANET_CORE_REG("array/new-filled", cfun_array_new_filled),
JANET_CORE_REG("array/fill", cfun_array_fill), JANET_CORE_REG("array/fill", cfun_array_fill),
JANET_CORE_REG("array/pop", cfun_array_pop), JANET_CORE_REG("array/pop", cfun_array_pop),

View File

@@ -560,9 +560,6 @@ 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;
@@ -787,9 +784,8 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
} }
/* Verify the func def */ /* Verify the func def */
int verify_status = janet_verify(def); if (janet_verify(def)) {
if (verify_status) { janet_asm_error(&a, "invalid assembly");
janet_asm_errorv(&a, janet_formatc("invalid assembly (%d)", verify_status));
} }
/* Add final flags */ /* Add final flags */

View File

@@ -135,7 +135,8 @@ 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 = (int32_t) strlen(cstring); int32_t len = 0;
while (cstring[len]) ++len;
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len); janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
} }
@@ -220,20 +221,6 @@ JANET_CORE_FN(cfun_buffer_new_filled,
return janet_wrap_buffer(buffer); return janet_wrap_buffer(buffer);
} }
JANET_CORE_FN(cfun_buffer_frombytes,
"(buffer/from-bytes & byte-vals)",
"Creates a buffer from integer parameters with byte values. All integers "
"will be coerced to the range of 1 byte 0-255.") {
int32_t i;
JanetBuffer *buffer = janet_buffer(argc);
for (i = 0; i < argc; i++) {
int32_t c = janet_getinteger(argv, i);
buffer->data[i] = c & 0xFF;
}
buffer->count = argc;
return janet_wrap_buffer(buffer);
}
JANET_CORE_FN(cfun_buffer_fill, JANET_CORE_FN(cfun_buffer_fill,
"(buffer/fill buffer &opt byte)", "(buffer/fill buffer &opt byte)",
"Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. " "Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. "
@@ -320,143 +307,6 @@ 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)) {
@@ -612,15 +462,13 @@ JANET_CORE_FN(cfun_buffer_blit,
int same_buf = src.bytes == dest->data; int same_buf = src.bytes == dest->data;
int32_t offset_dest = 0; int32_t offset_dest = 0;
int32_t offset_src = 0; int32_t offset_src = 0;
if (argc > 2 && !janet_checktype(argv[2], JANET_NIL)) if (argc > 2)
offset_dest = janet_gethalfrange(argv, 2, dest->count, "dest-start"); offset_dest = janet_gethalfrange(argv, 2, dest->count, "dest-start");
if (argc > 3 && !janet_checktype(argv[3], JANET_NIL)) if (argc > 3)
offset_src = janet_gethalfrange(argv, 3, src.len, "src-start"); offset_src = janet_gethalfrange(argv, 3, src.len, "src-start");
int32_t length_src; int32_t length_src;
if (argc > 4) { if (argc > 4) {
int32_t src_end = src.len; int32_t src_end = janet_gethalfrange(argv, 4, src.len, "src-end");
if (!janet_checktype(argv[4], JANET_NIL))
src_end = janet_gethalfrange(argv, 4, src.len, "src-end");
length_src = src_end - offset_src; length_src = src_end - offset_src;
if (length_src < 0) length_src = 0; if (length_src < 0) length_src = 0;
} else { } else {
@@ -659,17 +507,11 @@ void janet_lib_buffer(JanetTable *env) {
JanetRegExt buffer_cfuns[] = { JanetRegExt buffer_cfuns[] = {
JANET_CORE_REG("buffer/new", cfun_buffer_new), JANET_CORE_REG("buffer/new", cfun_buffer_new),
JANET_CORE_REG("buffer/new-filled", cfun_buffer_new_filled), JANET_CORE_REG("buffer/new-filled", cfun_buffer_new_filled),
JANET_CORE_REG("buffer/from-bytes", cfun_buffer_frombytes),
JANET_CORE_REG("buffer/fill", cfun_buffer_fill), JANET_CORE_REG("buffer/fill", cfun_buffer_fill),
JANET_CORE_REG("buffer/trim", cfun_buffer_trim), JANET_CORE_REG("buffer/trim", cfun_buffer_trim),
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),

View File

@@ -226,7 +226,6 @@ 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:
@@ -234,8 +233,6 @@ 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 */

View File

@@ -35,13 +35,6 @@
#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);
@@ -341,34 +334,11 @@ size_t janet_getsize(const Janet *argv, int32_t n) {
} }
int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) { int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) {
int32_t raw = janet_getinteger(argv, n);
int32_t not_raw = raw;
if (not_raw < 0) not_raw += length + 1;
if (not_raw < 0 || not_raw > 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;
}
int32_t janet_getstartrange(const Janet *argv, int32_t argc, int32_t n, int32_t length) {
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
return 0;
}
return janet_gethalfrange(argv, n, length, "start");
}
int32_t janet_getendrange(const Janet *argv, int32_t argc, int32_t n, int32_t length) {
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
return length;
}
return janet_gethalfrange(argv, n, length, "end");
}
int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which) {
int32_t raw = janet_getinteger(argv, n); int32_t raw = janet_getinteger(argv, n);
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, (int64_t)raw, -(int64_t)length, (int64_t)length); janet_panicf("%s index %d out of range [%d,%d]", which, raw, -length, length);
return not_raw; return not_raw;
} }
@@ -415,10 +385,24 @@ JanetRange janet_getslice(int32_t argc, const Janet *argv) {
janet_arity(argc, 1, 3); janet_arity(argc, 1, 3);
JanetRange range; JanetRange range;
int32_t length = janet_length(argv[0]); int32_t length = janet_length(argv[0]);
range.start = janet_getstartrange(argv, argc, 1, length); if (argc == 1) {
range.end = janet_getendrange(argv, argc, 2, length); range.start = 0;
if (range.end < range.start) range.end = length;
range.end = range.start; } else if (argc == 2) {
range.start = janet_checktype(argv[1], JANET_NIL)
? 0
: janet_gethalfrange(argv, 1, length, "start");
range.end = length;
} else {
range.start = janet_checktype(argv[1], JANET_NIL)
? 0
: janet_gethalfrange(argv, 1, length, "start");
range.end = janet_checktype(argv[2], JANET_NIL)
? length
: janet_gethalfrange(argv, 2, length, "end");
if (range.end < range.start)
range.end = range.start;
}
return range; return range;
} }
@@ -498,41 +482,9 @@ void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetA
return janet_getabstract(argv, n, at); return janet_getabstract(argv, n, at);
} }
/* Atomic refcounts */
JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
#ifdef JANET_WINDOWS
return InterlockedIncrement(x);
#elif defined(JANET_USE_STDATOMIC)
return atomic_fetch_add_explicit(x, 1, memory_order_relaxed) + 1;
#else
return __atomic_add_fetch(x, 1, __ATOMIC_RELAXED);
#endif
}
JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
#ifdef JANET_WINDOWS
return InterlockedDecrement(x);
#elif defined(JANET_USE_STDATOMIC)
return atomic_fetch_add_explicit(x, -1, memory_order_acq_rel) - 1;
#else
return __atomic_add_fetch(x, -1, __ATOMIC_ACQ_REL);
#endif
}
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
}
/* Some definitions for function-like macros */ /* Some definitions for function-like macros */
JANET_API JanetStructHead *(janet_struct_head)(JanetStruct st) { JANET_API JanetStructHead *(janet_struct_head)(const JanetKV *st) {
return janet_struct_head(st); return janet_struct_head(st);
} }
@@ -540,10 +492,10 @@ JANET_API JanetAbstractHead *(janet_abstract_head)(const void *abstract) {
return janet_abstract_head(abstract); return janet_abstract_head(abstract);
} }
JANET_API JanetStringHead *(janet_string_head)(JanetString s) { JANET_API JanetStringHead *(janet_string_head)(const uint8_t *s) {
return janet_string_head(s); return janet_string_head(s);
} }
JANET_API JanetTupleHead *(janet_tuple_head)(JanetTuple tuple) { JANET_API JanetTupleHead *(janet_tuple_head)(const Janet *tuple) {
return janet_tuple_head(tuple); return janet_tuple_head(tuple);
} }

View File

@@ -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 used for importing files. " "to expand the path to a path that can be "
"The replacements are as follows:\n\n" "used for importing files. 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, " "* :@all: -- Same as :all:, but if `path` starts with the @ character,\n"
"the first path segment is replaced with a dynamic binding " " the first path segment is replaced with a dynamic binding\n"
"`(dyn <first path segment as keyword>)`.\n\n" " `(dyn <first path segment as keyword>)`.\n\n"
"* :cur: -- the directory portion, if any, of (dyn :current-file)\n\n" "* :cur: -- the current file, or (dyn :current-file)\n\n"
"* :dir: -- the directory portion, if any, of the path argument\n\n" "* :dir: -- the directory containing the current file\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)") {
@@ -426,36 +426,6 @@ JANET_CORE_FN(janet_core_slice,
} }
} }
JANET_CORE_FN(janet_core_range,
"(range & args)",
"Create an array of values [start, end) with a given step. "
"With one argument, returns a range [0, end). With two arguments, returns "
"a range [start, end). With three, returns a range with optional step size.") {
janet_arity(argc, 1, 3);
int32_t start = 0, stop = 0, step = 1, count = 0;
if (argc == 3) {
start = janet_getinteger(argv, 0);
stop = janet_getinteger(argv, 1);
step = janet_getinteger(argv, 2);
count = (step > 0) ? (stop - start - 1) / step + 1 :
((step < 0) ? (stop - start + 1) / step + 1 : 0);
} else if (argc == 2) {
start = janet_getinteger(argv, 0);
stop = janet_getinteger(argv, 1);
count = stop - start;
} else {
stop = janet_getinteger(argv, 0);
count = stop;
}
count = (count > 0) ? count : 0;
JanetArray *array = janet_array(count);
for (int32_t i = 0; i < count; i++) {
array->data[i] = janet_wrap_number(start + i * step);
}
array->count = count;
return janet_wrap_array(array);
}
JANET_CORE_FN(janet_core_table, JANET_CORE_FN(janet_core_table,
"(table & kvs)", "(table & kvs)",
"Creates a new table from a variadic number of keys and values. " "Creates a new table from a variadic number of keys and values. "
@@ -659,34 +629,6 @@ ret_false:
return janet_wrap_false(); return janet_wrap_false();
} }
JANET_CORE_FN(janet_core_is_bytes,
"(bytes? x)",
"Check if x is a string, symbol, keyword, or buffer.") {
janet_fixarity(argc, 1);
return janet_wrap_boolean(janet_checktypes(argv[0], JANET_TFLAG_BYTES));
}
JANET_CORE_FN(janet_core_is_indexed,
"(indexed? x)",
"Check if x is an array or tuple.") {
janet_fixarity(argc, 1);
return janet_wrap_boolean(janet_checktypes(argv[0], JANET_TFLAG_INDEXED));
}
JANET_CORE_FN(janet_core_is_dictionary,
"(dictionary? x)",
"Check if x is a table or struct.") {
janet_fixarity(argc, 1);
return janet_wrap_boolean(janet_checktypes(argv[0], JANET_TFLAG_DICTIONARY));
}
JANET_CORE_FN(janet_core_is_lengthable,
"(lengthable? x)",
"Check if x is a bytes, indexed, or dictionary.") {
janet_fixarity(argc, 1);
return janet_wrap_boolean(janet_checktypes(argv[0], JANET_TFLAG_LENGTHABLE));
}
JANET_CORE_FN(janet_core_signal, JANET_CORE_FN(janet_core_signal,
"(signal what x)", "(signal what x)",
"Raise a signal with payload x. ") { "Raise a signal with payload x. ") {
@@ -748,7 +690,6 @@ static const SandboxOption sandbox_options[] = {
{"net-connect", JANET_SANDBOX_NET_CONNECT}, {"net-connect", JANET_SANDBOX_NET_CONNECT},
{"net-listen", JANET_SANDBOX_NET_LISTEN}, {"net-listen", JANET_SANDBOX_NET_LISTEN},
{"sandbox", JANET_SANDBOX_SANDBOX}, {"sandbox", JANET_SANDBOX_SANDBOX},
{"signal", JANET_SANDBOX_SIGNAL},
{"subprocess", JANET_SANDBOX_SUBPROCESS}, {"subprocess", JANET_SANDBOX_SUBPROCESS},
{NULL, 0} {NULL, 0}
}; };
@@ -773,7 +714,6 @@ JANET_CORE_FN(janet_core_sandbox,
"* :net-connect - disallow making outbound network connections\n" "* :net-connect - disallow making outbound network connections\n"
"* :net-listen - disallow accepting inbound network connections\n" "* :net-listen - disallow accepting inbound network connections\n"
"* :sandbox - disallow calling this function\n" "* :sandbox - disallow calling this function\n"
"* :signal - disallow adding or removing signal handlers\n"
"* :subprocess - disallow running subprocesses") { "* :subprocess - disallow running subprocesses") {
uint32_t flags = 0; uint32_t flags = 0;
for (int32_t i = 0; i < argc; i++) { for (int32_t i = 0; i < argc; i++) {
@@ -1083,12 +1023,7 @@ static void janet_load_libs(JanetTable *env) {
JANET_CORE_REG("module/expand-path", janet_core_expand_path), JANET_CORE_REG("module/expand-path", janet_core_expand_path),
JANET_CORE_REG("int?", janet_core_check_int), JANET_CORE_REG("int?", janet_core_check_int),
JANET_CORE_REG("nat?", janet_core_check_nat), JANET_CORE_REG("nat?", janet_core_check_nat),
JANET_CORE_REG("bytes?", janet_core_is_bytes),
JANET_CORE_REG("indexed?", janet_core_is_indexed),
JANET_CORE_REG("dictionary?", janet_core_is_dictionary),
JANET_CORE_REG("lengthable?", janet_core_is_lengthable),
JANET_CORE_REG("slice", janet_core_slice), JANET_CORE_REG("slice", janet_core_slice),
JANET_CORE_REG("range", janet_core_range),
JANET_CORE_REG("signal", janet_core_signal), JANET_CORE_REG("signal", janet_core_signal),
JANET_CORE_REG("memcmp", janet_core_memcmp), JANET_CORE_REG("memcmp", janet_core_memcmp),
JANET_CORE_REG("getproto", janet_core_getproto), JANET_CORE_REG("getproto", janet_core_getproto),
@@ -1144,20 +1079,17 @@ 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 the data structure is not mutated " "to be seen only once per iteration if they data structure is not mutated "
"during iteration. If key is nil, next returns the first key. If next " "during iteration. If key is nil, next returns the first key. If next "
"returns nil, there are no more keys to iterate through.")); "returns nil, there are no more keys to iterate through."));
janet_quick_asm(env, JANET_FUN_PROP, janet_quick_asm(env, JANET_FUN_PROP,
"propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm), "propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm),
JDOC("(propagate x fiber)\n\n" JDOC("(propagate x fiber)\n\n"
"Propagate a signal from a fiber to the current fiber and " "Propagate a signal from a fiber to the current fiber. The resulting "
"set the last value of the current fiber to `x`. The signal " "stack trace from the current fiber will include frames from fiber. If "
"value is then available as the status of the current fiber. " "fiber is in a state that can be resumed, resuming the current fiber will "
"The resulting stack trace from the current fiber will include " "first resume fiber. This function can be used to re-raise an error without "
"frames from fiber. If fiber is in a state that can be resumed, " "losing the original stack trace."));
"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"

View File

@@ -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 `prefix` is nil or not " "an error value to print the stack trace with. If `err` is nil or not "
"provided, will skip the error line. Returns the fiber.") { "provided, and no prefix is given, 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];

View File

@@ -26,7 +26,6 @@
#include "emit.h" #include "emit.h"
#include "vector.h" #include "vector.h"
#include "regalloc.h" #include "regalloc.h"
#include "util.h"
#endif #endif
/* Get a register */ /* Get a register */
@@ -129,8 +128,7 @@ static void janetc_movenear(JanetCompiler *c,
((uint32_t)(src.envindex) << 16) | ((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) | ((uint32_t)(dest) << 8) |
JOP_LOAD_UPVALUE); JOP_LOAD_UPVALUE);
} else if (src.index != dest) { } else if (src.index > 0xFF || src.index != dest) {
janet_assert(src.index >= 0, "bad slot");
janetc_emit(c, janetc_emit(c,
((uint32_t)(src.index) << 16) | ((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) | ((uint32_t)(dest) << 8) |
@@ -157,7 +155,6 @@ static void janetc_moveback(JanetCompiler *c,
((uint32_t)(src) << 8) | ((uint32_t)(src) << 8) |
JOP_SET_UPVALUE); JOP_SET_UPVALUE);
} else if (dest.index != src) { } else if (dest.index != src) {
janet_assert(dest.index >= 0, "bad slot");
janetc_emit(c, janetc_emit(c,
((uint32_t)(dest.index) << 16) | ((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) | ((uint32_t)(src) << 8) |

File diff suppressed because it is too large Load Diff

View File

@@ -1381,7 +1381,7 @@ JANET_CORE_FN(cfun_ffi_buffer_write,
"(ffi/write ffi-type data &opt buffer index)", "(ffi/write ffi-type data &opt buffer index)",
"Append a native type to a buffer such as it would appear in memory. This can be used " "Append a native type to a buffer such as it would appear in memory. This can be used "
"to pass pointers to structs in the ffi, or send C/C++/native structs over the network " "to pass pointers to structs in the ffi, or send C/C++/native structs over the network "
"or to files. Returns a modified buffer or a new buffer if one is not supplied.") { "or to files. Returns a modifed buffer or a new buffer if one is not supplied.") {
janet_sandbox_assert(JANET_SANDBOX_FFI_USE); janet_sandbox_assert(JANET_SANDBOX_FFI_USE);
janet_arity(argc, 2, 4); janet_arity(argc, 2, 4);
JanetFFIType type = decode_ffi_type(argv[0]); JanetFFIType type = decode_ffi_type(argv[0]);
@@ -1548,7 +1548,7 @@ JANET_CORE_FN(cfun_ffi_pointer_cfunction,
JANET_CORE_FN(cfun_ffi_supported_calling_conventions, JANET_CORE_FN(cfun_ffi_supported_calling_conventions,
"(ffi/calling-conventions)", "(ffi/calling-conventions)",
"Get an array of all supported calling conventions on the current architecture. Some architectures may have some FFI " "Get an array of all supported calling conventions on the current arhcitecture. Some architectures may have some FFI "
"functionality (ffi/malloc, ffi/free, ffi/read, ffi/write, etc.) but not support " "functionality (ffi/malloc, ffi/free, ffi/read, ffi/write, etc.) but not support "
"any calling conventions. This function can be used to get all supported calling conventions " "any calling conventions. This function can be used to get all supported calling conventions "
"that can be used on this architecture. All architectures support the :none calling " "that can be used on this architecture. All architectures support the :none calling "

View File

@@ -39,10 +39,8 @@ static void fiber_reset(JanetFiber *fiber) {
fiber->env = NULL; fiber->env = NULL;
fiber->last_value = janet_wrap_nil(); fiber->last_value = janet_wrap_nil();
#ifdef JANET_EV #ifdef JANET_EV
fiber->waiting = NULL;
fiber->sched_id = 0; fiber->sched_id = 0;
fiber->ev_callback = NULL;
fiber->ev_state = NULL;
fiber->ev_stream = NULL;
fiber->supervisor_channel = NULL; fiber->supervisor_channel = NULL;
#endif #endif
janet_fiber_set_status(fiber, JANET_STATUS_NEW); janet_fiber_set_status(fiber, JANET_STATUS_NEW);
@@ -87,6 +85,7 @@ JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t
if (janet_fiber_funcframe(fiber, callee)) return NULL; if (janet_fiber_funcframe(fiber, callee)) return NULL;
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE; janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
#ifdef JANET_EV #ifdef JANET_EV
fiber->waiting = NULL;
fiber->supervisor_channel = NULL; fiber->supervisor_channel = NULL;
#endif #endif
return fiber; return fiber;
@@ -239,8 +238,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 +369,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 +661,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)", "(fiber/last-value)",
"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);

View File

@@ -59,9 +59,6 @@
#define JANET_FIBER_EV_FLAG_CANCELED 0x10000 #define JANET_FIBER_EV_FLAG_CANCELED 0x10000
#define JANET_FIBER_EV_FLAG_SUSPENDED 0x20000 #define JANET_FIBER_EV_FLAG_SUSPENDED 0x20000
#define JANET_FIBER_FLAG_ROOT 0x40000 #define JANET_FIBER_FLAG_ROOT 0x40000
#define JANET_FIBER_EV_FLAG_IN_FLIGHT 0x1
/* used only on windows, should otherwise be unset */
#define janet_fiber_set_status(f, s) do {\ #define janet_fiber_set_status(f, s) do {\
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\ (f)->flags &= ~JANET_FIBER_STATUS_MASK;\

View File

@@ -132,24 +132,6 @@ static void janet_mark_many(const Janet *values, int32_t n) {
} }
} }
/* Mark a bunch of key values items in memory */
static void janet_mark_keys(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n;
while (kvs < end) {
janet_mark(kvs->key);
kvs++;
}
}
/* Mark a bunch of key values items in memory */
static void janet_mark_values(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n;
while (kvs < end) {
janet_mark(kvs->value);
kvs++;
}
}
/* Mark a bunch of key values items in memory */ /* Mark a bunch of key values items in memory */
static void janet_mark_kvs(const JanetKV *kvs, int32_t n) { static void janet_mark_kvs(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n; const JanetKV *end = kvs + n;
@@ -164,9 +146,7 @@ static void janet_mark_array(JanetArray *array) {
if (janet_gc_reachable(array)) if (janet_gc_reachable(array))
return; return;
janet_gc_mark(array); janet_gc_mark(array);
if (janet_gc_type((JanetGCObject *) array) == JANET_MEMORY_ARRAY) { janet_mark_many(array->data, array->count);
janet_mark_many(array->data, array->count);
}
} }
static void janet_mark_table(JanetTable *table) { static void janet_mark_table(JanetTable *table) {
@@ -174,15 +154,7 @@ recur: /* Manual tail recursion */
if (janet_gc_reachable(table)) if (janet_gc_reachable(table))
return; return;
janet_gc_mark(table); janet_gc_mark(table);
enum JanetMemoryType memtype = janet_gc_type(table); janet_mark_kvs(table->data, table->capacity);
if (memtype == JANET_MEMORY_TABLE_WEAKK) {
janet_mark_values(table->data, table->capacity);
} else if (memtype == JANET_MEMORY_TABLE_WEAKV) {
janet_mark_keys(table->data, table->capacity);
} else if (memtype == JANET_MEMORY_TABLE) {
janet_mark_kvs(table->data, table->capacity);
}
/* do nothing for JANET_MEMORY_TABLE_WEAKKV */
if (table->proto) { if (table->proto) {
table = table->proto; table = table->proto;
goto recur; goto recur;
@@ -296,12 +268,6 @@ recur:
if (fiber->supervisor_channel) { if (fiber->supervisor_channel) {
janet_mark_abstract(fiber->supervisor_channel); janet_mark_abstract(fiber->supervisor_channel);
} }
if (fiber->ev_stream) {
janet_mark_abstract(fiber->ev_stream);
}
if (fiber->ev_callback) {
fiber->ev_callback(fiber, JANET_ASYNC_EVENT_MARK);
}
#endif #endif
/* Explicit tail recursion */ /* Explicit tail recursion */
@@ -326,17 +292,9 @@ static void janet_deinit_block(JanetGCObject *mem) {
case JANET_MEMORY_TABLE: case JANET_MEMORY_TABLE:
janet_free(((JanetTable *) mem)->data); janet_free(((JanetTable *) mem)->data);
break; break;
case JANET_MEMORY_FIBER: { case JANET_MEMORY_FIBER:
JanetFiber *f = (JanetFiber *)mem; janet_free(((JanetFiber *)mem)->data);
#ifdef JANET_EV break;
if (f->ev_state && !(f->flags & JANET_FIBER_EV_FLAG_IN_FLIGHT)) {
janet_ev_dec_refcount();
janet_free(f->ev_state);
}
#endif
janet_free(f->data);
}
break;
case JANET_MEMORY_BUFFER: case JANET_MEMORY_BUFFER:
janet_buffer_deinit((JanetBuffer *) mem); janet_buffer_deinit((JanetBuffer *) mem);
break; break;
@@ -368,98 +326,12 @@ static void janet_deinit_block(JanetGCObject *mem) {
} }
} }
/* Check that a value x has been visited in the mark phase */
static int janet_check_liveref(Janet x) {
switch (janet_type(x)) {
default:
return 1;
case JANET_ARRAY:
case JANET_TABLE:
case JANET_FUNCTION:
case JANET_BUFFER:
case JANET_FIBER:
return janet_gc_reachable(janet_unwrap_pointer(x));
case JANET_STRING:
case JANET_SYMBOL:
case JANET_KEYWORD:
return janet_gc_reachable(janet_string_head(janet_unwrap_string(x)));
case JANET_ABSTRACT:
return janet_gc_reachable(janet_abstract_head(janet_unwrap_abstract(x)));
case JANET_TUPLE:
return janet_gc_reachable(janet_tuple_head(janet_unwrap_tuple(x)));
case JANET_STRUCT:
return janet_gc_reachable(janet_struct_head(janet_unwrap_struct(x)));
}
}
/* Iterate over all allocated memory, and free memory that is not /* Iterate over all allocated memory, and free memory that is not
* marked as reachable. Flip the gc color flag for next sweep. */ * marked as reachable. Flip the gc color flag for next sweep. */
void janet_sweep() { void janet_sweep() {
JanetGCObject *previous = NULL; JanetGCObject *previous = NULL;
JanetGCObject *current = janet_vm.weak_blocks; JanetGCObject *current = janet_vm.blocks;
JanetGCObject *next; JanetGCObject *next;
/* Sweep weak heap to drop weak refs */
while (NULL != current) {
next = current->data.next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
/* Check for dead references */
enum JanetMemoryType type = janet_gc_type(current);
if (type == JANET_MEMORY_ARRAY_WEAK) {
JanetArray *array = (JanetArray *) current;
for (uint32_t i = 0; i < (uint32_t) array->count; i++) {
if (!janet_check_liveref(array->data[i])) {
array->data[i] = janet_wrap_nil();
}
}
} else {
JanetTable *table = (JanetTable *) current;
int check_values = (type == JANET_MEMORY_TABLE_WEAKV) || (type == JANET_MEMORY_TABLE_WEAKKV);
int check_keys = (type == JANET_MEMORY_TABLE_WEAKK) || (type == JANET_MEMORY_TABLE_WEAKKV);
JanetKV *end = table->data + table->capacity;
JanetKV *kvs = table->data;
while (kvs < end) {
int drop = 0;
if (check_keys && !janet_check_liveref(kvs->key)) drop = 1;
if (check_values && !janet_check_liveref(kvs->value)) drop = 1;
if (drop) {
/* Inlined from janet_table_remove without search */
table->count--;
table->deleted++;
kvs->key = janet_wrap_nil();
kvs->value = janet_wrap_false();
}
kvs++;
}
}
}
current = next;
}
/* Sweep weak heap to free blocks */
previous = NULL;
current = janet_vm.weak_blocks;
while (NULL != current) {
next = current->data.next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
previous = current;
current->flags &= ~JANET_MEM_REACHABLE;
} else {
janet_vm.block_count--;
janet_deinit_block(current);
if (NULL != previous) {
previous->data.next = next;
} else {
janet_vm.weak_blocks = next;
}
janet_free(current);
}
current = next;
}
/* Sweep main heap to free blocks */
previous = NULL;
current = janet_vm.blocks;
while (NULL != current) { while (NULL != current) {
next = current->data.next; next = current->data.next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) { if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
@@ -477,7 +349,6 @@ void janet_sweep() {
} }
current = next; current = next;
} }
#ifdef JANET_EV #ifdef JANET_EV
/* Sweep threaded abstract types for references to decrement */ /* Sweep threaded abstract types for references to decrement */
JanetKV *items = janet_vm.threaded_abstracts.data; JanetKV *items = janet_vm.threaded_abstracts.data;
@@ -499,15 +370,14 @@ void janet_sweep() {
if (head->type->gc) { if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
} }
/* Mark as tombstone in place */
items[i].key = janet_wrap_nil();
items[i].value = janet_wrap_false();
janet_vm.threaded_abstracts.deleted++;
janet_vm.threaded_abstracts.count--;
/* Free memory */ /* Free memory */
janet_free(janet_abstract_head(abst)); janet_free(janet_abstract_head(abst));
} }
/* Mark as tombstone in place */
items[i].key = janet_wrap_nil();
items[i].value = janet_wrap_false();
janet_vm.threaded_abstracts.deleted++;
janet_vm.threaded_abstracts.count--;
} }
/* Reset for next sweep */ /* Reset for next sweep */
@@ -535,15 +405,8 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
/* Prepend block to heap list */ /* Prepend block to heap list */
janet_vm.next_collection += size; janet_vm.next_collection += size;
if (type < JANET_MEMORY_TABLE_WEAKK) { mem->data.next = janet_vm.blocks;
/* normal heap */ janet_vm.blocks = mem;
mem->data.next = janet_vm.blocks;
janet_vm.blocks = mem;
} else {
/* weak heap */
mem->data.next = janet_vm.weak_blocks;
janet_vm.weak_blocks = mem;
}
janet_vm.block_count++; janet_vm.block_count++;
return (void *)mem; return (void *)mem;
@@ -574,8 +437,7 @@ void janet_collect(void) {
uint32_t i; uint32_t i;
if (janet_vm.gc_suspend) return; if (janet_vm.gc_suspend) return;
depth = JANET_RECURSION_GUARD; depth = JANET_RECURSION_GUARD;
janet_vm.gc_mark_phase = 1; /* Try and prevent many major collections back to back.
/* Try to prevent many major collections back to back.
* A full collection will take O(janet_vm.block_count) time. * A full collection will take O(janet_vm.block_count) time.
* If we have a large heap, make sure our interval is not too * If we have a large heap, make sure our interval is not too
* small so we won't make many collections over it. This is just a * small so we won't make many collections over it. This is just a
@@ -594,7 +456,6 @@ void janet_collect(void) {
Janet x = janet_vm.roots[--janet_vm.root_count]; Janet x = janet_vm.roots[--janet_vm.root_count];
janet_mark(x); janet_mark(x);
} }
janet_vm.gc_mark_phase = 0;
janet_sweep(); janet_sweep();
janet_vm.next_collection = 0; janet_vm.next_collection = 0;
janet_free_all_scratch(); janet_free_all_scratch();
@@ -698,9 +559,7 @@ void janet_gcunlock(int handle) {
janet_vm.gc_suspend = handle; janet_vm.gc_suspend = handle;
} }
/* Scratch memory API /* Scratch memory API */
* Scratch memory allocations do not need to be free (but optionally can be), and will be automatically cleaned
* up in the next call to janet_collect. */
void *janet_smalloc(size_t size) { void *janet_smalloc(size_t size) {
JanetScratch *s = janet_malloc(sizeof(JanetScratch) + size); JanetScratch *s = janet_malloc(sizeof(JanetScratch) + size);

View File

@@ -57,10 +57,6 @@ enum JanetMemoryType {
JANET_MEMORY_FUNCENV, JANET_MEMORY_FUNCENV,
JANET_MEMORY_FUNCDEF, JANET_MEMORY_FUNCDEF,
JANET_MEMORY_THREADED_ABSTRACT, JANET_MEMORY_THREADED_ABSTRACT,
JANET_MEMORY_TABLE_WEAKK,
JANET_MEMORY_TABLE_WEAKV,
JANET_MEMORY_TABLE_WEAKKV,
JANET_MEMORY_ARRAY_WEAK
}; };
/* To allocate collectable memory, one must call janet_alloc, initialize the memory, /* To allocate collectable memory, one must call janet_alloc, initialize the memory,

View File

@@ -239,7 +239,7 @@ JANET_CORE_FN(cfun_to_bytes,
"Write the bytes of an `int/s64` or `int/u64` into a buffer.\n" "Write the bytes of an `int/s64` or `int/u64` into a buffer.\n"
"The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n" "The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n"
"Returns the modified buffer.\n" "Returns the modified buffer.\n"
"The `endianness` parameter indicates the byte order:\n" "The `endianness` paramater indicates the byte order:\n"
"- `nil` (unset): system byte order\n" "- `nil` (unset): system byte order\n"
"- `:le`: little-endian, least significant byte first\n" "- `:le`: little-endian, least significant byte first\n"
"- `:be`: big-endian, most significant byte first\n") { "- `:be`: big-endian, most significant byte first\n") {

View File

@@ -131,7 +131,7 @@ JANET_CORE_FN(cfun_io_temp,
} }
JANET_CORE_FN(cfun_io_fopen, JANET_CORE_FN(cfun_io_fopen,
"(file/open path &opt mode buffer-size)", "(file/open path &opt mode)",
"Open a file. `path` is an absolute or relative path, and " "Open a file. `path` is an absolute or relative path, and "
"`mode` is a set of flags indicating the mode to open the file in. " "`mode` is a set of flags indicating the mode to open the file in. "
"`mode` is a keyword where each character represents a flag. If the file " "`mode` is a keyword where each character represents a flag. If the file "
@@ -143,9 +143,8 @@ JANET_CORE_FN(cfun_io_fopen,
"Following one of the initial flags, 0 or more of the following flags can be appended:\n\n" "Following one of the initial flags, 0 or more of the following flags can be appended:\n\n"
"* b - open the file in binary mode (rather than text mode)\n\n" "* b - open the file in binary mode (rather than text mode)\n\n"
"* + - append to the file instead of overwriting it\n\n" "* + - append to the file instead of overwriting it\n\n"
"* n - error if the file cannot be opened instead of returning nil\n\n" "* n - error if the file cannot be opened instead of returning nil") {
"See fopen (<stdio.h>, C99) for further details.") { janet_arity(argc, 1, 2);
janet_arity(argc, 1, 3);
const uint8_t *fname = janet_getstring(argv, 0); const uint8_t *fname = janet_getstring(argv, 0);
const uint8_t *fmode; const uint8_t *fmode;
int32_t flags; int32_t flags;
@@ -158,15 +157,6 @@ JANET_CORE_FN(cfun_io_fopen,
flags = JANET_FILE_READ; flags = JANET_FILE_READ;
} }
FILE *f = fopen((const char *)fname, (const char *)fmode); FILE *f = fopen((const char *)fname, (const char *)fmode);
if (f != NULL) {
size_t bufsize = janet_optsize(argv, argc, 2, BUFSIZ);
if (bufsize != BUFSIZ) {
int result = setvbuf(f, NULL, bufsize ? _IOFBF : _IONBF, bufsize);
if (result) {
janet_panic("failed to set buffer size for file");
}
}
}
return f ? janet_makefile(f, flags) return f ? janet_makefile(f, flags)
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil()) : (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil())
: janet_wrap_nil(); : janet_wrap_nil();

View File

@@ -185,19 +185,6 @@ 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;
@@ -210,9 +197,7 @@ 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;
@@ -343,7 +328,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_panicf("cannot marshal fiber with c stackframe (%v)", janet_wrap_cfunction((JanetCFunction) frame->pc)); if (!frame->func) janet_panic("cannot marshal fiber with c stackframe");
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);
@@ -1063,11 +1048,9 @@ static const uint8_t *unmarshal_one_fiber(
fiber->env = NULL; fiber->env = NULL;
fiber->last_value = janet_wrap_nil(); fiber->last_value = janet_wrap_nil();
#ifdef JANET_EV #ifdef JANET_EV
fiber->waiting = NULL;
fiber->sched_id = 0; fiber->sched_id = 0;
fiber->supervisor_channel = NULL; fiber->supervisor_channel = NULL;
fiber->ev_state = NULL;
fiber->ev_callback = NULL;
fiber->ev_stream = NULL;
#endif #endif
/* Push fiber to seen stack */ /* Push fiber to seen stack */
@@ -1262,18 +1245,6 @@ void *janet_unmarshal_abstract(JanetMarshalContext *ctx, size_t size) {
return p; return p;
} }
void *janet_unmarshal_abstract_threaded(JanetMarshalContext *ctx, size_t size) {
#ifdef JANET_THREADS
void *p = janet_abstract_threaded(ctx->at, size);
janet_unmarshal_abstract_reuse(ctx, p);
return p;
#else
(void) ctx;
(void) size;
janet_panic("threaded abstracts not supported");
#endif
}
static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *data, Janet *out, int flags) { static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *data, Janet *out, int flags) {
Janet key; Janet key;
data = unmarshal_one(st, data, &key, flags + 1); data = unmarshal_one(st, data, &key, flags + 1);

View File

@@ -119,7 +119,7 @@ double janet_rng_double(JanetRNG *rng) {
JANET_CORE_FN(cfun_rng_make, JANET_CORE_FN(cfun_rng_make,
"(math/rng &opt seed)", "(math/rng &opt seed)",
"Creates a Pseudo-Random number generator, with an optional seed. " "Creates a Psuedo-Random number generator, with an optional seed. "
"The seed should be an unsigned 32 bit integer or a buffer. " "The seed should be an unsigned 32 bit integer or a buffer. "
"Do not use this for cryptography. Returns a core/rng abstract type." "Do not use this for cryptography. Returns a core/rng abstract type."
) { ) {
@@ -411,11 +411,11 @@ void janet_lib_math(JanetTable *env) {
JANET_CORE_DEF(env, "math/int32-min", janet_wrap_number(INT32_MIN), JANET_CORE_DEF(env, "math/int32-min", janet_wrap_number(INT32_MIN),
"The minimum contiguous integer representable by a 32 bit signed integer"); "The minimum contiguous integer representable by a 32 bit signed integer");
JANET_CORE_DEF(env, "math/int32-max", janet_wrap_number(INT32_MAX), JANET_CORE_DEF(env, "math/int32-max", janet_wrap_number(INT32_MAX),
"The maximum contiguous integer representable by a 32 bit signed integer"); "The maximum contiguous integer represtenable by a 32 bit signed integer");
JANET_CORE_DEF(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE), JANET_CORE_DEF(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE),
"The minimum contiguous integer representable by a double (2^53)"); "The minimum contiguous integer representable by a double (2^53)");
JANET_CORE_DEF(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE), JANET_CORE_DEF(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE),
"The maximum contiguous integer representable by a double (-(2^53))"); "The maximum contiguous integer represtenable by a double (-(2^53))");
#ifdef NAN #ifdef NAN
JANET_CORE_DEF(env, "math/nan", janet_wrap_number(NAN), "Not a number (IEEE-754 NaN)"); JANET_CORE_DEF(env, "math/nan", janet_wrap_number(NAN), "Not a number (IEEE-754 NaN)");
#else #else

View File

@@ -24,7 +24,6 @@
#include "features.h" #include "features.h"
#include <janet.h> #include <janet.h>
#include "util.h" #include "util.h"
#include "fiber.h"
#endif #endif
#ifdef JANET_NET #ifdef JANET_NET
@@ -79,20 +78,12 @@ 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);
@@ -120,57 +111,12 @@ static void janet_net_socknoblock(JSock s) {
#endif #endif
} }
/* State machine for async connect */
void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
JanetStream *stream = fiber->ev_stream;
switch (event) {
default:
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:
janet_cancel(fiber, janet_cstringv("stream closed"));
janet_async_end(fiber);
return;
}
#ifdef JANET_WINDOWS
int res = 0;
int size = sizeof(res);
int r = getsockopt((SOCKET)stream->handle, SOL_SOCKET, SO_ERROR, (char *)&res, &size);
#else
int res = 0;
socklen_t size = sizeof res;
int r = getsockopt(stream->handle, SOL_SOCKET, SO_ERROR, &res, &size);
#endif
if (r == 0) {
if (res == 0) {
janet_schedule(fiber, janet_wrap_abstract(stream));
} else {
janet_cancel(fiber, janet_cstringv(strerror(res)));
stream->flags |= JANET_STREAM_TOCLOSE;
}
} else {
janet_cancel(fiber, janet_ev_lasterr());
stream->flags |= JANET_STREAM_TOCLOSE;
}
janet_async_end(fiber);
}
static JANET_NO_RETURN void net_sched_connect(JanetStream *stream) {
janet_async_start(stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, NULL);
}
/* State machine for accepting connections. */ /* State machine for accepting connections. */
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
typedef struct { typedef struct {
JanetListenerState head;
WSAOVERLAPPED overlapped; WSAOVERLAPPED overlapped;
JanetFunction *function; JanetFunction *function;
JanetStream *lstream; JanetStream *lstream;
@@ -178,10 +124,10 @@ typedef struct {
char buf[1024]; char buf[1024];
} NetStateAccept; } NetStateAccept;
static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err); static int net_sched_accept_impl(NetStateAccept *state, Janet *err);
void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) { JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event) {
NetStateAccept *state = (NetStateAccept *)fiber->ev_state; NetStateAccept *state = (NetStateAccept *)s;
switch (event) { switch (event) {
default: default:
break; break;
@@ -192,60 +138,55 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
break; break;
} }
case JANET_ASYNC_EVENT_CLOSE: case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
case JANET_ASYNC_EVENT_COMPLETE: { case JANET_ASYNC_EVENT_COMPLETE: {
if (state->astream->flags & JANET_STREAM_CLOSED) { if (state->astream->flags & JANET_STREAM_CLOSED) {
janet_cancel(fiber, janet_cstringv("failed to accept connection")); janet_cancel(s->fiber, janet_cstringv("failed to accept connection"));
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
} }
SOCKET lsock = (SOCKET) state->lstream->handle; SOCKET lsock = (SOCKET) state->lstream->handle;
if (NO_ERROR != setsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, if (NO_ERROR != setsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char *) &lsock, sizeof(lsock))) { (char *) &lsock, sizeof(lsock))) {
janet_cancel(fiber, janet_cstringv("failed to accept connection")); janet_cancel(s->fiber, janet_cstringv("failed to accept connection"));
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
} }
Janet streamv = janet_wrap_abstract(state->astream); Janet streamv = janet_wrap_abstract(state->astream);
if (state->function) { if (state->function) {
/* Schedule worker */ /* Schedule worker */
JanetFiber *sub_fiber = janet_fiber(state->function, 64, 1, &streamv); JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
sub_fiber->supervisor_channel = fiber->supervisor_channel; fiber->supervisor_channel = s->fiber->supervisor_channel;
janet_schedule(sub_fiber, janet_wrap_nil()); janet_schedule(fiber, janet_wrap_nil());
/* Now listen again for next connection */ /* Now listen again for next connection */
Janet err; Janet err;
if (net_sched_accept_impl(state, fiber, &err)) { if (net_sched_accept_impl(state, &err)) {
janet_cancel(fiber, err); janet_cancel(s->fiber, err);
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
} }
} else { } else {
janet_schedule(fiber, streamv); janet_schedule(s->fiber, streamv);
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
} }
} }
} }
return JANET_ASYNC_STATUS_NOT_DONE;
} }
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;
NetStateAccept *state = janet_malloc(sizeof(NetStateAccept)); JanetListenerState *s = janet_listen(stream, net_machine_accept, JANET_ASYNC_LISTEN_READ, sizeof(NetStateAccept), NULL);
NetStateAccept *state = (NetStateAccept *)s;
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, janet_root_fiber(), &err)) { s->tag = &state->overlapped;
janet_free(state); if (net_sched_accept_impl(state, &err)) janet_panicv(err);
janet_panicv(err); janet_await();
}
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, Janet *err) {
SOCKET lsock = (SOCKET) state->lstream->handle; SOCKET lsock = (SOCKET) state->lstream->handle;
SOCKET asock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); SOCKET asock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (asock == INVALID_SOCKET) { if (asock == INVALID_SOCKET) {
@@ -257,11 +198,7 @@ static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet
int socksize = sizeof(SOCKADDR_STORAGE) + 16; int socksize = sizeof(SOCKADDR_STORAGE) + 16;
if (FALSE == AcceptEx(lsock, asock, state->buf, 0, socksize, socksize, NULL, &state->overlapped)) { if (FALSE == AcceptEx(lsock, asock, state->buf, 0, socksize, socksize, NULL, &state->overlapped)) {
int code = WSAGetLastError(); int code = WSAGetLastError();
if (code == WSA_IO_PENDING) { if (code == WSA_IO_PENDING) return 0; /* indicates io is happening async */
/* indicates io is happening async */
janet_async_in_flight(fiber);
return 0;
}
*err = janet_ev_lasterr(); *err = janet_ev_lasterr();
return 1; return 1;
} }
@@ -271,12 +208,12 @@ static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet
#else #else
typedef struct { typedef struct {
JanetListenerState head;
JanetFunction *function; JanetFunction *function;
} NetStateAccept; } NetStateAccept;
void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) { JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event) {
JanetStream *stream = fiber->ev_stream; NetStateAccept *state = (NetStateAccept *)s;
NetStateAccept *state = (NetStateAccept *)fiber->ev_state;
switch (event) { switch (event) {
default: default:
break; break;
@@ -285,41 +222,38 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
break; break;
} }
case JANET_ASYNC_EVENT_CLOSE: case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
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(s->stream->handle, NULL, NULL, SOCK_CLOEXEC);
#else #else
/* On BSDs, CLOEXEC should be inherited from server socket */ /* On BSDs, CLOEXEC should be inherited from server socket */
JSock connfd = accept(stream->handle, NULL, NULL); JSock connfd = accept(s->stream->handle, NULL, NULL);
#endif #endif
if (JSOCKVALID(connfd)) { if (JSOCKVALID(connfd)) {
janet_net_socknoblock(connfd); janet_net_socknoblock(connfd);
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE); JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
Janet streamv = janet_wrap_abstract(stream); Janet streamv = janet_wrap_abstract(stream);
if (state->function) { if (state->function) {
JanetFiber *sub_fiber = janet_fiber(state->function, 64, 1, &streamv); JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
sub_fiber->supervisor_channel = fiber->supervisor_channel; fiber->supervisor_channel = s->fiber->supervisor_channel;
janet_schedule(sub_fiber, janet_wrap_nil()); janet_schedule(fiber, janet_wrap_nil());
} else { } else {
janet_schedule(fiber, streamv); janet_schedule(s->fiber, streamv);
janet_async_end(fiber); return JANET_ASYNC_STATUS_DONE;
return;
} }
} }
break; break;
} }
} }
return JANET_ASYNC_STATUS_NOT_DONE;
} }
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) { JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
NetStateAccept *state = janet_malloc(sizeof(NetStateAccept)); NetStateAccept *state = (NetStateAccept *) janet_listen(stream, net_machine_accept, JANET_ASYNC_LISTEN_READ, sizeof(NetStateAccept), NULL);
memset(state, 0, sizeof(NetStateAccept));
state->function = fun; state->function = fun;
janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state); janet_await();
} }
#endif #endif
@@ -562,7 +496,7 @@ JANET_CORE_FN(cfun_net_connect,
} }
#endif #endif
if (status) { if (status != 0) {
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
if (err != WSAEWOULDBLOCK) { if (err != WSAEWOULDBLOCK) {
#else #else
@@ -574,7 +508,10 @@ JANET_CORE_FN(cfun_net_connect,
} }
} }
net_sched_connect(stream); /* Handle the connect() result in the event loop*/
janet_ev_connect(stream, MSG_NOSIGNAL);
janet_await();
} }
static const char *serverify_socket(JSock sfd) { static const char *serverify_socket(JSock sfd) {
@@ -745,7 +682,6 @@ 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))) {
@@ -754,7 +690,6 @@ 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;
@@ -821,7 +756,6 @@ 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);
} }
@@ -858,6 +792,7 @@ 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,
@@ -872,6 +807,7 @@ 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,
@@ -886,6 +822,7 @@ 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,
@@ -905,6 +842,7 @@ 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,
@@ -925,6 +863,7 @@ 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,
@@ -958,10 +897,8 @@ 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 }
}; };
@@ -998,9 +935,7 @@ 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;
@@ -1018,14 +953,12 @@ 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");
} }

View File

@@ -229,11 +229,10 @@ 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 force)", "(os/exit &opt x)",
"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. If `force` is truthy will exit immediately and " "the exit with status equal the hash of x.") {
"skip cleanup code.") { janet_arity(argc, 0, 1);
janet_arity(argc, 0, 2);
int status; int status;
if (argc == 0) { if (argc == 0) {
status = EXIT_SUCCESS; status = EXIT_SUCCESS;
@@ -243,11 +242,7 @@ JANET_CORE_FN(os_exit,
status = EXIT_FAILURE; status = EXIT_FAILURE;
} }
janet_deinit(); janet_deinit();
if (argc >= 2 && janet_truthy(argv[1])) { exit(status);
_exit(status);
} else {
exit(status);
}
return janet_wrap_nil(); return janet_wrap_nil();
} }
@@ -505,11 +500,8 @@ 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 if (WIFSIGNALED(status)) {
status = WTERMSIG(status) + 128;
} else { } else {
/* Could possibly return -1 but for now, just panic */ status = WTERMSIG(status) + 128;
janet_panicf("Undefined status code for process termination, %d.", status);
} }
return status; return status;
} }
@@ -525,6 +517,7 @@ static JanetEVGenericMessage janet_proc_wait_subr(JanetEVGenericMessage args) {
/* Callback that is called in main thread when subroutine completes. */ /* Callback that is called in main thread when subroutine completes. */
static void janet_proc_wait_cb(JanetEVGenericMessage args) { static void janet_proc_wait_cb(JanetEVGenericMessage args) {
janet_ev_dec_refcount();
JanetProc *proc = (JanetProc *) args.argp; JanetProc *proc = (JanetProc *) args.argp;
if (NULL != proc) { if (NULL != proc) {
int status = args.tag; int status = args.tag;
@@ -537,9 +530,7 @@ 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 {
if (janet_fiber_can_resume(args.fiber)) { janet_schedule(args.fiber, janet_wrap_integer(status));
janet_schedule(args.fiber, janet_wrap_integer(status));
}
} }
} }
} }
@@ -621,11 +612,7 @@ 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)",
"Suspend the current fiber until the subprocess completes. Returns the subprocess return code. " "Block 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
@@ -654,7 +641,7 @@ static const struct keyword_signal signal_keywords[] = {
#ifdef SIGTERM #ifdef SIGTERM
{"term", SIGTERM}, {"term", SIGTERM},
#endif #endif
#ifdef SIGALRM #ifdef SIGARLM
{"alrm", SIGALRM}, {"alrm", SIGALRM},
#endif #endif
#ifdef SIGHUP #ifdef SIGHUP
@@ -719,28 +706,15 @@ static const struct keyword_signal signal_keywords[] = {
#endif #endif
{NULL, 0}, {NULL, 0},
}; };
static int get_signal_kw(const Janet *argv, int32_t n) {
JanetKeyword signal_kw = janet_getkeyword(argv, n);
const struct keyword_signal *ptr = signal_keywords;
while (ptr->keyword) {
if (!janet_cstrcmp(signal_kw, ptr->keyword)) {
return ptr->signal;
}
ptr++;
}
janet_panicf("undefined signal %v", argv[n]);
}
#endif #endif
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 os/proc-wait already finished for proc, os/proc-kill raises an error. After " "handle on windows. If `wait` is truthy, will wait for the process to finish and "
"sending signal to proc, if `wait` is truthy, will wait for the process to finish and return the exit " "returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead."
"code by calling os/proc-wait. Otherwise, returns `proc`. If signal is specified, send it instead. " "Signal keywords are named after their C counterparts but in lowercase with the leading "
"Signal keywords are named after their C counterparts but in lowercase with the leading `SIG` stripped. " "`SIG` stripped. Signals are ignored on windows.") {
"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) {
@@ -757,7 +731,18 @@ JANET_CORE_FN(os_proc_kill,
#else #else
int signal = -1; int signal = -1;
if (argc == 3) { if (argc == 3) {
signal = get_signal_kw(argv, 2); JanetKeyword signal_kw = janet_getkeyword(argv, 2);
const struct keyword_signal *ptr = signal_keywords;
while (ptr->keyword) {
if (!janet_cstrcmp(signal_kw, ptr->keyword)) {
signal = ptr->signal;
break;
}
ptr++;
}
if (signal == -1) {
janet_panic("undefined signal");
}
} }
int status = kill(proc->pid, signal == -1 ? SIGKILL : signal); int status = kill(proc->pid, signal == -1 ? SIGKILL : signal);
if (status) { if (status) {
@@ -779,9 +764,8 @@ 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)",
"Close pipes created by `os/spawn` if they have not been closed. Then, if os/proc-wait was not already " "Wait on a process if it has not been waited on, and close pipes created by `os/spawn` "
"called on proc, os/proc-wait is called on it, and it returns the exit code returned by os/proc-wait. " "if they have not been closed. Returns nil.") {
"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
@@ -819,106 +803,6 @@ static void close_handle(JanetHandle handle) {
#endif #endif
} }
#ifdef JANET_EV
#ifndef JANET_WINDOWS
static void janet_signal_callback(JanetEVGenericMessage msg) {
int sig = msg.tag;
if (msg.argi) janet_interpreter_interrupt_handled(NULL);
Janet handlerv = janet_table_get(&janet_vm.signal_handlers, janet_wrap_integer(sig));
if (!janet_checktype(handlerv, JANET_FUNCTION)) {
/* Let another thread/process try to handle this */
sigset_t set;
sigemptyset(&set);
sigaddset(&set, sig);
#ifdef JANET_THREADS
pthread_sigmask(SIG_BLOCK, &set, NULL);
#else
sigprocmask(SIG_BLOCK, &set, NULL);
#endif
raise(sig);
return;
}
JanetFunction *handler = janet_unwrap_function(handlerv);
JanetFiber *fiber = janet_fiber(handler, 64, 0, NULL);
janet_schedule_soon(fiber, janet_wrap_nil(), JANET_SIGNAL_OK);
}
static void janet_signal_trampoline_no_interrupt(int sig) {
/* Do not interact with global janet state here except for janet_ev_post_event, unsafe! */
JanetEVGenericMessage msg;
memset(&msg, 0, sizeof(msg));
msg.tag = sig;
janet_ev_post_event(&janet_vm, janet_signal_callback, msg);
}
static void janet_signal_trampoline(int sig) {
/* Do not interact with global janet state here except for janet_ev_post_event, unsafe! */
JanetEVGenericMessage msg;
memset(&msg, 0, sizeof(msg));
msg.tag = sig;
msg.argi = 1;
janet_interpreter_interrupt(NULL);
janet_ev_post_event(&janet_vm, janet_signal_callback, msg);
}
#endif
JANET_CORE_FN(os_sigaction,
"(os/sigaction which &opt handler interrupt-interpreter)",
"Add a signal handler for a given action. Use nil for the `handler` argument to remove a signal handler. "
"All signal handlers are the same as supported by `os/proc-kill`.") {
janet_sandbox_assert(JANET_SANDBOX_SIGNAL);
janet_arity(argc, 1, 3);
#ifdef JANET_WINDOWS
(void) argv;
janet_panic("unsupported on this platform");
#else
/* TODO - per thread signal masks */
int rc;
int sig = get_signal_kw(argv, 0);
JanetFunction *handler = janet_optfunction(argv, argc, 1, NULL);
int can_interrupt = janet_optboolean(argv, argc, 2, 0);
Janet oldhandler = janet_table_get(&janet_vm.signal_handlers, janet_wrap_integer(sig));
if (!janet_checktype(oldhandler, JANET_NIL)) {
janet_gcunroot(oldhandler);
}
if (NULL != handler) {
Janet handlerv = janet_wrap_function(handler);
janet_gcroot(handlerv);
janet_table_put(&janet_vm.signal_handlers, janet_wrap_integer(sig), handlerv);
} else {
janet_table_put(&janet_vm.signal_handlers, janet_wrap_integer(sig), janet_wrap_nil());
}
struct sigaction action;
sigset_t mask;
sigaddset(&mask, sig);
memset(&action, 0, sizeof(action));
action.sa_flags |= SA_RESTART;
if (can_interrupt) {
#ifdef JANET_NO_INTERPRETER_INTERRUPT
janet_panic("interpreter interrupt not enabled");
#else
action.sa_handler = janet_signal_trampoline;
#endif
} else {
action.sa_handler = janet_signal_trampoline_no_interrupt;
}
action.sa_mask = mask;
RETRY_EINTR(rc, sigaction(sig, &action, NULL));
sigset_t set;
sigemptyset(&set);
sigaddset(&set, sig);
#ifdef JANET_THREADS
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
#else
sigprocmask(SIG_UNBLOCK, &set, NULL);
#endif
return janet_wrap_nil();
#endif
}
#endif
/* Create piped file for os/execute and os/spawn. Need to be careful that we mark /* Create piped file for os/execute and os/spawn. Need to be careful that we mark
the error flag if we can't create pipe and don't leak handles. *handle will be cleaned the error flag if we can't create pipe and don't leak handles. *handle will be cleaned
up by the calling function. If everything goes well, *handle is owned by the calling function, up by the calling function. If everything goes well, *handle is owned by the calling function,
@@ -1098,18 +982,11 @@ static JanetFile *get_stdio_for_handle(JanetHandle handle, void *orig, int iswri
} }
#endif #endif
typedef enum { static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
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");
@@ -1133,7 +1010,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
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 && (mode != JANET_EXECUTE_EXEC)) { if (argc > 2) {
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"));
@@ -1254,32 +1131,12 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
* 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);
@@ -1386,63 +1243,22 @@ 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. "
":in, :out, and :err should be core/file values or core/stream values. core/file values and core/stream " "These arguments should be core/file values. "
"values passed to :in, :out, and :err should be closed manually because os/execute doesn't close them. " "Returns the exit status of the program.") {
"Returns the exit code of the program.") { return os_execute_impl(argc, argv, 0);
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. For each of the :in, :out, and :err keys " "same arguments as `os/execute`. Does not wait for the process. "
"of the `env` argument, one can also pass in the keyword `:pipe` to get streams for standard IO of the " "For each of the :in, :out, and :err keys to the `env` argument, one "
"subprocess that can be read from and written to. The returned value `proc` has the fields :in, :out, " "can also pass in the keyword `:pipe` "
":err, and the additional field :pid on unix-like platforms. `(os/proc-wait proc)` must be called to " "to get streams for standard IO of the subprocess that can be read from and written to. "
"rejoin the subprocess. After `(os/proc-wait proc)` finishes, proc gains a new field, :return-code. " "The returned value `proc` has the fields :in, :out, :err, :return-code, and "
"If :x flag is passed to os/spawn, non-zero exit code will cause os/proc-wait to raise an error. " "the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
"If pipe streams created with :pipe keyword are not closed in time, janet can run out of file " "subprocess or `(os/proc-kill proc)`.") {
"descriptors. They can be closed individually, or `os/proc-close` can close all pipe streams on proc. " return os_execute_impl(argc, argv, 1);
"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
@@ -1518,8 +1334,8 @@ JANET_CORE_FN(os_getenv,
janet_sandbox_assert(JANET_SANDBOX_ENV); janet_sandbox_assert(JANET_SANDBOX_ENV);
janet_arity(argc, 1, 2); janet_arity(argc, 1, 2);
const char *cstr = janet_getcstring(argv, 0); const char *cstr = janet_getcstring(argv, 0);
janet_lock_environ();
const char *res = getenv(cstr); const char *res = getenv(cstr);
janet_lock_environ();
Janet ret = res Janet ret = res
? janet_cstringv(res) ? janet_cstringv(res)
: argc == 2 : argc == 2
@@ -1564,51 +1380,34 @@ JANET_CORE_FN(os_time,
} }
JANET_CORE_FN(os_clock, JANET_CORE_FN(os_clock,
"(os/clock &opt source format)", "(os/clock &opt source)",
"Return the current time of the requested clock source.\n\n" "Return the number of whole + fractional seconds 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, 2); janet_arity(argc, 0, 1);
enum JanetTimeSource source = JANET_TIME_REALTIME;
JanetKeyword sourcestr = janet_optkeyword(argv, argc, 0, (const uint8_t *) "realtime"); if (argc == 1) {
if (janet_cstrcmp(sourcestr, "realtime") == 0) { JanetKeyword sourcestr = janet_getkeyword(argv, 0);
source = JANET_TIME_REALTIME; if (janet_cstrcmp(sourcestr, "realtime") == 0) {
} else if (janet_cstrcmp(sourcestr, "monotonic") == 0) { source = JANET_TIME_REALTIME;
source = JANET_TIME_MONOTONIC; } else if (janet_cstrcmp(sourcestr, "monotonic") == 0) {
} else if (janet_cstrcmp(sourcestr, "cputime") == 0) { source = JANET_TIME_MONOTONIC;
source = JANET_TIME_CPUTIME; } else if (janet_cstrcmp(sourcestr, "cputime") == 0) {
} else { source = JANET_TIME_CPUTIME;
janet_panicf("expected :realtime, :monotonic, or :cputime, got %v", argv[0]); } else {
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);
JanetKeyword formatstr = janet_optkeyword(argv, argc, 1, (const uint8_t *) "double"); return janet_wrap_number(dtime);
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,
@@ -2724,8 +2523,6 @@ void janet_lib_os(JanetTable *env) {
JANET_CORE_REG("os/execute", os_execute), JANET_CORE_REG("os/execute", os_execute),
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-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),
@@ -2739,7 +2536,6 @@ void janet_lib_os(JanetTable *env) {
#ifdef JANET_EV #ifdef JANET_EV
JANET_CORE_REG("os/open", os_open), /* fs read and write */ JANET_CORE_REG("os/open", os_open), /* fs read and write */
JANET_CORE_REG("os/pipe", os_pipe), JANET_CORE_REG("os/pipe", os_pipe),
JANET_CORE_REG("os/sigaction", os_sigaction),
#endif #endif
#endif #endif
JANET_REG_END JANET_REG_END

View File

@@ -39,10 +39,6 @@
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;
@@ -118,12 +114,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->outer_text_end; c++) { for (const uint8_t *c = s->text_start; c < s->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->outer_text_end; c++) { for (const uint8_t *c = s->text_start; c < s->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;
@@ -183,7 +179,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) { switch (*rule & 0x1F) {
default: default:
janet_panic("unexpected opcode"); janet_panic("unexpected opcode");
return NULL; return NULL;
@@ -486,68 +482,6 @@ 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];
@@ -1173,22 +1107,6 @@ 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
@@ -1272,8 +1190,6 @@ 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},
@@ -1515,7 +1431,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) { switch (instr & 0x1F) {
case RULE_LITERAL: case RULE_LITERAL:
i += 2 + ((rule[1] + 3) >> 2); i += 2 + ((rule[1] + 3) >> 2);
break; break;
@@ -1608,15 +1524,6 @@ 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:
@@ -1745,7 +1652,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, min, -1); janet_arity(argc, get_replace, -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]);
@@ -1770,7 +1677,6 @@ 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);
@@ -1865,7 +1771,7 @@ JANET_CORE_FN(cfun_peg_replace_all,
} }
JANET_CORE_FN(cfun_peg_replace, JANET_CORE_FN(cfun_peg_replace,
"(peg/replace peg subst text &opt start & args)", "(peg/replace peg repl 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 "

View File

@@ -31,7 +31,6 @@
#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. */
@@ -39,15 +38,11 @@
/* 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" : ("%." STR(DBL_DIG) "g"); x >= JANET_INTMIN_DOUBLE) ? "%.0f" : "%g";
int count; int count;
if (x == 0.0) { if (x == 0.0) {
/* Prevent printing of '-0' */ /* Prevent printing of '-0' */
@@ -777,8 +772,6 @@ 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},
@@ -857,19 +850,13 @@ 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, int); int n = va_arg(args, long);
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 = (int64_t) va_arg(args, int32_t); int64_t n = va_arg(args, int);
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;
} }
@@ -877,7 +864,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, uint64_t); uint64_t n = va_arg(args, unsigned int);
nb = snprintf(item, MAX_ITEM, form, n); nb = snprintf(item, MAX_ITEM, form, n);
break; break;
} }
@@ -921,7 +908,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, int); int types = va_arg(args, long);
pushtypes(b, types); pushtypes(b, types);
break; break;
} }
@@ -1030,8 +1017,6 @@ 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);

View File

@@ -32,7 +32,6 @@ 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));
@@ -48,7 +47,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);
fiber = janet_fiber(f, 64, 0, NULL); JanetFiber *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) {
@@ -58,20 +57,12 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
} }
} else { } else {
ret = janet_wrap_string(cres.error); ret = janet_wrap_string(cres.error);
int32_t line = (int32_t) parser.line;
int32_t col = (int32_t) parser.column;
if ((cres.error_mapping.line > 0) &&
(cres.error_mapping.column > 0)) {
line = cres.error_mapping.line;
col = cres.error_mapping.column;
}
if (cres.macrofiber) { if (cres.macrofiber) {
janet_eprintf("%s:%d:%d: compile error", sourcePath, janet_eprintf("compile error in %s: ", sourcePath);
line, col);
janet_stacktrace_ext(cres.macrofiber, ret, ""); janet_stacktrace_ext(cres.macrofiber, ret, "");
} else { } else {
janet_eprintf("%s:%d:%d: compile error: %s\n", sourcePath, janet_eprintf("compile error in %s: %s\n", sourcePath,
line, col, (const char *)cres.error); (const char *)cres.error);
} }
errflags |= 0x02; errflags |= 0x02;
done = 1; done = 1;
@@ -113,14 +104,9 @@ 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) {
if (fiber) { janet_gcroot(ret);
janet_gcroot(janet_wrap_fiber(fiber));
}
janet_loop(); janet_loop();
if (fiber) { janet_gcunroot(ret);
janet_gcunroot(janet_wrap_fiber(fiber));
ret = fiber->last_value;
}
} }
#endif #endif
if (out) *out = ret; if (out) *out = ret;

View File

@@ -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 destructuring, got %v", left)); janetc_error(c, janet_formatc("unexpected type in destruction, got %v", left));
return 1; return 1;
case JANET_SYMBOL: case JANET_SYMBOL:
/* Leaf, assign right to left */ /* Leaf, assign right to left */
@@ -530,26 +530,6 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
return ret; return ret;
} }
/* Check if a form matches the pattern (= nil _) or (not= nil _) */
static int janetc_check_nil_form(Janet x, Janet *capture, uint32_t fun_tag) {
if (!janet_checktype(x, JANET_TUPLE)) return 0;
JanetTuple tup = janet_unwrap_tuple(x);
if (3 != janet_tuple_length(tup)) return 0;
Janet op1 = tup[0];
if (!janet_checktype(op1, JANET_FUNCTION)) return 0;
JanetFunction *fun = janet_unwrap_function(op1);
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
if (tag != fun_tag) return 0;
if (janet_checktype(tup[1], JANET_NIL)) {
*capture = tup[2];
return 1;
} else if (janet_checktype(tup[2], JANET_NIL)) {
*capture = tup[1];
return 1;
}
return 0;
}
/* /*
* :condition * :condition
* ... * ...
@@ -570,7 +550,6 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetScope condscope, tempscope; JanetScope condscope, tempscope;
const int tail = opts.flags & JANET_FOPTS_TAIL; const int tail = opts.flags & JANET_FOPTS_TAIL;
const int drop = opts.flags & JANET_FOPTS_DROP; const int drop = opts.flags & JANET_FOPTS_DROP;
uint8_t ifnjmp = JOP_JUMP_IF_NOT;
if (argn < 2 || argn > 3) { if (argn < 2 || argn > 3) {
janetc_cerror(c, "expected 2 or 3 arguments to if"); janetc_cerror(c, "expected 2 or 3 arguments to if");
@@ -593,24 +572,12 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Compile condition */ /* Compile condition */
janetc_scope(&condscope, c, 0, "if"); janetc_scope(&condscope, c, 0, "if");
cond = janetc_value(condopts, argv[0]);
Janet condform = argv[0];
if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
ifnjmp = JOP_JUMP_IF_NOT_NIL;
} else if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
ifnjmp = JOP_JUMP_IF_NIL;
}
cond = janetc_value(condopts, condform);
/* 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) {
int swap_condition = 0; if (!janet_truthy(cond.constant)) {
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;
@@ -628,7 +595,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
} }
/* Compile jump to right */ /* Compile jump to right */
labeljr = janetc_emit_si(c, ifnjmp, cond, 0, 0); labeljr = janetc_emit_si(c, JOP_JUMP_IF_NOT, cond, 0, 0);
/* Condition left body */ /* Condition left body */
janetc_scope(&tempscope, c, 0, "if-true"); janetc_scope(&tempscope, c, 0, "if-true");
@@ -638,7 +605,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Compile jump to done */ /* Compile jump to done */
labeljd = janet_v_count(c->buffer); labeljd = janet_v_count(c->buffer);
if (!tail && !(drop && janet_checktype(falsebody, JANET_NIL))) janetc_emit(c, JOP_JUMP); if (!tail) janetc_emit(c, JOP_JUMP);
/* Compile right body */ /* Compile right body */
labelr = janet_v_count(c->buffer); labelr = janet_v_count(c->buffer);
@@ -749,8 +716,9 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
if (!(scope->flags & JANET_SCOPE_WHILE) && argn) { if (!(scope->flags & JANET_SCOPE_WHILE) && argn) {
/* Closure body with return argument */ /* Closure body with return argument */
subopts.flags |= JANET_FOPTS_TAIL; subopts.flags |= JANET_FOPTS_TAIL;
janetc_value(subopts, argv[0]); JanetSlot ret = janetc_value(subopts, argv[0]);
return janetc_cslot(janet_wrap_nil()); ret.flags |= JANET_SLOT_RETURNED;
return ret;
} else { } else {
/* while loop IIFE or no argument */ /* while loop IIFE or no argument */
if (argn) { if (argn) {
@@ -758,7 +726,9 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_value(subopts, argv[0]); janetc_value(subopts, argv[0]);
} }
janetc_emit(c, JOP_RETURN_NIL); janetc_emit(c, JOP_RETURN_NIL);
return janetc_cslot(janet_wrap_nil()); JanetSlot s = janetc_cslot(janet_wrap_nil());
s.flags |= JANET_SLOT_RETURNED;
return s;
} }
} else { } else {
if (argn) { if (argn) {
@@ -771,6 +741,20 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
} }
} }
/* Check if a form matches the pattern (not= nil _) */
static int janetc_check_notnil_form(Janet x, Janet *capture) {
if (!janet_checktype(x, JANET_TUPLE)) return 0;
JanetTuple tup = janet_unwrap_tuple(x);
if (!janet_checktype(tup[0], JANET_FUNCTION)) return 0;
if (3 != janet_tuple_length(tup)) return 0;
JanetFunction *fun = janet_unwrap_function(tup[0]);
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
if (tag != JANET_FUN_NEQ) return 0;
if (!janet_checktype(tup[1], JANET_NIL)) return 0;
*capture = tup[2];
return 1;
}
/* /*
* :whiletop * :whiletop
* ... * ...
@@ -787,7 +771,6 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
JanetScope tempscope; JanetScope tempscope;
int32_t labelwt, labeld, labeljt, labelc, i; int32_t labelwt, labeld, labeljt, labelc, i;
int infinite = 0; int infinite = 0;
int is_nil_form = 0;
int is_notnil_form = 0; int is_notnil_form = 0;
uint8_t ifjmp = JOP_JUMP_IF; uint8_t ifjmp = JOP_JUMP_IF;
uint8_t ifnjmp = JOP_JUMP_IF_NOT; uint8_t ifnjmp = JOP_JUMP_IF_NOT;
@@ -801,16 +784,11 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_scope(&tempscope, c, JANET_SCOPE_WHILE, "while"); janetc_scope(&tempscope, c, JANET_SCOPE_WHILE, "while");
/* Check for `(= nil _)` or `(not= nil _)` in condition, and if so, use the /* Check for `(not= nil _)` in condition, and if so, use the
* 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(condform, &condform, JANET_FUN_EQ)) { if (janetc_check_notnil_form(condform, &condform)) {
is_nil_form = 1;
ifjmp = JOP_JUMP_IF_NIL;
ifnjmp = JOP_JUMP_IF_NOT_NIL;
}
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;
@@ -822,9 +800,7 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
/* Check for constant condition */ /* Check for constant condition */
if (cond.flags & JANET_SLOT_CONSTANT) { if (cond.flags & JANET_SLOT_CONSTANT) {
/* Loop never executes */ /* Loop never executes */
int never_executes = is_nil_form int never_executes = is_notnil_form
? !janet_checktype(cond.constant, JANET_NIL)
: is_notnil_form
? janet_checktype(cond.constant, JANET_NIL) ? janet_checktype(cond.constant, JANET_NIL)
: !janet_truthy(cond.constant); : !janet_truthy(cond.constant);
if (never_executes) { if (never_executes) {

View File

@@ -24,11 +24,6 @@
#include "features.h" #include "features.h"
#include <janet.h> #include <janet.h>
#include "state.h" #include "state.h"
#include "util.h"
#endif
#ifdef JANET_WINDOWS
#include <windows.h>
#endif #endif
JANET_THREAD_LOCAL JanetVM janet_vm; JANET_THREAD_LOCAL JanetVM janet_vm;
@@ -62,10 +57,5 @@ void janet_vm_load(JanetVM *from) {
* use NULL to interrupt the current VM when convenient */ * use NULL to interrupt the current VM when convenient */
void janet_interpreter_interrupt(JanetVM *vm) { void janet_interpreter_interrupt(JanetVM *vm) {
vm = vm ? vm : &janet_vm; vm = vm ? vm : &janet_vm;
janet_atomic_inc(&vm->auto_suspend); vm->auto_suspend = 1;
}
void janet_interpreter_interrupt_handled(JanetVM *vm) {
vm = vm ? vm : &janet_vm;
janet_atomic_dec(&vm->auto_suspend);
} }

View File

@@ -89,7 +89,7 @@ struct JanetVM {
/* If this flag is true, suspend on function calls and backwards jumps. /* If this flag is true, suspend on function calls and backwards jumps.
* When this occurs, this flag will be reset to 0. */ * When this occurs, this flag will be reset to 0. */
volatile JanetAtomicInt auto_suspend; int auto_suspend;
/* The current running fiber on the current thread. /* The current running fiber on the current thread.
* Set and unset by functions in vm.c */ * Set and unset by functions in vm.c */
@@ -121,12 +121,10 @@ struct JanetVM {
/* Garbage collection */ /* Garbage collection */
void *blocks; void *blocks;
void *weak_blocks;
size_t gc_interval; size_t gc_interval;
size_t next_collection; size_t next_collection;
size_t block_count; size_t block_count;
int gc_suspend; int gc_suspend;
int gc_mark_phase;
/* GC roots */ /* GC roots */
Janet *roots; Janet *roots;
@@ -156,10 +154,12 @@ struct JanetVM {
JanetQueue spawn; JanetQueue spawn;
JanetTimeout *tq; JanetTimeout *tq;
JanetRNG ev_rng; JanetRNG ev_rng;
volatile JanetAtomicInt listener_count; /* used in signal handler, must be volatile */ JanetListenerState **listeners;
size_t listener_count;
size_t listener_cap;
size_t extra_listeners;
JanetTable threaded_abstracts; /* All abstract types that can be shared between threads (used in this thread) */ JanetTable threaded_abstracts; /* All abstract types that can be shared between threads (used in this thread) */
JanetTable active_tasks; /* All possibly live task fibers - used just for tracking */ JanetTable active_tasks; /* All possibly live task fibers - used just for tracking */
JanetTable signal_handlers;
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
void **iocp; void **iocp;
#elif defined(JANET_EV_EPOLL) #elif defined(JANET_EV_EPOLL)
@@ -175,9 +175,6 @@ struct JanetVM {
int timer; int timer;
int timer_enabled; int timer_enabled;
#else #else
JanetStream **streams;
size_t stream_count;
size_t stream_capacity;
pthread_attr_t new_thread_attr; pthread_attr_t new_thread_attr;
JanetHandle selfpipe[2]; JanetHandle selfpipe[2];
struct pollfd *fds; struct pollfd *fds;

View File

@@ -175,9 +175,8 @@ JANET_CORE_FN(cfun_string_slice,
"Returns a substring from a byte sequence. The substring is from " "Returns a substring from a byte sequence. The substring is from "
"index `start` inclusive to index `end`, exclusive. All indexing " "index `start` inclusive to index `end`, exclusive. All indexing "
"is from 0. `start` and `end` can also be negative to indicate indexing " "is from 0. `start` and `end` can also be negative to indicate indexing "
"from the end of the string. Note that if `start` is negative it is " "from the end of the string. Note that index -1 is synonymous with "
"exclusive, and if `end` is negative it is inclusive, to allow a full " "index `(length bytes)` to allow a full negative slice range. ") {
"negative slice range.") {
JanetByteView view = janet_getbytes(argv, 0); JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv); JanetRange range = janet_getslice(argc, argv);
return janet_stringv(view.bytes + range.start, range.end - range.start); return janet_stringv(view.bytes + range.start, range.end - range.start);
@@ -549,12 +548,12 @@ 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)\n" "- `v`: format with (describe x)"
"- `V`: format with (string x)\n" "- `V`: format with (string x)"
"- `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 "
"variants generate colored output. These specifiers can take a precision " "variants generate colored output. These speficiers can take a precision "
"argument to specify the maximum nesting depth to print.\n" "argument to specify the maximum nesting depth to print.\n"
"- `p`, `P`: pretty format, truncating if necessary\n" "- `p`, `P`: pretty format, truncating if necessary\n"
"- `m`, `M`: pretty format without truncating.\n" "- `m`, `M`: pretty format without truncating.\n"

View File

@@ -234,7 +234,6 @@ 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;
} }

View File

@@ -87,27 +87,11 @@ void janet_table_deinit(JanetTable *table) {
} }
/* Create a new table */ /* Create a new table */
JanetTable *janet_table(int32_t capacity) { JanetTable *janet_table(int32_t capacity) {
JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable)); JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable));
return janet_table_init_impl(table, capacity, 0); return janet_table_init_impl(table, capacity, 0);
} }
JanetTable *janet_table_weakk(int32_t capacity) {
JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE_WEAKK, sizeof(JanetTable));
return janet_table_init_impl(table, capacity, 0);
}
JanetTable *janet_table_weakv(int32_t capacity) {
JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE_WEAKV, sizeof(JanetTable));
return janet_table_init_impl(table, capacity, 0);
}
JanetTable *janet_table_weakkv(int32_t capacity) {
JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE_WEAKKV, sizeof(JanetTable));
return janet_table_init_impl(table, capacity, 0);
}
/* Find the bucket that contains the given key. Will also return /* Find the bucket that contains the given key. Will also return
* bucket where key should go if not in the table. */ * bucket where key should go if not in the table. */
JanetKV *janet_table_find(JanetTable *t, Janet key) { JanetKV *janet_table_find(JanetTable *t, Janet key) {
@@ -127,11 +111,12 @@ static void janet_table_rehash(JanetTable *t, int32_t size) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
} }
int32_t oldcapacity = t->capacity; int32_t i, oldcapacity;
oldcapacity = t->capacity;
t->data = newdata; t->data = newdata;
t->capacity = size; t->capacity = size;
t->deleted = 0; t->deleted = 0;
for (int32_t i = 0; i < oldcapacity; i++) { for (i = 0; i < oldcapacity; i++) {
JanetKV *kv = olddata + i; JanetKV *kv = olddata + i;
if (!janet_checktype(kv->key, JANET_NIL)) { if (!janet_checktype(kv->key, JANET_NIL)) {
JanetKV *newkv = janet_table_find(t, kv->key); JanetKV *newkv = janet_table_find(t, kv->key);
@@ -313,46 +298,11 @@ JANET_CORE_FN(cfun_table_new,
"Creates a new empty table with pre-allocated memory " "Creates a new empty table with pre-allocated memory "
"for `capacity` entries. This means that if one knows the number of " "for `capacity` entries. This means that if one knows the number of "
"entries going into a table on creation, extra memory allocation " "entries going into a table on creation, extra memory allocation "
"can be avoided. " "can be avoided. Returns the new table.") {
"Returns the new table.") {
janet_fixarity(argc, 1); janet_fixarity(argc, 1);
int32_t cap = janet_getnat(argv, 0); int32_t cap = janet_getnat(argv, 0);
return janet_wrap_table(janet_table(cap)); return janet_wrap_table(janet_table(cap));
} }
/*
uint32_t flags = janet_getflags(argv, 1, "kv");
if (flags == 0) return janet_wrap_table(janet_table(cap));
if (flags == 1) return janet_wrap_table(janet_table_weakk(cap));
if (flags == 2) return janet_wrap_table(janet_table_weakv(cap));
return janet_wrap_table(janet_table_weakkv(cap));
*/
JANET_CORE_FN(cfun_table_weak,
"(table/weak capacity)",
"Creates a new empty table with weak references to keys and values. Similar to `table/new`. "
"Returns the new table.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getnat(argv, 0);
return janet_wrap_table(janet_table_weakkv(cap));
}
JANET_CORE_FN(cfun_table_weak_keys,
"(table/weak-keys capacity)",
"Creates a new empty table with weak references to keys and normal references to values. Similar to `table/new`. "
"Returns the new table.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getnat(argv, 0);
return janet_wrap_table(janet_table_weakk(cap));
}
JANET_CORE_FN(cfun_table_weak_values,
"(table/weak-values capacity)",
"Creates a new empty table with normal references to keys and weak references to values. Similar to `table/new`. "
"Returns the new table.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getnat(argv, 0);
return janet_wrap_table(janet_table_weakv(cap));
}
JANET_CORE_FN(cfun_table_getproto, JANET_CORE_FN(cfun_table_getproto,
"(table/getproto tab)", "(table/getproto tab)",
@@ -427,9 +377,6 @@ JANET_CORE_FN(cfun_table_proto_flatten,
void janet_lib_table(JanetTable *env) { void janet_lib_table(JanetTable *env) {
JanetRegExt table_cfuns[] = { JanetRegExt table_cfuns[] = {
JANET_CORE_REG("table/new", cfun_table_new), JANET_CORE_REG("table/new", cfun_table_new),
JANET_CORE_REG("table/weak", cfun_table_weak),
JANET_CORE_REG("table/weak-keys", cfun_table_weak_keys),
JANET_CORE_REG("table/weak-values", cfun_table_weak_values),
JANET_CORE_REG("table/to-struct", cfun_table_tostruct), JANET_CORE_REG("table/to-struct", cfun_table_tostruct),
JANET_CORE_REG("table/getproto", cfun_table_getproto), JANET_CORE_REG("table/getproto", cfun_table_getproto),
JANET_CORE_REG("table/setproto", cfun_table_setproto), JANET_CORE_REG("table/setproto", cfun_table_setproto),

View File

@@ -69,9 +69,9 @@ JANET_CORE_FN(cfun_tuple_slice,
"inclusive to index `end` exclusive. If `start` or `end` are not provided, " "inclusive to index `end` exclusive. If `start` or `end` are not provided, "
"they default to 0 and the length of `arrtup`, respectively. " "they default to 0 and the length of `arrtup`, respectively. "
"`start` and `end` can also be negative to indicate indexing " "`start` and `end` can also be negative to indicate indexing "
"from the end of the input. Note that if `start` is negative it is " "from the end of the input. Note that index -1 is synonymous with "
"exclusive, and if `end` is negative it is inclusive, to allow a full " "index `(length arrtup)` to allow a full negative slice range. "
"negative slice range. Returns the new tuple.") { "Returns the new tuple.") {
JanetView view = janet_getindexed(argv, 0); JanetView view = janet_getindexed(argv, 0);
JanetRange range = janet_getslice(argc, argv); JanetRange range = janet_getslice(argc, argv);
return janet_wrap_tuple(janet_tuple_n(view.items + range.start, range.end - range.start)); return janet_wrap_tuple(janet_tuple_n(view.items + range.start, range.end - range.start));

View File

@@ -960,7 +960,6 @@ 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;
@@ -972,10 +971,7 @@ int janet_cryptorand(uint8_t *out, size_t n) {
} }
} }
return 0; return 0;
#elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7) #elif defined(JANET_LINUX) || defined(JANET_CYGWIN) || ( defined(JANET_APPLE) && !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.
@@ -997,10 +993,12 @@ int janet_cryptorand(uint8_t *out, size_t n) {
} }
RETRY_EINTR(rc, close(randfd)); RETRY_EINTR(rc, close(randfd));
return 0; return 0;
#endif #elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
arc4random_buf(out, n);
return 0;
#else #else
(void) out;
(void) n; (void) n;
(void) out;
return -1; return -1;
#endif #endif
} }

View File

@@ -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 internal error at line %d in file %s: %s\n",\ fprintf(stderr, "C runtime error at line %d in file %s: %s\n",\
__LINE__,\ __LINE__,\
__FILE__,\ __FILE__,\
(m));\ (m));\
abort();\ exit(1);\
} while (0) } while (0)
#endif #endif

View File

@@ -116,6 +116,7 @@
#else #else
#define vm_maybe_auto_suspend(COND) do { \ #define vm_maybe_auto_suspend(COND) do { \
if ((COND) && janet_vm.auto_suspend) { \ if ((COND) && janet_vm.auto_suspend) { \
janet_vm.auto_suspend = 0; \
fiber->flags |= (JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP); \ fiber->flags |= (JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP); \
vm_return(JANET_SIGNAL_INTERRUPT, janet_wrap_nil()); \ vm_return(JANET_SIGNAL_INTERRUPT, janet_wrap_nil()); \
} \ } \
@@ -799,13 +800,13 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
VM_OP(JOP_JUMP) VM_OP(JOP_JUMP)
pc += DS; pc += DS;
vm_maybe_auto_suspend(DS <= 0); vm_maybe_auto_suspend(DS < 0);
vm_next(); vm_next();
VM_OP(JOP_JUMP_IF) VM_OP(JOP_JUMP_IF)
if (janet_truthy(stack[A])) { if (janet_truthy(stack[A])) {
pc += ES; pc += ES;
vm_maybe_auto_suspend(ES <= 0); vm_maybe_auto_suspend(ES < 0);
} else { } else {
pc++; pc++;
} }
@@ -816,14 +817,14 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
pc++; pc++;
} else { } else {
pc += ES; pc += ES;
vm_maybe_auto_suspend(ES <= 0); vm_maybe_auto_suspend(ES < 0);
} }
vm_next(); vm_next();
VM_OP(JOP_JUMP_IF_NIL) VM_OP(JOP_JUMP_IF_NIL)
if (janet_checktype(stack[A], JANET_NIL)) { if (janet_checktype(stack[A], JANET_NIL)) {
pc += ES; pc += ES;
vm_maybe_auto_suspend(ES <= 0); vm_maybe_auto_suspend(ES < 0);
} else { } else {
pc++; pc++;
} }
@@ -834,7 +835,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
pc++; pc++;
} else { } else {
pc += ES; pc += ES;
vm_maybe_auto_suspend(ES <= 0); vm_maybe_auto_suspend(ES < 0);
} }
vm_next(); vm_next();
@@ -861,7 +862,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_pcnext(); vm_pcnext();
VM_OP(JOP_EQUALS_IMMEDIATE) VM_OP(JOP_EQUALS_IMMEDIATE)
stack[A] = janet_wrap_boolean(janet_checktype(stack[B], JANET_NUMBER) && (janet_unwrap_number(stack[B]) == (double) CS)); stack[A] = janet_wrap_boolean(janet_unwrap_number(stack[B]) == (double) CS);
vm_pcnext(); vm_pcnext();
VM_OP(JOP_NOT_EQUALS) VM_OP(JOP_NOT_EQUALS)
@@ -869,7 +870,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_pcnext(); vm_pcnext();
VM_OP(JOP_NOT_EQUALS_IMMEDIATE) VM_OP(JOP_NOT_EQUALS_IMMEDIATE)
stack[A] = janet_wrap_boolean(!janet_checktype(stack[B], JANET_NUMBER) || (janet_unwrap_number(stack[B]) != (double) CS)); stack[A] = janet_wrap_boolean(janet_unwrap_number(stack[B]) != (double) CS);
vm_pcnext(); vm_pcnext();
VM_OP(JOP_COMPARE) VM_OP(JOP_COMPARE)
@@ -1585,11 +1586,9 @@ int janet_init(void) {
/* Garbage collection */ /* Garbage collection */
janet_vm.blocks = NULL; janet_vm.blocks = NULL;
janet_vm.weak_blocks = NULL;
janet_vm.next_collection = 0; janet_vm.next_collection = 0;
janet_vm.gc_interval = 0x400000; janet_vm.gc_interval = 0x400000;
janet_vm.block_count = 0; janet_vm.block_count = 0;
janet_vm.gc_mark_phase = 0;
janet_symcache_init(); janet_symcache_init();

View File

@@ -43,10 +43,10 @@ int (janet_truthy)(Janet x) {
return janet_truthy(x); return janet_truthy(x);
} }
JanetStruct(janet_unwrap_struct)(Janet x) { const JanetKV *(janet_unwrap_struct)(Janet x) {
return janet_unwrap_struct(x); return janet_unwrap_struct(x);
} }
JanetTuple(janet_unwrap_tuple)(Janet x) { const Janet *(janet_unwrap_tuple)(Janet x) {
return janet_unwrap_tuple(x); return janet_unwrap_tuple(x);
} }
JanetFiber *(janet_unwrap_fiber)(Janet x) { JanetFiber *(janet_unwrap_fiber)(Janet x) {
@@ -61,16 +61,16 @@ JanetTable *(janet_unwrap_table)(Janet x) {
JanetBuffer *(janet_unwrap_buffer)(Janet x) { JanetBuffer *(janet_unwrap_buffer)(Janet x) {
return janet_unwrap_buffer(x); return janet_unwrap_buffer(x);
} }
JanetString(janet_unwrap_string)(Janet x) { const uint8_t *(janet_unwrap_string)(Janet x) {
return janet_unwrap_string(x); return janet_unwrap_string(x);
} }
JanetSymbol(janet_unwrap_symbol)(Janet x) { const uint8_t *(janet_unwrap_symbol)(Janet x) {
return janet_unwrap_symbol(x); return janet_unwrap_symbol(x);
} }
JanetKeyword(janet_unwrap_keyword)(Janet x) { const uint8_t *(janet_unwrap_keyword)(Janet x) {
return janet_unwrap_keyword(x); return janet_unwrap_keyword(x);
} }
JanetAbstract(janet_unwrap_abstract)(Janet x) { void *(janet_unwrap_abstract)(Janet x) {
return janet_unwrap_abstract(x); return janet_unwrap_abstract(x);
} }
void *(janet_unwrap_pointer)(Janet x) { void *(janet_unwrap_pointer)(Janet x) {
@@ -102,22 +102,22 @@ Janet(janet_wrap_false)(void) {
Janet(janet_wrap_boolean)(int x) { Janet(janet_wrap_boolean)(int x) {
return janet_wrap_boolean(x); return janet_wrap_boolean(x);
} }
Janet(janet_wrap_string)(JanetString x) { Janet(janet_wrap_string)(const uint8_t *x) {
return janet_wrap_string(x); return janet_wrap_string(x);
} }
Janet(janet_wrap_symbol)(JanetSymbol x) { Janet(janet_wrap_symbol)(const uint8_t *x) {
return janet_wrap_symbol(x); return janet_wrap_symbol(x);
} }
Janet(janet_wrap_keyword)(JanetKeyword x) { Janet(janet_wrap_keyword)(const uint8_t *x) {
return janet_wrap_keyword(x); return janet_wrap_keyword(x);
} }
Janet(janet_wrap_array)(JanetArray *x) { Janet(janet_wrap_array)(JanetArray *x) {
return janet_wrap_array(x); return janet_wrap_array(x);
} }
Janet(janet_wrap_tuple)(JanetTuple x) { Janet(janet_wrap_tuple)(const Janet *x) {
return janet_wrap_tuple(x); return janet_wrap_tuple(x);
} }
Janet(janet_wrap_struct)(JanetStruct x) { Janet(janet_wrap_struct)(const JanetKV *x) {
return janet_wrap_struct(x); return janet_wrap_struct(x);
} }
Janet(janet_wrap_fiber)(JanetFiber *x) { Janet(janet_wrap_fiber)(JanetFiber *x) {
@@ -135,7 +135,7 @@ Janet(janet_wrap_cfunction)(JanetCFunction x) {
Janet(janet_wrap_table)(JanetTable *x) { Janet(janet_wrap_table)(JanetTable *x) {
return janet_wrap_table(x); return janet_wrap_table(x);
} }
Janet(janet_wrap_abstract)(JanetAbstract x) { Janet(janet_wrap_abstract)(void *x) {
return janet_wrap_abstract(x); return janet_wrap_abstract(x);
} }
Janet(janet_wrap_pointer)(void *x) { Janet(janet_wrap_pointer)(void *x) {
@@ -317,3 +317,4 @@ JANET_WRAP_DEFINE(pointer, void *, JANET_POINTER, pointer)
#undef JANET_WRAP_DEFINE #undef JANET_WRAP_DEFINE
#endif #endif

View File

@@ -234,28 +234,10 @@ extern "C" {
#define JANET_EV_KQUEUE #define JANET_EV_KQUEUE
#endif #endif
/* Use poll as last resort */
#if !defined(JANET_WINDOWS) && !defined(JANET_EV_EPOLL) && !defined(JANET_EV_KQUEUE)
#define JANET_EV_POLL
#endif
/* How to export symbols */ /* How to export symbols */
#ifndef JANET_EXPORT
#ifdef JANET_WINDOWS
#define JANET_EXPORT __declspec(dllexport)
#else
#define JANET_EXPORT __attribute__((visibility ("default")))
#endif
#endif
/* How declare API functions */
#ifndef JANET_API #ifndef JANET_API
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
#ifdef JANET_DLL_IMPORT
#define JANET_API __declspec(dllimport)
#else
#define JANET_API __declspec(dllexport) #define JANET_API __declspec(dllexport)
#endif
#else #else
#define JANET_API __attribute__((visibility ("default"))) #define JANET_API __attribute__((visibility ("default")))
#endif #endif
@@ -411,11 +393,12 @@ typedef enum {
JANET_SIGNAL_USER6, JANET_SIGNAL_USER6,
JANET_SIGNAL_USER7, JANET_SIGNAL_USER7,
JANET_SIGNAL_USER8, JANET_SIGNAL_USER8,
JANET_SIGNAL_USER9, JANET_SIGNAL_USER9
JANET_SIGNAL_INTERRUPT = JANET_SIGNAL_USER8,
JANET_SIGNAL_EVENT = JANET_SIGNAL_USER9,
} JanetSignal; } JanetSignal;
#define JANET_SIGNAL_EVENT JANET_SIGNAL_USER9
#define JANET_SIGNAL_INTERRUPT JANET_SIGNAL_USER8
/* Fiber statuses - mostly corresponds to signals. */ /* Fiber statuses - mostly corresponds to signals. */
typedef enum { typedef enum {
JANET_STATUS_DEAD, JANET_STATUS_DEAD,
@@ -579,7 +562,7 @@ typedef void *JanetAbstract;
#define JANET_STREAM_CLOSED 0x1 #define JANET_STREAM_CLOSED 0x1
#define JANET_STREAM_SOCKET 0x2 #define JANET_STREAM_SOCKET 0x2
#define JANET_STREAM_UNREGISTERED 0x4 #define JANET_STREAM_IOCP 0x4
#define JANET_STREAM_READABLE 0x200 #define JANET_STREAM_READABLE 0x200
#define JANET_STREAM_WRITABLE 0x400 #define JANET_STREAM_WRITABLE 0x400
#define JANET_STREAM_ACCEPTABLE 0x800 #define JANET_STREAM_ACCEPTABLE 0x800
@@ -587,67 +570,62 @@ typedef void *JanetAbstract;
#define JANET_STREAM_TOCLOSE 0x10000 #define JANET_STREAM_TOCLOSE 0x10000
typedef enum { typedef enum {
JANET_ASYNC_EVENT_INIT = 0, JANET_ASYNC_EVENT_INIT,
JANET_ASYNC_EVENT_MARK = 1, JANET_ASYNC_EVENT_MARK,
JANET_ASYNC_EVENT_DEINIT = 2, JANET_ASYNC_EVENT_DEINIT,
JANET_ASYNC_EVENT_CLOSE = 3, JANET_ASYNC_EVENT_CLOSE,
JANET_ASYNC_EVENT_ERR = 4, JANET_ASYNC_EVENT_ERR,
JANET_ASYNC_EVENT_HUP = 5, JANET_ASYNC_EVENT_HUP,
JANET_ASYNC_EVENT_READ = 6, JANET_ASYNC_EVENT_READ,
JANET_ASYNC_EVENT_WRITE = 7, JANET_ASYNC_EVENT_WRITE,
JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */ JANET_ASYNC_EVENT_CANCEL,
JANET_ASYNC_EVENT_FAILED = 9 /* Used on windows for IOCP */ JANET_ASYNC_EVENT_COMPLETE, /* Used on windows for IOCP */
JANET_ASYNC_EVENT_USER
} JanetAsyncEvent; } JanetAsyncEvent;
typedef enum { #define JANET_ASYNC_LISTEN_READ (1 << JANET_ASYNC_EVENT_READ)
JANET_ASYNC_LISTEN_READ = 1, #define JANET_ASYNC_LISTEN_WRITE (1 << JANET_ASYNC_EVENT_WRITE)
JANET_ASYNC_LISTEN_WRITE,
JANET_ASYNC_LISTEN_BOTH
} JanetAsyncMode;
typedef enum {
JANET_ASYNC_STATUS_NOT_DONE,
JANET_ASYNC_STATUS_DONE
} JanetAsyncStatus;
/* Typedefs */
typedef struct JanetListenerState JanetListenerState;
typedef struct JanetStream JanetStream; typedef struct JanetStream JanetStream;
typedef JanetAsyncStatus(*JanetListener)(JanetListenerState *state, 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 {
JanetHandle handle; JanetHandle handle;
uint32_t flags; uint32_t flags;
uint32_t index; /* Linked list of all in-flight IO routines for this stream */
JanetFiber *read_fiber; JanetListenerState *state;
JanetFiber *write_fiber;
const void *methods; /* Methods for this stream */ const void *methods; /* Methods for this stream */
/* internal - used to disallow multiple concurrent reads / writes on the same stream.
* this constraint may be lifted later but allowing such would require more internal book keeping
* for some implementations. You can read and write at the same time on the same stream, though. */
int _mask;
}; };
typedef void (*JanetEVCallback)(JanetFiber *fiber, JanetAsyncEvent event); /* Interface for state machine based event loop */
struct JanetListenerState {
/* Start listening for events from a stream on the current root fiber. After JanetListener machine;
* calling this, users should call janet_await() before returning from the JanetFiber *fiber;
* current C Function. This also will call janet_await. JanetStream *stream;
* mode is which events to listen for, and callback is the function pointer to void *event; /* Used to pass data from asynchronous IO event. Contents depend on both
* call when ever an event is sent from the event loop. state is an optional (can be NULL) implementation of the event loop and the particular event. */
* 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);
/* 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
/* Janet uses atomic integers in several places for synchronization between threads and
* signals. Define them here */
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
typedef long JanetAtomicInt; void *tag; /* Used to associate listeners with an overlapped structure */
#else int bytes; /* Used to track how many bytes were transfered. */
typedef int32_t JanetAtomicInt; #endif
/* internal */
size_t _index;
int _mask;
JanetListenerState *_next;
};
#endif #endif
JANET_API JanetAtomicInt janet_atomic_inc(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
@@ -675,10 +653,10 @@ JANET_API JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x);
* external bindings, we should prefer using the Head structs directly, and * external bindings, we should prefer using the Head structs directly, and
* use the host language to add sugar around the manipulation of the Janet types. */ * use the host language to add sugar around the manipulation of the Janet types. */
JANET_API JanetStructHead *janet_struct_head(JanetStruct st); JANET_API JanetStructHead *janet_struct_head(const JanetKV *st);
JANET_API JanetAbstractHead *janet_abstract_head(const void *abstract); JANET_API JanetAbstractHead *janet_abstract_head(const void *abstract);
JANET_API JanetStringHead *janet_string_head(JanetString s); JANET_API JanetStringHead *janet_string_head(const uint8_t *s);
JANET_API JanetTupleHead *janet_tuple_head(JanetTuple tuple); JANET_API JanetTupleHead *janet_tuple_head(const Janet *tuple);
/* Some language bindings won't have access to the macro versions. */ /* Some language bindings won't have access to the macro versions. */
@@ -687,16 +665,16 @@ JANET_API int janet_checktype(Janet x, JanetType type);
JANET_API int janet_checktypes(Janet x, int typeflags); JANET_API int janet_checktypes(Janet x, int typeflags);
JANET_API int janet_truthy(Janet x); JANET_API int janet_truthy(Janet x);
JANET_API JanetStruct janet_unwrap_struct(Janet x); JANET_API const JanetKV *janet_unwrap_struct(Janet x);
JANET_API JanetTuple janet_unwrap_tuple(Janet x); JANET_API const Janet *janet_unwrap_tuple(Janet x);
JANET_API JanetFiber *janet_unwrap_fiber(Janet x); JANET_API JanetFiber *janet_unwrap_fiber(Janet x);
JANET_API JanetArray *janet_unwrap_array(Janet x); JANET_API JanetArray *janet_unwrap_array(Janet x);
JANET_API JanetTable *janet_unwrap_table(Janet x); JANET_API JanetTable *janet_unwrap_table(Janet x);
JANET_API JanetBuffer *janet_unwrap_buffer(Janet x); JANET_API JanetBuffer *janet_unwrap_buffer(Janet x);
JANET_API JanetString janet_unwrap_string(Janet x); JANET_API const uint8_t *janet_unwrap_string(Janet x);
JANET_API JanetSymbol janet_unwrap_symbol(Janet x); JANET_API const uint8_t *janet_unwrap_symbol(Janet x);
JANET_API JanetKeyword janet_unwrap_keyword(Janet x); JANET_API const uint8_t *janet_unwrap_keyword(Janet x);
JANET_API JanetAbstract janet_unwrap_abstract(Janet x); JANET_API void *janet_unwrap_abstract(Janet x);
JANET_API void *janet_unwrap_pointer(Janet x); JANET_API void *janet_unwrap_pointer(Janet x);
JANET_API JanetFunction *janet_unwrap_function(Janet x); JANET_API JanetFunction *janet_unwrap_function(Janet x);
JANET_API JanetCFunction janet_unwrap_cfunction(Janet x); JANET_API JanetCFunction janet_unwrap_cfunction(Janet x);
@@ -709,18 +687,18 @@ JANET_API Janet janet_wrap_number(double x);
JANET_API Janet janet_wrap_true(void); JANET_API Janet janet_wrap_true(void);
JANET_API Janet janet_wrap_false(void); JANET_API Janet janet_wrap_false(void);
JANET_API Janet janet_wrap_boolean(int x); JANET_API Janet janet_wrap_boolean(int x);
JANET_API Janet janet_wrap_string(JanetString x); JANET_API Janet janet_wrap_string(const uint8_t *x);
JANET_API Janet janet_wrap_symbol(JanetSymbol x); JANET_API Janet janet_wrap_symbol(const uint8_t *x);
JANET_API Janet janet_wrap_keyword(JanetKeyword x); JANET_API Janet janet_wrap_keyword(const uint8_t *x);
JANET_API Janet janet_wrap_array(JanetArray *x); JANET_API Janet janet_wrap_array(JanetArray *x);
JANET_API Janet janet_wrap_tuple(JanetTuple x); JANET_API Janet janet_wrap_tuple(const Janet *x);
JANET_API Janet janet_wrap_struct(JanetStruct x); JANET_API Janet janet_wrap_struct(const JanetKV *x);
JANET_API Janet janet_wrap_fiber(JanetFiber *x); JANET_API Janet janet_wrap_fiber(JanetFiber *x);
JANET_API Janet janet_wrap_buffer(JanetBuffer *x); JANET_API Janet janet_wrap_buffer(JanetBuffer *x);
JANET_API Janet janet_wrap_function(JanetFunction *x); JANET_API Janet janet_wrap_function(JanetFunction *x);
JANET_API Janet janet_wrap_cfunction(JanetCFunction x); JANET_API Janet janet_wrap_cfunction(JanetCFunction x);
JANET_API Janet janet_wrap_table(JanetTable *x); JANET_API Janet janet_wrap_table(JanetTable *x);
JANET_API Janet janet_wrap_abstract(JanetAbstract x); JANET_API Janet janet_wrap_abstract(void *x);
JANET_API Janet janet_wrap_pointer(void *x); JANET_API Janet janet_wrap_pointer(void *x);
JANET_API Janet janet_wrap_integer(int32_t x); JANET_API Janet janet_wrap_integer(int32_t x);
@@ -752,7 +730,6 @@ JANET_API Janet janet_wrap_integer(int32_t x);
? janet_nanbox_isnumber(x) \ ? janet_nanbox_isnumber(x) \
: janet_nanbox_checkauxtype((x), (t))) : janet_nanbox_checkauxtype((x), (t)))
/* Use JANET_API so that modules will use a local version of these functions if possible */
JANET_API void *janet_nanbox_to_pointer(Janet x); JANET_API void *janet_nanbox_to_pointer(Janet x);
JANET_API Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask); JANET_API Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask);
JANET_API Janet janet_nanbox_from_cpointer(const void *p, uint64_t tagmask); JANET_API Janet janet_nanbox_from_cpointer(const void *p, uint64_t tagmask);
@@ -799,14 +776,14 @@ JANET_API Janet janet_nanbox_from_bits(uint64_t bits);
#define janet_wrap_pointer(s) janet_nanbox_wrap_((s), JANET_POINTER) #define janet_wrap_pointer(s) janet_nanbox_wrap_((s), JANET_POINTER)
/* Unwrap the pointer types */ /* Unwrap the pointer types */
#define janet_unwrap_struct(x) ((JanetStruct)janet_nanbox_to_pointer(x)) #define janet_unwrap_struct(x) ((const JanetKV *)janet_nanbox_to_pointer(x))
#define janet_unwrap_tuple(x) ((JanetTuple)janet_nanbox_to_pointer(x)) #define janet_unwrap_tuple(x) ((const Janet *)janet_nanbox_to_pointer(x))
#define janet_unwrap_fiber(x) ((JanetFiber *)janet_nanbox_to_pointer(x)) #define janet_unwrap_fiber(x) ((JanetFiber *)janet_nanbox_to_pointer(x))
#define janet_unwrap_array(x) ((JanetArray *)janet_nanbox_to_pointer(x)) #define janet_unwrap_array(x) ((JanetArray *)janet_nanbox_to_pointer(x))
#define janet_unwrap_table(x) ((JanetTable *)janet_nanbox_to_pointer(x)) #define janet_unwrap_table(x) ((JanetTable *)janet_nanbox_to_pointer(x))
#define janet_unwrap_buffer(x) ((JanetBuffer *)janet_nanbox_to_pointer(x)) #define janet_unwrap_buffer(x) ((JanetBuffer *)janet_nanbox_to_pointer(x))
#define janet_unwrap_string(x) ((JanetString)janet_nanbox_to_pointer(x)) #define janet_unwrap_string(x) ((const uint8_t *)janet_nanbox_to_pointer(x))
#define janet_unwrap_symbol(x) ((JanetSymbol)janet_nanbox_to_pointer(x)) #define janet_unwrap_symbol(x) ((const uint8_t *)janet_nanbox_to_pointer(x))
#define janet_unwrap_keyword(x) ((const uint8_t *)janet_nanbox_to_pointer(x)) #define janet_unwrap_keyword(x) ((const uint8_t *)janet_nanbox_to_pointer(x))
#define janet_unwrap_abstract(x) (janet_nanbox_to_pointer(x)) #define janet_unwrap_abstract(x) (janet_nanbox_to_pointer(x))
#define janet_unwrap_pointer(x) (janet_nanbox_to_pointer(x)) #define janet_unwrap_pointer(x) (janet_nanbox_to_pointer(x))
@@ -848,15 +825,15 @@ JANET_API Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer);
#define janet_wrap_cfunction(s) janet_nanbox32_from_tagp(JANET_CFUNCTION, (void *)(s)) #define janet_wrap_cfunction(s) janet_nanbox32_from_tagp(JANET_CFUNCTION, (void *)(s))
#define janet_wrap_pointer(s) janet_nanbox32_from_tagp(JANET_POINTER, (void *)(s)) #define janet_wrap_pointer(s) janet_nanbox32_from_tagp(JANET_POINTER, (void *)(s))
#define janet_unwrap_struct(x) ((JanetStruct)(x).tagged.payload.pointer) #define janet_unwrap_struct(x) ((const JanetKV *)(x).tagged.payload.pointer)
#define janet_unwrap_tuple(x) ((JanetTuple)(x).tagged.payload.pointer) #define janet_unwrap_tuple(x) ((const Janet *)(x).tagged.payload.pointer)
#define janet_unwrap_fiber(x) ((JanetFiber *)(x).tagged.payload.pointer) #define janet_unwrap_fiber(x) ((JanetFiber *)(x).tagged.payload.pointer)
#define janet_unwrap_array(x) ((JanetArray *)(x).tagged.payload.pointer) #define janet_unwrap_array(x) ((JanetArray *)(x).tagged.payload.pointer)
#define janet_unwrap_table(x) ((JanetTable *)(x).tagged.payload.pointer) #define janet_unwrap_table(x) ((JanetTable *)(x).tagged.payload.pointer)
#define janet_unwrap_buffer(x) ((JanetBuffer *)(x).tagged.payload.pointer) #define janet_unwrap_buffer(x) ((JanetBuffer *)(x).tagged.payload.pointer)
#define janet_unwrap_string(x) ((JanetString)(x).tagged.payload.pointer) #define janet_unwrap_string(x) ((const uint8_t *)(x).tagged.payload.pointer)
#define janet_unwrap_symbol(x) ((JanetSymbol)(x).tagged.payload.pointer) #define janet_unwrap_symbol(x) ((const uint8_t *)(x).tagged.payload.pointer)
#define janet_unwrap_keyword(x) ((JanetKeyword)(x).tagged.payload.pointer) #define janet_unwrap_keyword(x) ((const uint8_t *)(x).tagged.payload.pointer)
#define janet_unwrap_abstract(x) ((x).tagged.payload.pointer) #define janet_unwrap_abstract(x) ((x).tagged.payload.pointer)
#define janet_unwrap_pointer(x) ((x).tagged.payload.pointer) #define janet_unwrap_pointer(x) ((x).tagged.payload.pointer)
#define janet_unwrap_function(x) ((JanetFunction *)(x).tagged.payload.pointer) #define janet_unwrap_function(x) ((JanetFunction *)(x).tagged.payload.pointer)
@@ -871,15 +848,15 @@ JANET_API Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer);
#define janet_truthy(x) \ #define janet_truthy(x) \
((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.u64 & 0x1))) ((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.u64 & 0x1)))
#define janet_unwrap_struct(x) ((JanetStruct)(x).as.pointer) #define janet_unwrap_struct(x) ((const JanetKV *)(x).as.pointer)
#define janet_unwrap_tuple(x) ((JanetTuple)(x).as.pointer) #define janet_unwrap_tuple(x) ((const Janet *)(x).as.pointer)
#define janet_unwrap_fiber(x) ((JanetFiber *)(x).as.pointer) #define janet_unwrap_fiber(x) ((JanetFiber *)(x).as.pointer)
#define janet_unwrap_array(x) ((JanetArray *)(x).as.pointer) #define janet_unwrap_array(x) ((JanetArray *)(x).as.pointer)
#define janet_unwrap_table(x) ((JanetTable *)(x).as.pointer) #define janet_unwrap_table(x) ((JanetTable *)(x).as.pointer)
#define janet_unwrap_buffer(x) ((JanetBuffer *)(x).as.pointer) #define janet_unwrap_buffer(x) ((JanetBuffer *)(x).as.pointer)
#define janet_unwrap_string(x) ((JanetString)(x).as.pointer) #define janet_unwrap_string(x) ((const uint8_t *)(x).as.pointer)
#define janet_unwrap_symbol(x) ((JanetSymbol)(x).as.pointer) #define janet_unwrap_symbol(x) ((const uint8_t *)(x).as.pointer)
#define janet_unwrap_keyword(x) ((JanetKeyword)(x).as.pointer) #define janet_unwrap_keyword(x) ((const uint8_t *)(x).as.pointer)
#define janet_unwrap_abstract(x) ((x).as.pointer) #define janet_unwrap_abstract(x) ((x).as.pointer)
#define janet_unwrap_pointer(x) ((x).as.pointer) #define janet_unwrap_pointer(x) ((x).as.pointer)
#define janet_unwrap_function(x) ((JanetFunction *)(x).as.pointer) #define janet_unwrap_function(x) ((JanetFunction *)(x).as.pointer)
@@ -912,7 +889,7 @@ struct JanetGCObject {
int32_t flags; int32_t flags;
union { union {
JanetGCObject *next; JanetGCObject *next;
volatile JanetAtomicInt refcount; /* For threaded abstract types */ int32_t refcount; /* For threaded abstract types */
} data; } data;
}; };
@@ -935,10 +912,8 @@ struct JanetFiber {
* that is, fibers that are scheduled on the event loop and behave much like threads * that is, fibers that are scheduled on the event loop and behave much like threads
* in a multi-tasking system. It would be possible to move these fields to a new * in a multi-tasking system. It would be possible to move these fields to a new
* type, say "JanetTask", that as separate from fibers to save a bit of space. */ * type, say "JanetTask", that as separate from fibers to save a bit of space. */
JanetListenerState *waiting;
uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */ uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */
JanetEVCallback ev_callback; /* Call this before starting scheduled fibers */
JanetStream *ev_stream; /* which stream we are waiting on */
void *ev_state; /* Extra data for ev callback state. On windows, first element must be OVERLAPPED. */
void *supervisor_channel; /* Channel to push self to when complete */ void *supervisor_channel; /* Channel to push self to when complete */
#endif #endif
}; };
@@ -1413,7 +1388,9 @@ JANET_API void janet_stream_flags(JanetStream *stream, uint32_t flags);
JANET_API void janet_schedule(JanetFiber *fiber, Janet value); JANET_API void janet_schedule(JanetFiber *fiber, Janet value);
JANET_API void janet_cancel(JanetFiber *fiber, Janet value); JANET_API void janet_cancel(JanetFiber *fiber, Janet value);
JANET_API void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig); JANET_API void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig);
JANET_API void janet_schedule_soon(JanetFiber *fiber, Janet value, JanetSignal sig);
/* Start a state machine listening for events from a stream */
JANET_API JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user);
/* Shorthand for yielding to event loop in C */ /* Shorthand for yielding to event loop in C */
JANET_NO_RETURN JANET_API void janet_await(void); JANET_NO_RETURN JANET_API void janet_await(void);
@@ -1501,22 +1478,23 @@ 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_NO_RETURN JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes); JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
JANET_NO_RETURN JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes); JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
#ifdef JANET_NET #ifdef JANET_NET
JANET_NO_RETURN JANET_API void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags); JANET_API void janet_ev_recv(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_recvchunk(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); JANET_API void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
JANET_API void janet_ev_connect(JanetStream *stream, int flags);
#endif #endif
/* Write async to a stream */ /* Write async to a stream */
JANET_NO_RETURN JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf); JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf);
JANET_NO_RETURN JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str); JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str);
#ifdef JANET_NET #ifdef JANET_NET
JANET_NO_RETURN JANET_API void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags); JANET_API void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags);
JANET_NO_RETURN JANET_API void janet_ev_send_string(JanetStream *stream, JanetString str, int flags); JANET_API void janet_ev_send_string(JanetStream *stream, JanetString str, 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_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags);
JANET_NO_RETURN JANET_API void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags); JANET_API void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags);
#endif #endif
#endif #endif
@@ -1605,7 +1583,6 @@ JANET_API double janet_rng_double(JanetRNG *rng);
/* Array functions */ /* Array functions */
JANET_API JanetArray *janet_array(int32_t capacity); JANET_API JanetArray *janet_array(int32_t capacity);
JANET_API JanetArray *janet_array_weak(int32_t capacity);
JANET_API JanetArray *janet_array_n(const Janet *elements, int32_t n); JANET_API JanetArray *janet_array_n(const Janet *elements, int32_t n);
JANET_API void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth); JANET_API void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth);
JANET_API void janet_array_setcount(JanetArray *array, int32_t count); JANET_API void janet_array_setcount(JanetArray *array, int32_t count);
@@ -1635,7 +1612,7 @@ JANET_API void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x);
#define JANET_TUPLE_FLAG_BRACKETCTOR 0x10000 #define JANET_TUPLE_FLAG_BRACKETCTOR 0x10000
#define janet_tuple_head(t) ((JanetTupleHead *)((char *)t - offsetof(JanetTupleHead, data))) #define janet_tuple_head(t) ((JanetTupleHead *)((char *)t - offsetof(JanetTupleHead, data)))
#define janet_tuple_from_head(gcobject) ((JanetTuple)((char *)gcobject + offsetof(JanetTupleHead, data))) #define janet_tuple_from_head(gcobject) ((const Janet *)((char *)gcobject + offsetof(JanetTupleHead, data)))
#define janet_tuple_length(t) (janet_tuple_head(t)->length) #define janet_tuple_length(t) (janet_tuple_head(t)->length)
#define janet_tuple_hash(t) (janet_tuple_head(t)->hash) #define janet_tuple_hash(t) (janet_tuple_head(t)->hash)
#define janet_tuple_sm_line(t) (janet_tuple_head(t)->sm_line) #define janet_tuple_sm_line(t) (janet_tuple_head(t)->sm_line)
@@ -1681,7 +1658,7 @@ JANET_API JanetSymbol janet_symbol_gen(void);
/* Structs */ /* Structs */
#define janet_struct_head(t) ((JanetStructHead *)((char *)t - offsetof(JanetStructHead, data))) #define janet_struct_head(t) ((JanetStructHead *)((char *)t - offsetof(JanetStructHead, data)))
#define janet_struct_from_head(t) ((JanetStruct)((char *)gcobject + offsetof(JanetStructHead, data))) #define janet_struct_from_head(t) ((const JanetKV *)((char *)gcobject + offsetof(JanetStructHead, data)))
#define janet_struct_length(t) (janet_struct_head(t)->length) #define janet_struct_length(t) (janet_struct_head(t)->length)
#define janet_struct_capacity(t) (janet_struct_head(t)->capacity) #define janet_struct_capacity(t) (janet_struct_head(t)->capacity)
#define janet_struct_hash(t) (janet_struct_head(t)->hash) #define janet_struct_hash(t) (janet_struct_head(t)->hash)
@@ -1822,7 +1799,6 @@ JANET_API void janet_vm_free(JanetVM *vm);
JANET_API void janet_vm_save(JanetVM *into); JANET_API void janet_vm_save(JanetVM *into);
JANET_API void janet_vm_load(JanetVM *from); JANET_API void janet_vm_load(JanetVM *from);
JANET_API void janet_interpreter_interrupt(JanetVM *vm); JANET_API void janet_interpreter_interrupt(JanetVM *vm);
JANET_API void janet_interpreter_interrupt_handled(JanetVM *vm);
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out); JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig); JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig);
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f); JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
@@ -1846,7 +1822,6 @@ JANET_API void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *pr
#define JANET_SANDBOX_FS_TEMP 1024 #define JANET_SANDBOX_FS_TEMP 1024
#define JANET_SANDBOX_FFI_USE 2048 #define JANET_SANDBOX_FFI_USE 2048
#define JANET_SANDBOX_FFI_JIT 4096 #define JANET_SANDBOX_FFI_JIT 4096
#define JANET_SANDBOX_SIGNAL 8192
#define JANET_SANDBOX_FFI (JANET_SANDBOX_FFI_DEFINE | JANET_SANDBOX_FFI_USE | JANET_SANDBOX_FFI_JIT) #define JANET_SANDBOX_FFI (JANET_SANDBOX_FFI_DEFINE | JANET_SANDBOX_FFI_USE | JANET_SANDBOX_FFI_JIT)
#define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ | JANET_SANDBOX_FS_TEMP) #define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ | JANET_SANDBOX_FS_TEMP)
#define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN) #define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN)
@@ -1970,10 +1945,10 @@ JANET_API void janet_register(const char *name, JanetCFunction cfun);
#endif #endif
#ifndef JANET_ENTRY_NAME #ifndef JANET_ENTRY_NAME
#define JANET_MODULE_ENTRY \ #define JANET_MODULE_ENTRY \
JANET_MODULE_PREFIX JANET_EXPORT JanetBuildConfig _janet_mod_config(void) { \ JANET_MODULE_PREFIX JANET_API JanetBuildConfig _janet_mod_config(void) { \
return janet_config_current(); \ return janet_config_current(); \
} \ } \
JANET_MODULE_PREFIX JANET_EXPORT void _janet_init JANET_MODULE_PREFIX JANET_API void _janet_init
#else #else
#define JANET_MODULE_ENTRY JANET_MODULE_PREFIX JANET_API void JANET_ENTRY_NAME #define JANET_MODULE_ENTRY JANET_MODULE_PREFIX JANET_API void JANET_ENTRY_NAME
#endif #endif
@@ -2022,9 +1997,6 @@ JANET_API JanetDictView janet_getdictionary(const Janet *argv, int32_t n);
JANET_API void *janet_getabstract(const Janet *argv, int32_t n, const JanetAbstractType *at); JANET_API void *janet_getabstract(const Janet *argv, int32_t n, const JanetAbstractType *at);
JANET_API JanetRange janet_getslice(int32_t argc, const Janet *argv); JANET_API JanetRange janet_getslice(int32_t argc, const Janet *argv);
JANET_API int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which); JANET_API int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which);
JANET_API int32_t janet_getstartrange(const Janet *argv, int32_t argc, int32_t n, int32_t length);
JANET_API int32_t janet_getendrange(const Janet *argv, int32_t argc, int32_t n, int32_t length);
JANET_API int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which);
JANET_API uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags); JANET_API uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags);
/* Optionals */ /* Optionals */
@@ -2097,7 +2069,6 @@ JANET_API uint8_t janet_unmarshal_byte(JanetMarshalContext *ctx);
JANET_API void janet_unmarshal_bytes(JanetMarshalContext *ctx, uint8_t *dest, size_t len); JANET_API void janet_unmarshal_bytes(JanetMarshalContext *ctx, uint8_t *dest, size_t len);
JANET_API Janet janet_unmarshal_janet(JanetMarshalContext *ctx); JANET_API Janet janet_unmarshal_janet(JanetMarshalContext *ctx);
JANET_API JanetAbstract janet_unmarshal_abstract(JanetMarshalContext *ctx, size_t size); JANET_API JanetAbstract janet_unmarshal_abstract(JanetMarshalContext *ctx, size_t size);
JANET_API JanetAbstract janet_unmarshal_abstract_threaded(JanetMarshalContext *ctx, size_t size);
JANET_API void janet_unmarshal_abstract_reuse(JanetMarshalContext *ctx, void *p); JANET_API void janet_unmarshal_abstract_reuse(JanetMarshalContext *ctx, void *p);
JANET_API void janet_register_abstract_type(const JanetAbstractType *at); JANET_API void janet_register_abstract_type(const JanetAbstractType *at);
@@ -2140,9 +2111,7 @@ 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 {

View File

@@ -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();

View File

@@ -19,7 +19,7 @@
(frame :source) (frame :source-line))) (frame :source) (frame :source-line)))
(if x (if x
(when is-verbose (eprintf "\e[32m✔\e[0m %s: %s: %v" line-info (describe e) x)) (when is-verbose (eprintf "\e[32m✔\e[0m %s: %s: %v" line-info (describe e) x))
(do (eprintf "\e[31m✘\e[0m %s: %s: %v" line-info (describe e) x) (eflush))) (eprintf "\e[31m✘\e[0m %s: %s: %v" line-info (describe e) x))
x) x)
(defmacro assert-error (defmacro assert-error
@@ -34,17 +34,17 @@
(defmacro assert-no-error (defmacro assert-no-error
[msg & forms] [msg & forms]
(def e (gensym)) (def errsym (keyword (gensym)))
(def f (gensym)) ~(assert (not= ,errsym (try (do ,;forms) ([_] ,errsym))) ,msg))
(if is-verbose
~(try (do ,;forms (,assert true ,msg)) ([,e ,f] (,assert false ,msg) (,debug/stacktrace ,f ,e "\e[31m✘\e[0m ")))
~(try (do ,;forms (,assert true ,msg)) ([_] (,assert false ,msg)))))
(defn start-suite [&opt x] (defn start-suite [&opt x]
(default x (dyn :current-file)) (default x (dyn :current-file))
(set suite-name (set suite-name
(cond (cond
(number? x) (string x) (number? x) (string x)
(string? x) (string/slice x
(length "test/suite-")
(- (length ".janet")))
(string x))) (string x)))
(set start-time (os/clock)) (set start-time (os/clock))
(eprint "Starting suite " suite-name "...")) (eprint "Starting suite " suite-name "..."))

View File

@@ -37,7 +37,7 @@
(assert (array= @[:one :two :three :four :five] (assert (array= @[:one :two :three :four :five]
@[:one :two :three :four :five]) "array comparison 3") @[:one :two :three :four :five]) "array comparison 3")
(assert (array= (array/slice @[1 2 3] 0 2) @[1 2]) "array/slice 1") (assert (array= (array/slice @[1 2 3] 0 2) @[1 2]) "array/slice 1")
(assert (array= (array/slice @[0 7 3 9 1 4] 2 -2) @[3 9 1]) "array/slice 2") (assert (array= (array/slice @[0 7 3 9 1 4] 2 -1) @[3 9 1]) "array/slice 2")
# Array remove # Array remove
# 687a3c9 # 687a3c9

View File

@@ -51,13 +51,5 @@
(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)

View File

@@ -113,22 +113,13 @@
# 7478ad11 # 7478ad11
(assert (= nil (any? [])) "any? 1") (assert (= nil (any? [])) "any? 1")
(assert (= nil (any? [false nil])) "any? 2") (assert (= nil (any? [false nil])) "any? 2")
(assert (= false (any? [nil false])) "any? 3") (assert (= nil (any? [nil false])) "any? 3")
(assert (= 1 (any? [1])) "any? 4") (assert (= 1 (any? [1])) "any? 4")
(assert (nan? (any? [nil math/nan nil])) "any? 5") (assert (nan? (any? [nil math/nan nil])) "any? 5")
(assert (= true (assert (= true
(any? [nil nil false nil nil true nil nil nil nil false :a nil])) (any? [nil nil false nil nil true nil nil nil nil false :a nil]))
"any? 6") "any? 6")
(assert (= true (every? [])) "every? 1")
(assert (= true (every? [1 true])) "every? 2")
(assert (= 1 (every? [true 1])) "every? 3")
(assert (= nil (every? [nil])) "every? 4")
(assert (= 2 (every? [1 math/nan 2])) "every? 5")
(assert (= false
(every? [1 1 true 1 1 false 1 1 1 1 true :a nil]))
"every? 6")
# Some higher order functions and macros # Some higher order functions and macros
# 5e2de33 # 5e2de33
(def my-array @[1 2 3 4 5 6]) (def my-array @[1 2 3 4 5 6])
@@ -186,11 +177,6 @@
(assert (= txs [[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]]) (assert (= txs [[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]])
"nested seq") "nested seq")
# :unless modifier
(assert (deep= (seq [i :range [0 10] :unless (odd? i)] i)
@[0 2 4 6 8])
":unless modifier")
# 515891b03 # 515891b03
(assert (deep= (tabseq [i :in (range 3)] i (* 3 i)) (assert (deep= (tabseq [i :in (range 3)] i (* 3 i))
@{0 0 1 3 2 6})) @{0 0 1 3 2 6}))
@@ -209,12 +195,6 @@
(assert (deep= (seq [x :down-to [10 0]] x) (seq [x :down [10 -1]] x)) (assert (deep= (seq [x :down-to [10 0]] x) (seq [x :down [10 -1]] x))
"loop :down-to") "loop :down-to")
# one-term :range forms
(assert (deep= (seq [x :range [10]] x) (seq [x :range [0 10]] x))
"one-term :range")
(assert (deep= (seq [x :down [10]] x) (seq [x :down [10 0]] x))
"one-term :down")
# 7880d7320 # 7880d7320
(def res @{}) (def res @{})
(loop [[k v] :pairs @{1 2 3 4 5 6}] (loop [[k v] :pairs @{1 2 3 4 5 6}]
@@ -241,16 +221,6 @@
(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")
@@ -364,13 +334,6 @@
"sort 5") "sort 5")
(assert (<= ;(sort (map (fn [x] (math/random)) (range 1000)))) "sort 6") (assert (<= ;(sort (map (fn [x] (math/random)) (range 1000)))) "sort 6")
# #1283
(assert (deep=
(partition 2 (generate [ i :in [:a :b :c :d :e]] i))
'@[(:a :b) (:c :d) (:e)]))
(assert (= (mean (generate [i :in [2 3 5 7 11]] i))
5.6))
# And and or # And and or
# c16a9d846 # c16a9d846
(assert (= (and true true) true) "and true true") (assert (= (and true true) true) "and true true")
@@ -399,7 +362,14 @@
(assert (= false (and false false)) "and 1") (assert (= false (and false false)) "and 1")
(assert (= false (or false false)) "or 1") (assert (= false (or false false)) "or 1")
# Range
# a982f351d
(assert (deep= (range 10) @[0 1 2 3 4 5 6 7 8 9]) "range 1 argument")
(assert (deep= (range 5 10) @[5 6 7 8 9]) "range 2 arguments")
(assert (deep= (range 5 10 2) @[5 7 9]) "range 3 arguments")
# 11cd1279d # 11cd1279d
(assert (= (length (range 10)) 10) "(range 10)")
(assert (= (length (range 1 10)) 9) "(range 1 10)")
(assert (deep= @{:a 1 :b 2 :c 3} (zipcoll '[:a :b :c] '[1 2 3])) "zipcoll") (assert (deep= @{:a 1 :b 2 :c 3} (zipcoll '[:a :b :c] '[1 2 3])) "zipcoll")
# bc8be266f # bc8be266f
@@ -934,46 +904,4 @@
[:strict 3 4 "bar-oops"]]) [:strict 3 4 "bar-oops"]])
"maclintf 2") "maclintf 2")
# Bad bytecode wrt. using result from break expression
(defn bytecode-roundtrip
[f]
(assert-no-error "bytecode round-trip" (unmarshal (marshal f make-image-dict))))
(defn case-1 [&] (def x (break 1)))
(bytecode-roundtrip case-1)
(defn foo [&])
(defn case-2 [&]
(foo (break (foo)))
(foo))
(bytecode-roundtrip case-2)
(defn case-3 [&]
(def x (break (do (foo)))))
(bytecode-roundtrip case-3)
(defn case-4 [&]
(def x (break (break (foo)))))
(bytecode-roundtrip case-4)
(defn case-4 [&]
(def x (break (break (break)))))
(bytecode-roundtrip case-4)
(defn case-5 []
(def foo (fn [one two] one))
(foo 100 200))
(bytecode-roundtrip case-5)
# Debug bytecode of these functions
# (pp (disasm case-1))
# (pp (disasm case-2))
# (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)

View File

@@ -77,54 +77,6 @@
(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
(assert (deep= @"" (buffer/from-bytes)) "buffer/from-bytes 1")
(assert (deep= @"ABC" (buffer/from-bytes 65 66 67)) "buffer/from-bytes 2")
(assert (deep= @"0123456789" (buffer/from-bytes ;(range 48 58))) "buffer/from-bytes 3")
(assert (= 0 (length (buffer/from-bytes))) "buffer/from-bytes 4")
(assert (= 5 (length (buffer/from-bytes ;(range 5)))) "buffer/from-bytes 5")
(assert-error "bad slot #1, expected 32 bit signed integer" (buffer/from-bytes :abc))
# some tests for buffer/format # some tests for buffer/format
# 029394d # 029394d
(assert (= (string (buffer/format @"" "pi = %6.3f" math/pi)) "pi = 3.142") (assert (= (string (buffer/format @"" "pi = %6.3f" math/pi)) "pi = 3.142")
@@ -144,14 +96,13 @@
# Regression #301 # Regression #301
# a3d4ecddb # a3d4ecddb
(def b (buffer/new-filled 128 0x78)) (def b (buffer/new-filled 128 0x78))
(assert (= 38 (length (buffer/blit @"" b -1 90))) "buffer/blit 1") (assert (= 38 (length (buffer/blit @"" b 0 90))) "buffer/blit 1")
(def a @"abcdefghijklm") (def a @"abcdefghijklm")
(assert (deep= @"abcde" (buffer/blit @"" a -1 0 5)) "buffer/blit 2") (assert (deep= @"abcde" (buffer/blit @"" a 0 0 5)) "buffer/blit 2")
(assert (deep= @"bcde" (buffer/blit @"" a -1 1 5)) "buffer/blit 3") (assert (deep= @"bcde" (buffer/blit @"" a 0 1 5)) "buffer/blit 3")
(assert (deep= @"cde" (buffer/blit @"" a -1 2 5)) "buffer/blit 4") (assert (deep= @"cde" (buffer/blit @"" a 0 2 5)) "buffer/blit 4")
(assert (deep= @"de" (buffer/blit @"" a -1 3 5)) "buffer/blit 5") (assert (deep= @"de" (buffer/blit @"" a 0 3 5)) "buffer/blit 5")
(assert (deep= @"de" (buffer/blit @"" a nil 3 5)) "buffer/blit 6")
# buffer/push-at # buffer/push-at
# c55d93512 # c55d93512
@@ -162,5 +113,8 @@
(assert (deep= @"abc423" (buffer/push-at @"abc123" 3 "4")) (assert (deep= @"abc423" (buffer/push-at @"abc123" 3 "4"))
"buffer/push-at 3") "buffer/push-at 3")
# 4782a76
(assert (= 10 (do (var x 10) (def y x) (++ x) y)) "no invalid aliasing")
(end-suite) (end-suite)

View File

@@ -159,23 +159,5 @@
(assert-error "invalid offset-a: 1" (memcmp "a" "b" 1 1 0)) (assert-error "invalid offset-a: 1" (memcmp "a" "b" 1 1 0))
(assert-error "invalid offset-b: 1" (memcmp "a" "b" 1 0 1)) (assert-error "invalid offset-b: 1" (memcmp "a" "b" 1 0 1))
# Range
# a982f351d
(assert (deep= (range 10) @[0 1 2 3 4 5 6 7 8 9]) "(range 10)")
(assert (deep= (range 5 10) @[5 6 7 8 9]) "(range 5 10)")
(assert (deep= (range 0 16 4) @[0 4 8 12]) "(range 0 16 4)")
(assert (deep= (range 0 17 4) @[0 4 8 12 16]) "(range 0 17 4)")
(assert (deep= (range 16 0 -4) @[16 12 8 4]) "(range 16 0 -4)")
(assert (deep= (range 17 0 -4) @[17 13 9 5 1]) "(range 17 0 -4)")
(assert (= (length (range 10)) 10) "(range 10)")
(assert (= (length (range -10)) 0) "(range -10)")
(assert (= (length (range 1 10)) 9) "(range 1 10)")
# iterating over generator
(assert-no-error "iterate over coro 1" (values (generate [x :range [0 10]] x)))
(assert-no-error "iterate over coro 2" (keys (generate [x :range [0 10]] x)))
(assert-no-error "iterate over coro 3" (pairs (generate [x :range [0 10]] x)))
(end-suite) (end-suite)

View File

@@ -21,12 +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))
# Subprocess should inherit the "RUN" parameter for fancy testing # Subprocess should inherit the "RUN" parameter for fancy testing
(def run (filter next (string/split " " (os/getenv "SUBRUN" "")))) (def run (filter next (string/split " " (os/getenv "SUBRUN" ""))))
@@ -195,11 +192,11 @@
(net/write stream b) (net/write stream b)
(buffer/clear b))) (buffer/clear b)))
(def s (net/server test-host test-port handler)) (def s (net/server "127.0.0.1" "8000" handler))
(assert s "made server 1") (assert s "made server 1")
(defn test-echo [msg] (defn test-echo [msg]
(with [conn (net/connect test-host test-port)] (with [conn (net/connect "127.0.0.1" "8000")]
(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))))
@@ -208,8 +205,7 @@
(test-echo "world") (test-echo "world")
(test-echo (string/repeat "abcd" 200)) (test-echo (string/repeat "abcd" 200))
(:close s) (:close s))
(gccollect))
# Test on both server and client # Test on both server and client
# 504411e # 504411e
@@ -219,18 +215,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 test-host) "localname host server") (assert (= host "127.0.0.1") "localname host server")
(assert (= port (scan-number test-port)) "localname port server"))) (assert (= port 8000) "localname port server")))
# Test localname and peername # Test localname and peername
# 077bf5eba # 077bf5eba
(repeat 10 (repeat 10
(with [s (net/server test-host test-port names-handler)] (with [s (net/server "127.0.0.1" "8000" names-handler)]
(repeat 10 (repeat 10
(with [conn (net/connect test-host test-port)] (with [conn (net/connect "127.0.0.1" "8000")]
(def [host port] (net/peername conn)) (def [host port] (net/peername conn))
(assert (= host test-host) "peername host client ") (assert (= host "127.0.0.1") "peername host client ")
(assert (= port (scan-number test-port)) "peername port client") (assert (= port 8000) "peername port client")
# let server close # let server close
(ev/write conn " ")))) (ev/write conn " "))))
(gccollect)) (gccollect))
@@ -348,31 +344,5 @@
(ev/go |(ev/chan-close ch)) (ev/go |(ev/chan-close ch))
(assert (= (ev/select [ch 1]) [:close ch])) (assert (= (ev/select [ch 1]) [:close ch]))
# ev/gather check
(defn exec-slurp
"Read stdout of subprocess and return it trimmed in a string."
[& args]
(def env (os/environ))
(put env :out :pipe)
(def proc (os/spawn args :epx env))
(def out (get proc :out))
(def buf @"")
(ev/gather
(:read out :all buf)
(:wait proc))
(string/trimr buf))
(assert-no-error
"ev/with-deadline 1"
(assert (= "hi"
(ev/with-deadline
10
(exec-slurp ;run janet "-e" "(print :hi)")))
"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)

View File

@@ -126,7 +126,7 @@
(assert (deep= (int/to-bytes (u64 300) :be buf2) (assert (deep= (int/to-bytes (u64 300) :be buf2)
@"abcd\x00\x00\x00\x00\x00\x00\x01\x2C"))) @"abcd\x00\x00\x00\x00\x00\x00\x01\x2C")))
# int/s64 and int/u64 parameter type checking # int/s64 and int/u64 paramater type checking
# 6aea7c7f7 # 6aea7c7f7
(assert-error (assert-error
"bad value passed to int/to-bytes" "bad value passed to int/to-bytes"

View File

@@ -96,23 +96,11 @@
(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")
@@ -160,3 +148,4 @@
{:out dn :err dn}))) {:out dn :err dn})))
(end-suite) (end-suite)

View File

@@ -69,7 +69,7 @@
(def first-nl (= (chr "\n") (first str))) (def first-nl (= (chr "\n") (first str)))
(def last-nl (= (chr "\n") (last str))) (def last-nl (= (chr "\n") (last str)))
(string/slice str (if first-nl 1 0) (if last-nl -2))) (string/slice str (if first-nl 1 0) (if last-nl -1)))
(defn reindent-reference (defn reindent-reference
"Same as reindent but use parser functionality. Useful for "Same as reindent but use parser functionality. Useful for

View File

@@ -263,9 +263,6 @@
(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
@@ -663,98 +660,5 @@
(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)

View File

@@ -32,10 +32,10 @@
# Buffer self blitting, check for use after free # Buffer self blitting, check for use after free
# bbcfaf128 # bbcfaf128
(def buf1 @"1234567890") (def buf1 @"1234567890")
(buffer/blit buf1 buf1 -1) (buffer/blit buf1 buf1 (length buf1))
(buffer/blit buf1 buf1 -1) (buffer/blit buf1 buf1 (length buf1))
(buffer/blit buf1 buf1 -1) (buffer/blit buf1 buf1 (length buf1))
(buffer/blit buf1 buf1 -1) (buffer/blit buf1 buf1 (length buf1))
(assert (= (string buf1) (string/repeat "1234567890" 16)) (assert (= (string buf1) (string/repeat "1234567890" 16))
"buffer blit against self") "buffer blit against self")

View File

@@ -198,9 +198,5 @@
(assert (= (test) '(1 ())) "issue #919") (assert (= (test) '(1 ())) "issue #919")
# Regression #1327
(def x "A")
(def x (if (= nil x) "B" x))
(assert (= x "A"))
(end-suite) (end-suite)

View File

@@ -292,8 +292,5 @@
[2 6 4 'z]]) [2 6 4 'z]])
"arg & inner symbolmap") "arg & inner symbolmap")
# 4782a76
(assert (= 10 (do (var x 10) (def y x) (++ x) y)) "no invalid aliasing")
(end-suite) (end-suite)