mirror of
				https://github.com/janet-lang/janet
				synced 2025-11-04 01:23:04 +00:00 
			
		
		
		
	Compare commits
	
		
			49 Commits
		
	
	
		
			ev-epoll-f
			...
			v1.33.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f91e599451 | ||
| 
						 | 
					5b9aa9237c | ||
| 
						 | 
					9142f38cbc | ||
| 
						 | 
					e8ed961572 | ||
| 
						 | 
					be11a2a1ad | ||
| 
						 | 
					ea75086300 | ||
| 
						 | 
					9eeefbd79a | ||
| 
						 | 
					c573a98363 | ||
| 
						 | 
					11d7af3f95 | ||
| 
						 | 
					a10b4f61d8 | ||
| 
						 | 
					a0cb7514f1 | ||
| 
						 | 
					b066edc116 | ||
| 
						 | 
					938f5a689e | ||
| 
						 | 
					772f4c26e8 | ||
| 
						 | 
					6b5d151beb | ||
| 
						 | 
					a9176a77e6 | ||
| 
						 | 
					16f409c6a9 | ||
| 
						 | 
					9593c930de | ||
| 
						 | 
					56f33f514b | ||
| 
						 | 
					1ccd544b94 | ||
| 
						 | 
					93c83a2ee2 | ||
| 
						 | 
					f459e32ada | ||
| 
						 | 
					9b640c8e9c | ||
| 
						 | 
					a3228f4997 | ||
| 
						 | 
					715eb69d92 | ||
| 
						 | 
					df2d5cb3d3 | ||
| 
						 | 
					3b189eab64 | ||
| 
						 | 
					609b629c22 | ||
| 
						 | 
					e74365fe38 | ||
| 
						 | 
					46b34833c2 | ||
| 
						 | 
					045c80869d | ||
| 
						 | 
					2ea2e72ddd | ||
| 
						 | 
					1b17e12fd6 | ||
| 
						 | 
					cc5beda0d2 | ||
| 
						 | 
					a363fd926d | ||
| 
						 | 
					21ebede529 | ||
| 
						 | 
					15d67e9191 | ||
| 
						 | 
					b5996f5f02 | ||
| 
						 | 
					83204dc293 | ||
| 
						 | 
					e3f4142d2a | ||
| 
						 | 
					f18ad36b1b | ||
| 
						 | 
					cb25a2ecd6 | ||
| 
						 | 
					741a5036e8 | ||
| 
						 | 
					549ee95f3d | ||
| 
						 | 
					6ae81058aa | ||
| 
						 | 
					267c603824 | ||
| 
						 | 
					a8f583a372 | ||
| 
						 | 
					2b5d90f73a | ||
| 
						 | 
					4139e426fe | 
							
								
								
									
										2
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							@@ -56,7 +56,7 @@ jobs:
 | 
			
		||||
            gcc
 | 
			
		||||
      - name: Build the project
 | 
			
		||||
        shell: cmd
 | 
			
		||||
        run: make -j CC=gcc
 | 
			
		||||
        run: make -j4 CC=gcc JANET_NO_AMALG=1
 | 
			
		||||
 | 
			
		||||
  test-mingw-linux:
 | 
			
		||||
    name: Build and test with Mingw on Linux + Wine
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -34,8 +34,11 @@ local
 | 
			
		||||
 | 
			
		||||
# Common test files I use.
 | 
			
		||||
temp.janet
 | 
			
		||||
temp*.janet
 | 
			
		||||
temp.c
 | 
			
		||||
temp*janet
 | 
			
		||||
temp*.c
 | 
			
		||||
scratch.janet
 | 
			
		||||
scratch.c
 | 
			
		||||
 | 
			
		||||
# Emscripten
 | 
			
		||||
*.bc
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,7 +1,33 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
All notable changes to this project will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## Unreleased - ???
 | 
			
		||||
## 1.33.0 - 2023-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`.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								Makefile
									
									
									
									
									
								
							@@ -33,6 +33,7 @@ CLIBS=-lm -lpthread
 | 
			
		||||
JANET_TARGET=build/janet
 | 
			
		||||
JANET_BOOT=build/janet_boot
 | 
			
		||||
JANET_IMPORT_LIB=build/janet.lib
 | 
			
		||||
JANET_LIBRARY_IMPORT_LIB=build/libjanet.lib
 | 
			
		||||
JANET_LIBRARY=build/libjanet.so
 | 
			
		||||
JANET_STATIC_LIBRARY=build/libjanet.a
 | 
			
		||||
JANET_PATH?=$(LIBDIR)/janet
 | 
			
		||||
@@ -42,6 +43,7 @@ JANET_DIST_DIR?=janet-dist
 | 
			
		||||
JANET_BOOT_FLAGS:=. JANET_PATH '$(JANET_PATH)'
 | 
			
		||||
JANET_TARGET_OBJECTS=build/janet.o build/shell.o
 | 
			
		||||
JPM_TAG?=master
 | 
			
		||||
HAS_SHARED?=1
 | 
			
		||||
DEBUGGER=gdb
 | 
			
		||||
SONAME_SETTER=-Wl,-soname,
 | 
			
		||||
 | 
			
		||||
@@ -51,6 +53,7 @@ HOSTAR?=$(AR)
 | 
			
		||||
# Symbols are (optionally) removed later, keep -g as default!
 | 
			
		||||
CFLAGS?=-O2 -g
 | 
			
		||||
LDFLAGS?=-rdynamic
 | 
			
		||||
LIBJANET_LDFLAGS?=$(LD_FLAGS)
 | 
			
		||||
RUN:=$(RUN)
 | 
			
		||||
 | 
			
		||||
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
 | 
			
		||||
@@ -93,12 +96,17 @@ endif
 | 
			
		||||
ifeq ($(findstring MINGW,$(UNAME)), MINGW)
 | 
			
		||||
	CLIBS:=-lws2_32 -lpsapi -lwsock32
 | 
			
		||||
	LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB)
 | 
			
		||||
	LIBJANET_LDFLAGS:=-Wl,--out-implib,$(JANET_LIBRARY_IMPORT_LIB)
 | 
			
		||||
	JANET_TARGET:=$(JANET_TARGET).exe
 | 
			
		||||
	JANET_BOOT:=$(JANET_BOOT).exe
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$(shell mkdir -p build/core build/c build/boot build/mainclient)
 | 
			
		||||
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.h
 | 
			
		||||
all: $(JANET_TARGET) $(JANET_STATIC_LIBRARY) build/janet.h
 | 
			
		||||
ifeq ($(HAS_SHARED), 1)
 | 
			
		||||
all: $(JANET_LIBRARY)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
######################
 | 
			
		||||
##### Name Files #####
 | 
			
		||||
@@ -196,9 +204,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
 | 
			
		||||
########################
 | 
			
		||||
 | 
			
		||||
ifeq ($(UNAME), Darwin)
 | 
			
		||||
SONAME=libjanet.1.31.dylib
 | 
			
		||||
SONAME=libjanet.1.33.dylib
 | 
			
		||||
else
 | 
			
		||||
SONAME=libjanet.so.1.31
 | 
			
		||||
SONAME=libjanet.so.1.33
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
build/c/shell.c: src/mainclient/shell.c
 | 
			
		||||
@@ -220,7 +228,7 @@ $(JANET_TARGET): $(JANET_TARGET_OBJECTS)
 | 
			
		||||
	$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
 | 
			
		||||
 | 
			
		||||
$(JANET_LIBRARY): $(JANET_TARGET_OBJECTS)
 | 
			
		||||
	$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
 | 
			
		||||
	$(HOSTCC) $(LIBJANET_LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
 | 
			
		||||
 | 
			
		||||
$(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
 | 
			
		||||
	$(HOSTAR) rcs $@ $^
 | 
			
		||||
@@ -263,7 +271,7 @@ dist: build/janet-dist.tar.gz
 | 
			
		||||
 | 
			
		||||
build/janet-%.tar.gz: $(JANET_TARGET) \
 | 
			
		||||
	build/janet.h \
 | 
			
		||||
	janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
 | 
			
		||||
	janet.1 LICENSE CONTRIBUTING.md $(JANET_STATIC_LIBRARY) \
 | 
			
		||||
	README.md build/c/janet.c build/c/shell.c
 | 
			
		||||
	mkdir -p build/$(JANET_DIST_DIR)/bin
 | 
			
		||||
	cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
 | 
			
		||||
@@ -271,13 +279,17 @@ build/janet-%.tar.gz: $(JANET_TARGET) \
 | 
			
		||||
	mkdir -p build/$(JANET_DIST_DIR)/include
 | 
			
		||||
	cp build/janet.h build/$(JANET_DIST_DIR)/include/
 | 
			
		||||
	mkdir -p build/$(JANET_DIST_DIR)/lib/
 | 
			
		||||
	cp $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
 | 
			
		||||
	cp $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
 | 
			
		||||
	cp $(JANET_LIBRARY) build/$(JANET_DIST_DIR)/lib/ || true
 | 
			
		||||
	mkdir -p build/$(JANET_DIST_DIR)/man/man1/
 | 
			
		||||
	cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
 | 
			
		||||
	mkdir -p 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)/
 | 
			
		||||
	cd build && tar -czvf ../$@ ./$(JANET_DIST_DIR)
 | 
			
		||||
ifeq ($(HAS_SHARED), 1)
 | 
			
		||||
build/janet-%.tar.gz: $(JANET_LIBRARY)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
#########################
 | 
			
		||||
##### Documentation #####
 | 
			
		||||
@@ -331,6 +343,7 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
 | 
			
		||||
	mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
 | 
			
		||||
	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_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"
 | 
			
		||||
 | 
			
		||||
install-jpm-git: $(JANET_TARGET)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								examples/posix-exec.janet
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/posix-exec.janet
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# Switch to python
 | 
			
		||||
 | 
			
		||||
(print "running in Janet")
 | 
			
		||||
(os/posix-exec ["python"] :p)
 | 
			
		||||
(print "will not print")
 | 
			
		||||
							
								
								
									
										18
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								meson.build
									
									
									
									
									
								
							@@ -20,7 +20,7 @@
 | 
			
		||||
 | 
			
		||||
project('janet', 'c',
 | 
			
		||||
  default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
 | 
			
		||||
  version : '1.31.0')
 | 
			
		||||
  version : '1.33.0')
 | 
			
		||||
 | 
			
		||||
# Global settings
 | 
			
		||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
 | 
			
		||||
@@ -61,6 +61,7 @@ conf.set('JANET_NO_SOURCEMAPS', not get_option('sourcemaps'))
 | 
			
		||||
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
 | 
			
		||||
conf.set('JANET_NO_PEG', not get_option('peg'))
 | 
			
		||||
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_REDUCED_OS', get_option('reduced_os'))
 | 
			
		||||
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
 | 
			
		||||
@@ -78,6 +79,7 @@ conf.set('JANET_EV_NO_KQUEUE', not get_option('kqueue'))
 | 
			
		||||
conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt'))
 | 
			
		||||
conf.set('JANET_NO_FFI', not get_option('ffi'))
 | 
			
		||||
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') != ''
 | 
			
		||||
  conf.set('JANET_OS_NAME', get_option('os_name'))
 | 
			
		||||
endif
 | 
			
		||||
@@ -182,11 +184,13 @@ if not get_option('single_threaded')
 | 
			
		||||
  janet_dependencies += thread_dep
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Allow building with no shared library
 | 
			
		||||
if cc.has_argument('-fvisibility=hidden')
 | 
			
		||||
  lib_cflags = ['-fvisibility=hidden']
 | 
			
		||||
else
 | 
			
		||||
  lib_cflags = []
 | 
			
		||||
endif
 | 
			
		||||
if get_option('shared')
 | 
			
		||||
  libjanet = library('janet', janetc,
 | 
			
		||||
    include_directories : incdir,
 | 
			
		||||
    dependencies : janet_dependencies,
 | 
			
		||||
@@ -194,7 +198,6 @@ libjanet = library('janet', janetc,
 | 
			
		||||
    soversion: version_parts[0] + '.' + version_parts[1],
 | 
			
		||||
    c_args : lib_cflags,
 | 
			
		||||
    install : true)
 | 
			
		||||
 | 
			
		||||
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
 | 
			
		||||
# shaves off about 10k on linux x64, likely similar on other platforms.
 | 
			
		||||
  if cc.has_argument('-fvisibility=hidden')
 | 
			
		||||
@@ -208,6 +211,14 @@ janet_mainclient = executable('janet', mainclient_src,
 | 
			
		||||
    link_with: [libjanet],
 | 
			
		||||
    c_args : extra_cflags,
 | 
			
		||||
    install : true)
 | 
			
		||||
else
 | 
			
		||||
  # No shared library
 | 
			
		||||
  janet_mainclient = executable('janet', mainclient_src, janetc,
 | 
			
		||||
    include_directories : incdir,
 | 
			
		||||
    dependencies : janet_dependencies,
 | 
			
		||||
    c_args : lib_cflags,
 | 
			
		||||
    install : true)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if meson.is_cross_build()
 | 
			
		||||
  native_cc = meson.get_compiler('c', native: true)
 | 
			
		||||
@@ -271,14 +282,15 @@ endforeach
 | 
			
		||||
run_target('repl', command : [janet_nativeclient])
 | 
			
		||||
 | 
			
		||||
# For use as meson subproject (wrap)
 | 
			
		||||
if get_option('shared')
 | 
			
		||||
  janet_dep = declare_dependency(include_directories : incdir,
 | 
			
		||||
    link_with : libjanet)
 | 
			
		||||
 | 
			
		||||
# pkgconfig
 | 
			
		||||
  pkg = import('pkgconfig')
 | 
			
		||||
  pkg.generate(libjanet,
 | 
			
		||||
    subdirs: 'janet',
 | 
			
		||||
    description: 'Library for the Janet programming language.')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Installation
 | 
			
		||||
install_man('janet.1')
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ option('peg', type : 'boolean', value : true)
 | 
			
		||||
option('int_types', type : 'boolean', value : true)
 | 
			
		||||
option('prf', type : 'boolean', value : false)
 | 
			
		||||
option('net', type : 'boolean', value : true)
 | 
			
		||||
option('ipv6', type : 'boolean', value : true)
 | 
			
		||||
option('ev', type : 'boolean', value : true)
 | 
			
		||||
option('processes', type : 'boolean', value : true)
 | 
			
		||||
option('umask', type : 'boolean', value : true)
 | 
			
		||||
@@ -29,3 +30,5 @@ option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7f
 | 
			
		||||
 | 
			
		||||
option('arch_name', type : 'string', value: '')
 | 
			
		||||
option('os_name', type : 'string', value: '')
 | 
			
		||||
option('shared', type : 'boolean', value: true)
 | 
			
		||||
option('cryptorand', type : 'boolean', value: true)
 | 
			
		||||
 
 | 
			
		||||
@@ -162,7 +162,7 @@
 | 
			
		||||
  ``Define a default value for an optional argument.
 | 
			
		||||
  Expands to `(def sym (if (= nil sym) val sym))`.``
 | 
			
		||||
  [sym val]
 | 
			
		||||
  ~(def ,sym (if (= nil ,sym) ,val ,sym)))
 | 
			
		||||
  ~(def ,sym (if (,= nil ,sym) ,val ,sym)))
 | 
			
		||||
 | 
			
		||||
(defmacro comment
 | 
			
		||||
  "Ignores the body of the comment."
 | 
			
		||||
@@ -420,10 +420,14 @@
 | 
			
		||||
 | 
			
		||||
(defn- range-template
 | 
			
		||||
  [binding object kind rest op comparison]
 | 
			
		||||
  (let [[start stop step] (check-indexed object)]
 | 
			
		||||
    (case kind
 | 
			
		||||
      :range (for-template binding (if stop start 0) (or stop start) (or step 1) comparison op [rest])
 | 
			
		||||
      :down (for-template binding start (or stop 0) (or step 1) comparison op [rest]))))
 | 
			
		||||
  (check-indexed object)
 | 
			
		||||
  (def [a b c] object)
 | 
			
		||||
  (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
 | 
			
		||||
  [binding inx kind body]
 | 
			
		||||
@@ -2123,6 +2127,7 @@
 | 
			
		||||
     'upscope expandall})
 | 
			
		||||
 | 
			
		||||
  (defn dotup [t]
 | 
			
		||||
    (if (= nil (next t)) (break ()))
 | 
			
		||||
    (def h (in t 0))
 | 
			
		||||
    (def s (in specs h))
 | 
			
		||||
    (def entry (or (dyn h) {}))
 | 
			
		||||
@@ -2333,26 +2338,36 @@
 | 
			
		||||
(def default-peg-grammar
 | 
			
		||||
  `The default grammar used for pegs. This grammar defines several common patterns
 | 
			
		||||
  that should make it easier to write more complex patterns.`
 | 
			
		||||
  ~@{:d (range "09")
 | 
			
		||||
     :a (range "az" "AZ")
 | 
			
		||||
  ~@{:a (range "az" "AZ")
 | 
			
		||||
     :d (range "09")
 | 
			
		||||
     :h (range "09" "af" "AF")
 | 
			
		||||
     :s (set " \t\r\n\0\f\v")
 | 
			
		||||
     :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)
 | 
			
		||||
     :D (if-not :d 1)
 | 
			
		||||
     :H (if-not :h 1)
 | 
			
		||||
     :d+ (some :d)
 | 
			
		||||
     :S (if-not :s 1)
 | 
			
		||||
     :W (if-not :w 1)
 | 
			
		||||
     :a+ (some :a)
 | 
			
		||||
     :d+ (some :d)
 | 
			
		||||
     :h+ (some :h)
 | 
			
		||||
     :s+ (some :s)
 | 
			
		||||
     :w+ (some :w)
 | 
			
		||||
     :h+ (some :h)
 | 
			
		||||
     :d* (any :d)
 | 
			
		||||
     :A+ (some :A)
 | 
			
		||||
     :D+ (some :D)
 | 
			
		||||
     :H+ (some :H)
 | 
			
		||||
     :S+ (some :S)
 | 
			
		||||
     :W+ (some :W)
 | 
			
		||||
     :a* (any :a)
 | 
			
		||||
     :w* (any :w)
 | 
			
		||||
     :d* (any :d)
 | 
			
		||||
     :h* (any :h)
 | 
			
		||||
     :s* (any :s)
 | 
			
		||||
     :h* (any :h)})
 | 
			
		||||
     :w* (any :w)
 | 
			
		||||
     :A* (any :A)
 | 
			
		||||
     :D* (any :D)
 | 
			
		||||
     :H* (any :H)
 | 
			
		||||
     :S* (any :S)
 | 
			
		||||
     :W* (any :W)})
 | 
			
		||||
 | 
			
		||||
(setdyn *peg-grammar* default-peg-grammar)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,10 @@
 | 
			
		||||
#define JANETCONF_H
 | 
			
		||||
 | 
			
		||||
#define JANET_VERSION_MAJOR 1
 | 
			
		||||
#define JANET_VERSION_MINOR 31
 | 
			
		||||
#define JANET_VERSION_MINOR 33
 | 
			
		||||
#define JANET_VERSION_PATCH 0
 | 
			
		||||
#define JANET_VERSION_EXTRA ""
 | 
			
		||||
#define JANET_VERSION "1.31.0"
 | 
			
		||||
#define JANET_VERSION "1.33.0"
 | 
			
		||||
 | 
			
		||||
/* #define JANET_BUILD "local" */
 | 
			
		||||
 | 
			
		||||
@@ -52,6 +52,8 @@
 | 
			
		||||
/* #define JANET_EV_NO_EPOLL */
 | 
			
		||||
/* #define JANET_EV_NO_KQUEUE */
 | 
			
		||||
/* #define JANET_NO_INTERPRETER_INTERRUPT */
 | 
			
		||||
/* #define JANET_NO_IPV6 */
 | 
			
		||||
/* #define JANET_NO_CRYPTORAND */
 | 
			
		||||
 | 
			
		||||
/* Custom vm allocator support */
 | 
			
		||||
/* #include <mimalloc.h> */
 | 
			
		||||
 
 | 
			
		||||
@@ -135,8 +135,7 @@ void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
 | 
			
		||||
 | 
			
		||||
/* Push a cstring to buffer */
 | 
			
		||||
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
 | 
			
		||||
    int32_t len = 0;
 | 
			
		||||
    while (cstring[len]) ++len;
 | 
			
		||||
    int32_t len = (int32_t) strlen(cstring);
 | 
			
		||||
    janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -226,6 +226,7 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
 | 
			
		||||
                case JOP_LOAD_TRUE:
 | 
			
		||||
                case JOP_LOAD_FALSE:
 | 
			
		||||
                case JOP_LOAD_SELF:
 | 
			
		||||
                    break;
 | 
			
		||||
                case JOP_MAKE_ARRAY:
 | 
			
		||||
                case JOP_MAKE_BUFFER:
 | 
			
		||||
                case JOP_MAKE_STRING:
 | 
			
		||||
@@ -233,6 +234,8 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
 | 
			
		||||
                case JOP_MAKE_TABLE:
 | 
			
		||||
                case JOP_MAKE_TUPLE:
 | 
			
		||||
                case JOP_MAKE_BRACKET_TUPLE:
 | 
			
		||||
                    /* Reads from the stack, don't remove */
 | 
			
		||||
                    janetc_regalloc_touch(&ra, DD);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                /* Read A */
 | 
			
		||||
 
 | 
			
		||||
@@ -338,7 +338,7 @@ int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const c
 | 
			
		||||
    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, raw, -length - 1, length);
 | 
			
		||||
        janet_panicf("%s index %d out of range [%d,%d]", which, (int64_t) raw, -(int64_t)length - 1, (int64_t) length);
 | 
			
		||||
    return not_raw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -361,7 +361,7 @@ int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const ch
 | 
			
		||||
    int32_t not_raw = raw;
 | 
			
		||||
    if (not_raw < 0) not_raw += length;
 | 
			
		||||
    if (not_raw < 0 || not_raw > length)
 | 
			
		||||
        janet_panicf("%s index %d out of range [%d,%d)", which, raw, -length, length);
 | 
			
		||||
        janet_panicf("%s index %d out of range [%d,%d)", which, (int64_t)raw, -(int64_t)length, (int64_t)length);
 | 
			
		||||
    return not_raw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -505,7 +505,15 @@ JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    return InterlockedDecrement(x);
 | 
			
		||||
#else
 | 
			
		||||
    return __atomic_add_fetch(x, -1, __ATOMIC_RELAXED);
 | 
			
		||||
    return __atomic_add_fetch(x, -1, __ATOMIC_ACQ_REL);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x) {
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    return InterlockedOr(x, 0);
 | 
			
		||||
#else
 | 
			
		||||
    return __atomic_load_n(x, __ATOMIC_ACQUIRE);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1144,7 +1144,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
 | 
			
		||||
                    JDOC("(next ds &opt key)\n\n"
 | 
			
		||||
                         "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 "
 | 
			
		||||
                         "to be seen only once per iteration if they data structure is not mutated "
 | 
			
		||||
                         "to be seen only once per iteration if the data structure is not mutated "
 | 
			
		||||
                         "during iteration. If key is nil, next returns the first key. If next "
 | 
			
		||||
                         "returns nil, there are no more keys to iterate through."));
 | 
			
		||||
    janet_quick_asm(env, JANET_FUN_PROP,
 | 
			
		||||
 
 | 
			
		||||
@@ -255,19 +255,29 @@ static void add_timeout(JanetTimeout to) {
 | 
			
		||||
 | 
			
		||||
void janet_async_end(JanetFiber *fiber) {
 | 
			
		||||
    if (fiber->ev_callback) {
 | 
			
		||||
        fiber->ev_callback(fiber, JANET_ASYNC_EVENT_DEINIT);
 | 
			
		||||
        janet_gcunroot(janet_wrap_abstract(fiber->ev_stream));
 | 
			
		||||
        fiber->ev_callback = NULL;
 | 
			
		||||
        if (fiber->ev_state) {
 | 
			
		||||
        if (!(fiber->flags & JANET_FIBER_EV_FLAG_IN_FLIGHT)) {
 | 
			
		||||
            if (fiber->ev_state) {
 | 
			
		||||
                janet_free(fiber->ev_state);
 | 
			
		||||
                janet_ev_dec_refcount();
 | 
			
		||||
            }
 | 
			
		||||
                fiber->ev_state = NULL;
 | 
			
		||||
            }
 | 
			
		||||
            janet_ev_dec_refcount();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, size_t data_size) {
 | 
			
		||||
void janet_async_in_flight(JanetFiber *fiber) {
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
 | 
			
		||||
#else
 | 
			
		||||
    (void) fiber;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_async_start(JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, void *state) {
 | 
			
		||||
    JanetFiber *fiber = janet_vm.root_fiber;
 | 
			
		||||
    janet_assert(!fiber->ev_callback, "double async on fiber");
 | 
			
		||||
    if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber;
 | 
			
		||||
    if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber;
 | 
			
		||||
@@ -275,14 +285,9 @@ void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode m
 | 
			
		||||
    fiber->ev_stream = stream;
 | 
			
		||||
    janet_ev_inc_refcount();
 | 
			
		||||
    janet_gcroot(janet_wrap_abstract(stream));
 | 
			
		||||
    if (data_size) {
 | 
			
		||||
        void *data = janet_malloc(data_size);
 | 
			
		||||
        fiber->ev_state = data;
 | 
			
		||||
        return data;
 | 
			
		||||
    } else {
 | 
			
		||||
        fiber->ev_state = NULL;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    fiber->ev_state = state;
 | 
			
		||||
    callback(fiber, JANET_ASYNC_EVENT_INIT);
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_fiber_did_resume(JanetFiber *fiber) {
 | 
			
		||||
@@ -1279,7 +1284,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout);
 | 
			
		||||
int janet_loop_done(void) {
 | 
			
		||||
    return !((janet_vm.spawn.head != janet_vm.spawn.tail) ||
 | 
			
		||||
             janet_vm.tq_count ||
 | 
			
		||||
             janet_vm.listener_count);
 | 
			
		||||
             janet_atomic_load(&janet_vm.listener_count));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JanetFiber *janet_loop1(void) {
 | 
			
		||||
@@ -1341,7 +1346,7 @@ JanetFiber *janet_loop1(void) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Poll for events */
 | 
			
		||||
    if (janet_vm.tq_count || janet_vm.listener_count) {
 | 
			
		||||
    if (janet_vm.tq_count || janet_atomic_load(&janet_vm.listener_count)) {
 | 
			
		||||
        JanetTimeout to;
 | 
			
		||||
        memset(&to, 0, sizeof(to));
 | 
			
		||||
        int has_timeout;
 | 
			
		||||
@@ -1360,7 +1365,7 @@ JanetFiber *janet_loop1(void) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        /* Run polling implementation only if pending timeouts or pending events */
 | 
			
		||||
        if (janet_vm.tq_count || janet_vm.listener_count) {
 | 
			
		||||
        if (janet_vm.tq_count || janet_atomic_load(&janet_vm.listener_count)) {
 | 
			
		||||
            janet_loop1_impl(has_timeout, to.when);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1813,8 +1818,8 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
 | 
			
		||||
        JanetStream *stream = janet_vm.streams[i];
 | 
			
		||||
        janet_vm.fds[i + 1].events = 0;
 | 
			
		||||
        janet_vm.fds[i + 1].revents = 0;
 | 
			
		||||
        if (stream->read_fiber) janet_vm.fds[i + 1].events |= POLLIN;
 | 
			
		||||
        if (stream->write_fiber) janet_vm.fds[i + 1].events |= POLLOUT;
 | 
			
		||||
        if (stream->read_fiber && stream->read_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLIN;
 | 
			
		||||
        if (stream->write_fiber && stream->write_fiber->ev_callback) janet_vm.fds[i + 1].events |= POLLOUT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Poll for events */
 | 
			
		||||
@@ -2026,6 +2031,7 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) {
 | 
			
		||||
    if (return_value.fiber == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (janet_fiber_can_resume(return_value.fiber)) {
 | 
			
		||||
        switch (return_value.tag) {
 | 
			
		||||
            default:
 | 
			
		||||
            case JANET_EV_TCTAG_NIL:
 | 
			
		||||
@@ -2054,6 +2060,7 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) {
 | 
			
		||||
                janet_schedule(return_value.fiber, janet_wrap_boolean(return_value.argi));
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    janet_gcunroot(janet_wrap_fiber(return_value.fiber));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2199,7 +2206,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* fallthrough */
 | 
			
		||||
        case JANET_ASYNC_EVENT_USER: {
 | 
			
		||||
        case JANET_ASYNC_EVENT_INIT: {
 | 
			
		||||
            int32_t chunk_size = state->bytes_left > JANET_EV_CHUNKSIZE ? JANET_EV_CHUNKSIZE : state->bytes_left;
 | 
			
		||||
            memset(&(state->overlapped), 0, sizeof(OVERLAPPED));
 | 
			
		||||
            int status;
 | 
			
		||||
@@ -2237,7 +2244,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
 | 
			
		||||
            janet_async_in_flight(fiber);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
#else
 | 
			
		||||
@@ -2253,7 +2260,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
 | 
			
		||||
    read_more:
 | 
			
		||||
        case JANET_ASYNC_EVENT_HUP:
 | 
			
		||||
        case JANET_ASYNC_EVENT_USER:
 | 
			
		||||
        case JANET_ASYNC_EVENT_INIT:
 | 
			
		||||
        case JANET_ASYNC_EVENT_READ: {
 | 
			
		||||
            JanetBuffer *buffer = state->buf;
 | 
			
		||||
            int32_t bytes_left = state->bytes_left;
 | 
			
		||||
@@ -2332,9 +2339,8 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int is_chunked, JanetReadMode mode, int flags) {
 | 
			
		||||
    JanetFiber *f = janet_vm.root_fiber;
 | 
			
		||||
    StateRead *state = (StateRead *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, ev_callback_read, sizeof(StateRead));
 | 
			
		||||
static JANET_NO_RETURN void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int is_chunked, JanetReadMode mode, int flags) {
 | 
			
		||||
    StateRead *state = janet_malloc(sizeof(StateRead));
 | 
			
		||||
    state->is_chunk = is_chunked;
 | 
			
		||||
    state->buf = buf;
 | 
			
		||||
    state->bytes_left = nbytes;
 | 
			
		||||
@@ -2345,23 +2351,23 @@ static void janet_ev_read_generic(JanetStream *stream, JanetBuffer *buf, int32_t
 | 
			
		||||
#else
 | 
			
		||||
    state->flags = flags;
 | 
			
		||||
#endif
 | 
			
		||||
    ev_callback_read(f, JANET_ASYNC_EVENT_USER);
 | 
			
		||||
    janet_async_start(stream, JANET_ASYNC_LISTEN_READ, ev_callback_read, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
 | 
			
		||||
    janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_READ, 0);
 | 
			
		||||
}
 | 
			
		||||
void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
 | 
			
		||||
    janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_READ, 0);
 | 
			
		||||
}
 | 
			
		||||
#ifdef JANET_NET
 | 
			
		||||
void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
    janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECV, flags);
 | 
			
		||||
}
 | 
			
		||||
void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
    janet_ev_read_generic(stream, buf, nbytes, 1, JANET_ASYNC_READMODE_RECV, flags);
 | 
			
		||||
}
 | 
			
		||||
void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
 | 
			
		||||
    janet_ev_read_generic(stream, buf, nbytes, 0, JANET_ASYNC_READMODE_RECVFROM, flags);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2431,7 +2437,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
        case JANET_ASYNC_EVENT_USER: {
 | 
			
		||||
        case JANET_ASYNC_EVENT_INIT: {
 | 
			
		||||
            /* Begin write */
 | 
			
		||||
            int32_t len;
 | 
			
		||||
            const uint8_t *bytes;
 | 
			
		||||
@@ -2461,7 +2467,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
                status = WSASendTo(sock, &state->wbuf, 1, NULL, state->flags, to, tolen, &state->overlapped, NULL);
 | 
			
		||||
                if (status) {
 | 
			
		||||
                    if (WSA_IO_PENDING == WSAGetLastError()) {
 | 
			
		||||
                        fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
 | 
			
		||||
                        janet_async_in_flight(fiber);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        janet_cancel(fiber, janet_ev_lasterr());
 | 
			
		||||
                        janet_async_end(fiber);
 | 
			
		||||
@@ -2486,7 +2492,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
                status = WriteFile(stream->handle, bytes, len, NULL, &state->overlapped);
 | 
			
		||||
                if (!status) {
 | 
			
		||||
                    if (ERROR_IO_PENDING == GetLastError()) {
 | 
			
		||||
                        fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
 | 
			
		||||
                        janet_async_in_flight(fiber);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        janet_cancel(fiber, janet_ev_lasterr());
 | 
			
		||||
                        janet_async_end(fiber);
 | 
			
		||||
@@ -2505,7 +2511,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
            janet_cancel(fiber, janet_cstringv("stream hup"));
 | 
			
		||||
            janet_async_end(fiber);
 | 
			
		||||
            break;
 | 
			
		||||
        case JANET_ASYNC_EVENT_USER:
 | 
			
		||||
        case JANET_ASYNC_EVENT_INIT:
 | 
			
		||||
        case JANET_ASYNC_EVENT_WRITE: {
 | 
			
		||||
            int32_t start, len;
 | 
			
		||||
            const uint8_t *bytes;
 | 
			
		||||
@@ -2570,10 +2576,8 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_abst, JanetWriteMode mode, int is_buffer, int flags) {
 | 
			
		||||
    JanetFiber *f = janet_vm.root_fiber;
 | 
			
		||||
    StateWrite *state = (StateWrite *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE,
 | 
			
		||||
                        ev_callback_write, sizeof(StateWrite));
 | 
			
		||||
static JANET_NO_RETURN void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_abst, JanetWriteMode mode, int is_buffer, int flags) {
 | 
			
		||||
    StateWrite *state = janet_malloc(sizeof(StateWrite));
 | 
			
		||||
    state->is_buffer = is_buffer;
 | 
			
		||||
    state->src.buf = buf;
 | 
			
		||||
    state->dest_abst = dest_abst;
 | 
			
		||||
@@ -2584,31 +2588,31 @@ static void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_ab
 | 
			
		||||
    state->flags = flags;
 | 
			
		||||
    state->start = 0;
 | 
			
		||||
#endif
 | 
			
		||||
    ev_callback_write(f, JANET_ASYNC_EVENT_USER);
 | 
			
		||||
    janet_async_start(stream, JANET_ASYNC_LISTEN_WRITE, ev_callback_write, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf) {
 | 
			
		||||
    janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_WRITE, 1, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_write_string(JanetStream *stream, JanetString str) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_write_string(JanetStream *stream, JanetString str) {
 | 
			
		||||
    janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_WRITE, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef JANET_NET
 | 
			
		||||
void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags) {
 | 
			
		||||
    janet_ev_write_generic(stream, buf, NULL, JANET_ASYNC_WRITEMODE_SEND, 1, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_send_string(JanetStream *stream, JanetString str, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_send_string(JanetStream *stream, JanetString str, int flags) {
 | 
			
		||||
    janet_ev_write_generic(stream, (void *) str, NULL, JANET_ASYNC_WRITEMODE_SEND, 0, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags) {
 | 
			
		||||
    janet_ev_write_generic(stream, buf, dest, JANET_ASYNC_WRITEMODE_SENDTO, 1, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags) {
 | 
			
		||||
JANET_NO_RETURN void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags) {
 | 
			
		||||
    janet_ev_write_generic(stream, (void *) str, dest, JANET_ASYNC_WRITEMODE_SENDTO, 0, flags);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2999,7 +3003,6 @@ JANET_CORE_FN(janet_cfun_stream_read,
 | 
			
		||||
        if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
        janet_ev_read(stream, buffer, n);
 | 
			
		||||
    }
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(janet_cfun_stream_chunk,
 | 
			
		||||
@@ -3014,7 +3017,6 @@ JANET_CORE_FN(janet_cfun_stream_chunk,
 | 
			
		||||
    double to = janet_optnumber(argv, argc, 3, INFINITY);
 | 
			
		||||
    if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
    janet_ev_readchunk(stream, buffer, n);
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(janet_cfun_stream_write,
 | 
			
		||||
@@ -3034,7 +3036,6 @@ JANET_CORE_FN(janet_cfun_stream_write,
 | 
			
		||||
        if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
        janet_ev_write_string(stream, bytes.bytes);
 | 
			
		||||
    }
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mutexgc(void *p, size_t size) {
 | 
			
		||||
 
 | 
			
		||||
@@ -185,6 +185,19 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags);
 | 
			
		||||
/* Prevent stack overflows */
 | 
			
		||||
#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 */
 | 
			
		||||
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
 | 
			
		||||
    MARSH_STACKCHECK;
 | 
			
		||||
@@ -197,7 +210,9 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
 | 
			
		||||
    }
 | 
			
		||||
    janet_env_valid(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, env->length);
 | 
			
		||||
        Janet *values = env->as.fiber->data + env->offset;
 | 
			
		||||
@@ -328,7 +343,7 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
 | 
			
		||||
    while (i > 0) {
 | 
			
		||||
        JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
 | 
			
		||||
        if (frame->env) frame->flags |= JANET_STACKFRAME_HASENV;
 | 
			
		||||
        if (!frame->func) janet_panic("cannot marshal fiber with c stackframe");
 | 
			
		||||
        if (!frame->func) janet_panicf("cannot marshal fiber with c stackframe (%v)", janet_wrap_cfunction((JanetCFunction) frame->pc));
 | 
			
		||||
        pushint(st, frame->flags);
 | 
			
		||||
        pushint(st, frame->prevframe);
 | 
			
		||||
        int32_t pcdiff = (int32_t)(frame->pc - frame->func->def->bytecode);
 | 
			
		||||
 
 | 
			
		||||
@@ -79,12 +79,20 @@ const JanetAbstractType janet_address_type = {
 | 
			
		||||
 | 
			
		||||
/* maximum number of bytes in a socket address host (post name resolution) */
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
#ifdef JANET_NO_IPV6
 | 
			
		||||
#define SA_ADDRSTRLEN (INET_ADDRSTRLEN + 1)
 | 
			
		||||
#else
 | 
			
		||||
#define SA_ADDRSTRLEN (INET6_ADDRSTRLEN + 1)
 | 
			
		||||
#endif
 | 
			
		||||
typedef unsigned short in_port_t;
 | 
			
		||||
#else
 | 
			
		||||
#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)
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static JanetStream *make_stream(JSock handle, uint32_t flags);
 | 
			
		||||
 | 
			
		||||
@@ -114,16 +122,18 @@ static void janet_net_socknoblock(JSock s) {
 | 
			
		||||
 | 
			
		||||
/* State machine for async connect */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int did_connect;
 | 
			
		||||
} NetStateConnect;
 | 
			
		||||
 | 
			
		||||
void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
    JanetStream *stream = fiber->ev_stream;
 | 
			
		||||
    NetStateConnect *state = (NetStateConnect *)fiber->ev_state;
 | 
			
		||||
    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);
 | 
			
		||||
@@ -140,7 +150,6 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
#endif
 | 
			
		||||
    if (r == 0) {
 | 
			
		||||
        if (res == 0) {
 | 
			
		||||
            state->did_connect = 1;
 | 
			
		||||
            janet_schedule(fiber, janet_wrap_abstract(stream));
 | 
			
		||||
        } else {
 | 
			
		||||
            janet_cancel(fiber, janet_cstringv(strerror(res)));
 | 
			
		||||
@@ -153,13 +162,8 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
    janet_async_end(fiber);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void net_sched_connect(JanetStream *stream) {
 | 
			
		||||
    JanetFiber *f = janet_vm.root_fiber;
 | 
			
		||||
    NetStateConnect *state = (NetStateConnect *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, sizeof(NetStateConnect));
 | 
			
		||||
    state->did_connect = 0;
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    net_callback_connect(f, JANET_ASYNC_EVENT_USER);
 | 
			
		||||
#endif
 | 
			
		||||
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. */
 | 
			
		||||
@@ -229,14 +233,16 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
 | 
			
		||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
 | 
			
		||||
    Janet err;
 | 
			
		||||
    JanetFiber *f = janet_vm.root_fiber;
 | 
			
		||||
    NetStateAccept *state = (NetStateAccept *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, sizeof(NetStateAccept));
 | 
			
		||||
    NetStateAccept *state = janet_malloc(sizeof(NetStateAccept));
 | 
			
		||||
    memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED));
 | 
			
		||||
    memset(&state->buf, 0, 1024);
 | 
			
		||||
    state->function = fun;
 | 
			
		||||
    state->lstream = stream;
 | 
			
		||||
    if (net_sched_accept_impl(state, f, &err)) janet_panicv(err);
 | 
			
		||||
    janet_await();
 | 
			
		||||
    if (net_sched_accept_impl(state, janet_root_fiber(), &err)) {
 | 
			
		||||
        janet_free(state);
 | 
			
		||||
        janet_panicv(err);
 | 
			
		||||
    }
 | 
			
		||||
    janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err) {
 | 
			
		||||
@@ -253,7 +259,7 @@ static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet
 | 
			
		||||
        int code = WSAGetLastError();
 | 
			
		||||
        if (code == WSA_IO_PENDING) {
 | 
			
		||||
            /* indicates io is happening async */
 | 
			
		||||
            fiber->flags |= JANET_FIBER_EV_FLAG_IN_FLIGHT;
 | 
			
		||||
            janet_async_in_flight(fiber);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        *err = janet_ev_lasterr();
 | 
			
		||||
@@ -282,7 +288,7 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
            janet_schedule(fiber, janet_wrap_nil());
 | 
			
		||||
            janet_async_end(fiber);
 | 
			
		||||
            return;
 | 
			
		||||
        case JANET_ASYNC_EVENT_USER:
 | 
			
		||||
        case JANET_ASYNC_EVENT_INIT:
 | 
			
		||||
        case JANET_ASYNC_EVENT_READ: {
 | 
			
		||||
#if defined(JANET_LINUX)
 | 
			
		||||
            JSock connfd = accept4(stream->handle, NULL, NULL, SOCK_CLOEXEC);
 | 
			
		||||
@@ -310,11 +316,10 @@ void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) {
 | 
			
		||||
    JanetFiber *f = janet_vm.root_fiber;
 | 
			
		||||
    NetStateAccept *state = (NetStateAccept *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, sizeof(NetStateAccept));
 | 
			
		||||
    NetStateAccept *state = janet_malloc(sizeof(NetStateAccept));
 | 
			
		||||
    memset(state, 0, sizeof(NetStateAccept));
 | 
			
		||||
    state->function = fun;
 | 
			
		||||
    net_callback_accept(f, JANET_ASYNC_EVENT_USER);
 | 
			
		||||
    janet_await();
 | 
			
		||||
    janet_async_start(stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -570,7 +575,6 @@ JANET_CORE_FN(cfun_net_connect,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    net_sched_connect(stream);
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *serverify_socket(JSock sfd) {
 | 
			
		||||
@@ -741,6 +745,7 @@ static Janet janet_so_getname(const void *sa_any) {
 | 
			
		||||
            Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai->sin_port))};
 | 
			
		||||
            return janet_wrap_tuple(janet_tuple_n(pair, 2));
 | 
			
		||||
        }
 | 
			
		||||
#ifndef JANET_NO_IPV6
 | 
			
		||||
        case AF_INET6: {
 | 
			
		||||
            const struct sockaddr_in6 *sai6 = sa_any;
 | 
			
		||||
            if (!inet_ntop(AF_INET6, &(sai6->sin6_addr), buffer, sizeof(buffer))) {
 | 
			
		||||
@@ -749,6 +754,7 @@ static Janet janet_so_getname(const void *sa_any) {
 | 
			
		||||
            Janet pair[2] = {janet_cstringv(buffer), janet_wrap_integer(ntohs(sai6->sin6_port))};
 | 
			
		||||
            return janet_wrap_tuple(janet_tuple_n(pair, 2));
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef JANET_WINDOWS
 | 
			
		||||
        case AF_UNIX: {
 | 
			
		||||
            const struct sockaddr_un *sun = sa_any;
 | 
			
		||||
@@ -815,6 +821,7 @@ JANET_CORE_FN(cfun_stream_accept_loop,
 | 
			
		||||
    JanetStream *stream = janet_getabstract(argv, 0, &janet_stream_type);
 | 
			
		||||
    janet_stream_flags(stream, JANET_STREAM_ACCEPTABLE | JANET_STREAM_SOCKET);
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -851,7 +858,6 @@ JANET_CORE_FN(cfun_stream_read,
 | 
			
		||||
        if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
        janet_ev_recv(stream, buffer, n, MSG_NOSIGNAL);
 | 
			
		||||
    }
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(cfun_stream_chunk,
 | 
			
		||||
@@ -866,7 +872,6 @@ JANET_CORE_FN(cfun_stream_chunk,
 | 
			
		||||
    double to = janet_optnumber(argv, argc, 3, INFINITY);
 | 
			
		||||
    if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
    janet_ev_recvchunk(stream, buffer, n, MSG_NOSIGNAL);
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(cfun_stream_recv_from,
 | 
			
		||||
@@ -881,7 +886,6 @@ JANET_CORE_FN(cfun_stream_recv_from,
 | 
			
		||||
    double to = janet_optnumber(argv, argc, 3, INFINITY);
 | 
			
		||||
    if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
    janet_ev_recvfrom(stream, buffer, n, MSG_NOSIGNAL);
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(cfun_stream_write,
 | 
			
		||||
@@ -901,7 +905,6 @@ JANET_CORE_FN(cfun_stream_write,
 | 
			
		||||
        if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
        janet_ev_send_string(stream, bytes.bytes, MSG_NOSIGNAL);
 | 
			
		||||
    }
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(cfun_stream_send_to,
 | 
			
		||||
@@ -922,7 +925,6 @@ JANET_CORE_FN(cfun_stream_send_to,
 | 
			
		||||
        if (to != INFINITY) janet_addtimeout(to);
 | 
			
		||||
        janet_ev_sendto_string(stream, bytes.bytes, dest, MSG_NOSIGNAL);
 | 
			
		||||
    }
 | 
			
		||||
    janet_await();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(cfun_stream_flush,
 | 
			
		||||
@@ -956,8 +958,10 @@ static const struct sockopt_type sockopt_type_list[] = {
 | 
			
		||||
    { "ip-multicast-ttl", IPPROTO_IP, IP_MULTICAST_TTL, JANET_NUMBER },
 | 
			
		||||
    { "ip-add-membership", IPPROTO_IP, IP_ADD_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-leave-group", IPPROTO_IPV6, IPV6_LEAVE_GROUP, JANET_POINTER },
 | 
			
		||||
#endif
 | 
			
		||||
    { NULL, 0, 0, JANET_POINTER }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -994,7 +998,9 @@ JANET_CORE_FN(cfun_net_setsockopt,
 | 
			
		||||
    union {
 | 
			
		||||
        int v_int;
 | 
			
		||||
        struct ip_mreq v_mreq;
 | 
			
		||||
#ifndef JANET_NO_IPV6
 | 
			
		||||
        struct ipv6_mreq v_mreq6;
 | 
			
		||||
#endif
 | 
			
		||||
    } val;
 | 
			
		||||
 | 
			
		||||
    void *optval = (void *)&val;
 | 
			
		||||
@@ -1012,12 +1018,14 @@ JANET_CORE_FN(cfun_net_setsockopt,
 | 
			
		||||
        val.v_mreq.imr_interface.s_addr = htonl(INADDR_ANY);
 | 
			
		||||
        inet_pton(AF_INET, addr, &val.v_mreq.imr_multiaddr.s_addr);
 | 
			
		||||
        optlen = sizeof(val.v_mreq);
 | 
			
		||||
#ifndef JANET_NO_IPV6
 | 
			
		||||
    } else if (st->optname == IPV6_JOIN_GROUP || st->optname == IPV6_LEAVE_GROUP) {
 | 
			
		||||
        const char *addr = janet_getcstring(argv, 2);
 | 
			
		||||
        memset(&val.v_mreq6, 0, sizeof val.v_mreq6);
 | 
			
		||||
        val.v_mreq6.ipv6mr_interface = 0;
 | 
			
		||||
        inet_pton(AF_INET6, addr, &val.v_mreq6.ipv6mr_multiaddr);
 | 
			
		||||
        optlen = sizeof(val.v_mreq6);
 | 
			
		||||
#endif
 | 
			
		||||
    } else {
 | 
			
		||||
        janet_panicf("invalid socket option type");
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										108
									
								
								src/core/os.c
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								src/core/os.c
									
									
									
									
									
								
							@@ -529,10 +529,12 @@ static void janet_proc_wait_cb(JanetEVGenericMessage args) {
 | 
			
		||||
            JanetString s = janet_formatc("command failed with non-zero exit code %d", status);
 | 
			
		||||
            janet_cancel(args.fiber, janet_wrap_string(s));
 | 
			
		||||
        } else {
 | 
			
		||||
            if (janet_fiber_can_resume(args.fiber)) {
 | 
			
		||||
                janet_schedule(args.fiber, janet_wrap_integer(status));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* End ev check */
 | 
			
		||||
 | 
			
		||||
@@ -640,7 +642,7 @@ static const struct keyword_signal signal_keywords[] = {
 | 
			
		||||
#ifdef SIGTERM
 | 
			
		||||
    {"term", SIGTERM},
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SIGARLM
 | 
			
		||||
#ifdef SIGALRM
 | 
			
		||||
    {"alrm", SIGALRM},
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SIGHUP
 | 
			
		||||
@@ -1081,11 +1083,18 @@ static JanetFile *get_stdio_for_handle(JanetHandle handle, void *orig, int iswri
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
 | 
			
		||||
typedef enum {
 | 
			
		||||
    JANET_EXECUTE_EXECUTE,
 | 
			
		||||
    JANET_EXECUTE_SPAWN,
 | 
			
		||||
    JANET_EXECUTE_EXEC
 | 
			
		||||
} JanetExecuteMode;
 | 
			
		||||
 | 
			
		||||
static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
 | 
			
		||||
    janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
 | 
			
		||||
    janet_arity(argc, 1, 3);
 | 
			
		||||
 | 
			
		||||
    /* Get flags */
 | 
			
		||||
    int is_spawn = mode == JANET_EXECUTE_SPAWN;
 | 
			
		||||
    uint64_t flags = 0;
 | 
			
		||||
    if (argc > 1) {
 | 
			
		||||
        flags = janet_getflags(argv, 1, "epxd");
 | 
			
		||||
@@ -1109,7 +1118,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
 | 
			
		||||
    int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0;
 | 
			
		||||
 | 
			
		||||
    /* Get optional redirections */
 | 
			
		||||
    if (argc > 2) {
 | 
			
		||||
    if (argc > 2 && (mode != JANET_EXECUTE_EXEC)) {
 | 
			
		||||
        JanetDictView tab = janet_getdictionary(argv, 2);
 | 
			
		||||
        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"));
 | 
			
		||||
@@ -1230,12 +1239,32 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
 | 
			
		||||
     * of posix_spawn would modify the argv array passed in. */
 | 
			
		||||
    char *const *cargv = (char *const *)child_argv;
 | 
			
		||||
 | 
			
		||||
    /* Use posix_spawn to spawn new process */
 | 
			
		||||
 | 
			
		||||
    if (use_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_file_actions_t actions;
 | 
			
		||||
    posix_spawn_file_actions_init(&actions);
 | 
			
		||||
@@ -1344,7 +1373,7 @@ JANET_CORE_FN(os_execute,
 | 
			
		||||
              "contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
 | 
			
		||||
              "These arguments should be core/file values. "
 | 
			
		||||
              "Returns the exit status of the program.") {
 | 
			
		||||
    return os_execute_impl(argc, argv, 0);
 | 
			
		||||
    return os_execute_impl(argc, argv, JANET_EXECUTE_EXECUTE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(os_spawn,
 | 
			
		||||
@@ -1357,7 +1386,43 @@ JANET_CORE_FN(os_spawn,
 | 
			
		||||
              "The returned value `proc` has the fields :in, :out, :err, :return-code, and "
 | 
			
		||||
              "the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
 | 
			
		||||
              "subprocess or `(os/proc-kill proc)`.") {
 | 
			
		||||
    return os_execute_impl(argc, argv, 1);
 | 
			
		||||
    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
 | 
			
		||||
@@ -2336,34 +2401,6 @@ JANET_CORE_FN(os_permission_int,
 | 
			
		||||
    return janet_wrap_integer(os_get_unix_mode(argv, 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JANET_CORE_FN(os_posix_fork,
 | 
			
		||||
              "(os/posix-fork)",
 | 
			
		||||
              "Make a `fork` system call and create a new process. Return nil if in the new process, otherwise a core/process object (as returned by os/spawn). "
 | 
			
		||||
              "Not supported on all systems (POSIX only).") {
 | 
			
		||||
    janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
 | 
			
		||||
    janet_fixarity(argc, 0);
 | 
			
		||||
    (void) argv;
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    janet_panic("not supported");
 | 
			
		||||
#else
 | 
			
		||||
    pid_t result;
 | 
			
		||||
    do {
 | 
			
		||||
        result = fork();
 | 
			
		||||
    } while (result == -1 && errno == EINTR);
 | 
			
		||||
    if (result == -1) {
 | 
			
		||||
        janet_panic(strerror(errno));
 | 
			
		||||
    }
 | 
			
		||||
    if (result) {
 | 
			
		||||
        JanetProc *proc = janet_abstract(&ProcAT, sizeof(JanetProc));
 | 
			
		||||
        memset(proc, 0, sizeof(JanetProc));
 | 
			
		||||
        proc->pid = result;
 | 
			
		||||
        proc->flags = JANET_PROC_ALLOW_ZOMBIE;
 | 
			
		||||
        return janet_wrap_abstract(proc);
 | 
			
		||||
    }
 | 
			
		||||
    return janet_wrap_nil();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef JANET_EV
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -2651,6 +2688,7 @@ void janet_lib_os(JanetTable *env) {
 | 
			
		||||
        JANET_CORE_REG("os/spawn", os_spawn),
 | 
			
		||||
        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
 | 
			
		||||
         * (allows for limited functionality if use exposes C-functions to create specific processes) */
 | 
			
		||||
        JANET_CORE_REG("os/proc-wait", os_proc_wait),
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,10 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const uint8_t *text_start;
 | 
			
		||||
    const uint8_t *text_end;
 | 
			
		||||
    /* text_end will be restricted in a (sub) rule, 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 Janet *constants;
 | 
			
		||||
    JanetArray *captures;
 | 
			
		||||
@@ -114,12 +118,12 @@ static LineCol get_linecol_from_position(PegState *s, int32_t position) {
 | 
			
		||||
    /* Generate if not made yet */
 | 
			
		||||
    if (s->linemaplen < 0) {
 | 
			
		||||
        int32_t newline_count = 0;
 | 
			
		||||
        for (const uint8_t *c = s->text_start; c < s->text_end; c++) {
 | 
			
		||||
        for (const uint8_t *c = s->text_start; c < s->outer_text_end; c++) {
 | 
			
		||||
            if (*c == '\n') newline_count++;
 | 
			
		||||
        }
 | 
			
		||||
        int32_t *mem = janet_smalloc(sizeof(int32_t) * newline_count);
 | 
			
		||||
        size_t index = 0;
 | 
			
		||||
        for (const uint8_t *c = s->text_start; c < s->text_end; c++) {
 | 
			
		||||
        for (const uint8_t *c = s->text_start; c < s->outer_text_end; c++) {
 | 
			
		||||
            if (*c == '\n') mem[index++] = (int32_t)(c - s->text_start);
 | 
			
		||||
        }
 | 
			
		||||
        s->linemaplen = newline_count;
 | 
			
		||||
@@ -179,7 +183,7 @@ static const uint8_t *peg_rule(
 | 
			
		||||
    const uint32_t *rule,
 | 
			
		||||
    const uint8_t *text) {
 | 
			
		||||
tail:
 | 
			
		||||
    switch (*rule & 0x1F) {
 | 
			
		||||
    switch (*rule) {
 | 
			
		||||
        default:
 | 
			
		||||
            janet_panic("unexpected opcode");
 | 
			
		||||
            return NULL;
 | 
			
		||||
@@ -482,6 +486,30 @@ tail:
 | 
			
		||||
            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_REPLACE:
 | 
			
		||||
        case RULE_MATCHTIME: {
 | 
			
		||||
            uint32_t tag = rule[3];
 | 
			
		||||
@@ -1107,6 +1135,14 @@ static void spec_matchtime(Builder *b, int32_t argc, const Janet *argv) {
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef JANET_INT_TYPES
 | 
			
		||||
#define JANET_MAX_READINT_WIDTH 8
 | 
			
		||||
#else
 | 
			
		||||
@@ -1190,6 +1226,7 @@ static const SpecialPair peg_specials[] = {
 | 
			
		||||
    {"sequence", spec_sequence},
 | 
			
		||||
    {"set", spec_set},
 | 
			
		||||
    {"some", spec_some},
 | 
			
		||||
    {"sub", spec_sub},
 | 
			
		||||
    {"thru", spec_thru},
 | 
			
		||||
    {"to", spec_to},
 | 
			
		||||
    {"uint", spec_uint_le},
 | 
			
		||||
@@ -1431,7 +1468,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
 | 
			
		||||
        uint32_t instr = bytecode[i];
 | 
			
		||||
        uint32_t *rule = bytecode + i;
 | 
			
		||||
        op_flags[i] |= 0x02;
 | 
			
		||||
        switch (instr & 0x1F) {
 | 
			
		||||
        switch (instr) {
 | 
			
		||||
            case RULE_LITERAL:
 | 
			
		||||
                i += 2 + ((rule[1] + 3) >> 2);
 | 
			
		||||
                break;
 | 
			
		||||
@@ -1524,6 +1561,14 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
 | 
			
		||||
                op_flags[rule[1]] |= 0x01;
 | 
			
		||||
                i += 4;
 | 
			
		||||
                break;
 | 
			
		||||
            case RULE_SUB:
 | 
			
		||||
                /* [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_DROP:
 | 
			
		||||
            case RULE_NOT:
 | 
			
		||||
@@ -1652,7 +1697,7 @@ typedef struct {
 | 
			
		||||
static PegCall peg_cfun_init(int32_t argc, Janet *argv, int get_replace) {
 | 
			
		||||
    PegCall ret;
 | 
			
		||||
    int32_t min = get_replace ? 3 : 2;
 | 
			
		||||
    janet_arity(argc, get_replace, -1);
 | 
			
		||||
    janet_arity(argc, min, -1);
 | 
			
		||||
    if (janet_checktype(argv[0], JANET_ABSTRACT) &&
 | 
			
		||||
            janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
 | 
			
		||||
        ret.peg = janet_unwrap_abstract(argv[0]);
 | 
			
		||||
@@ -1677,6 +1722,7 @@ static PegCall peg_cfun_init(int32_t argc, Janet *argv, int get_replace) {
 | 
			
		||||
    ret.s.mode = PEG_MODE_NORMAL;
 | 
			
		||||
    ret.s.text_start = ret.bytes.bytes;
 | 
			
		||||
    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.captures = janet_array(0);
 | 
			
		||||
    ret.s.tagged_captures = janet_array(0);
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <float.h>
 | 
			
		||||
 | 
			
		||||
/* Implements a pretty printer for Janet. The pretty printer
 | 
			
		||||
 * is simple and not that flexible, but fast. */
 | 
			
		||||
@@ -38,11 +39,15 @@
 | 
			
		||||
/* Temporary buffer size */
 | 
			
		||||
#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) {
 | 
			
		||||
    janet_buffer_ensure(buffer, buffer->count + BUFSIZE, 2);
 | 
			
		||||
    const char *fmt = (x == floor(x) &&
 | 
			
		||||
                       x <= JANET_INTMAX_DOUBLE &&
 | 
			
		||||
                       x >= JANET_INTMIN_DOUBLE) ? "%.0f" : "%g";
 | 
			
		||||
                       x >= JANET_INTMIN_DOUBLE) ? "%.0f" : ("%." STR(DBL_DIG) "g");
 | 
			
		||||
    int count;
 | 
			
		||||
    if (x == 0.0) {
 | 
			
		||||
        /* Prevent printing of '-0' */
 | 
			
		||||
@@ -772,6 +777,8 @@ struct FmtMapping {
 | 
			
		||||
/* Janet uses fixed width integer types for most things, so map
 | 
			
		||||
 * format specifiers to these fixed sizes */
 | 
			
		||||
static const struct FmtMapping format_mappings[] = {
 | 
			
		||||
    {'D', PRId64},
 | 
			
		||||
    {'I', PRIi64},
 | 
			
		||||
    {'d', PRId64},
 | 
			
		||||
    {'i', PRIi64},
 | 
			
		||||
    {'o', PRIo64},
 | 
			
		||||
@@ -850,13 +857,19 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
 | 
			
		||||
            c = scanformat(c, form, width, precision);
 | 
			
		||||
            switch (*c++) {
 | 
			
		||||
                case 'c': {
 | 
			
		||||
                    int n = va_arg(args, long);
 | 
			
		||||
                    int n = va_arg(args, int);
 | 
			
		||||
                    nb = snprintf(item, MAX_ITEM, form, n);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'd':
 | 
			
		||||
                case 'i': {
 | 
			
		||||
                    int64_t n = va_arg(args, int);
 | 
			
		||||
                    int64_t n = (int64_t) va_arg(args, int32_t);
 | 
			
		||||
                    nb = snprintf(item, MAX_ITEM, form, n);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'D':
 | 
			
		||||
                case 'I': {
 | 
			
		||||
                    int64_t n = va_arg(args, int64_t);
 | 
			
		||||
                    nb = snprintf(item, MAX_ITEM, form, n);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -864,7 +877,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
 | 
			
		||||
                case 'X':
 | 
			
		||||
                case 'o':
 | 
			
		||||
                case 'u': {
 | 
			
		||||
                    uint64_t n = va_arg(args, unsigned int);
 | 
			
		||||
                    uint64_t n = va_arg(args, uint64_t);
 | 
			
		||||
                    nb = snprintf(item, MAX_ITEM, form, n);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -908,7 +921,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
 | 
			
		||||
                    janet_buffer_push_cstring(b, typestr(va_arg(args, Janet)));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'T': {
 | 
			
		||||
                    int types = va_arg(args, long);
 | 
			
		||||
                    int types = va_arg(args, int);
 | 
			
		||||
                    pushtypes(b, types);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -1017,6 +1030,8 @@ void janet_buffer_format(
 | 
			
		||||
                                  janet_getinteger(argv, arg));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'D':
 | 
			
		||||
                case 'I':
 | 
			
		||||
                case 'd':
 | 
			
		||||
                case 'i': {
 | 
			
		||||
                    int64_t n = janet_getinteger64(argv, arg);
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
 | 
			
		||||
    int errflags = 0, done = 0;
 | 
			
		||||
    int32_t index = 0;
 | 
			
		||||
    Janet ret = janet_wrap_nil();
 | 
			
		||||
    JanetFiber *fiber = NULL;
 | 
			
		||||
    const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
 | 
			
		||||
 | 
			
		||||
    if (where) janet_gcroot(janet_wrap_string(where));
 | 
			
		||||
@@ -47,7 +48,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
 | 
			
		||||
            JanetCompileResult cres = janet_compile(form, env, where);
 | 
			
		||||
            if (cres.status == JANET_COMPILE_OK) {
 | 
			
		||||
                JanetFunction *f = janet_thunk(cres.funcdef);
 | 
			
		||||
                JanetFiber *fiber = janet_fiber(f, 64, 0, NULL);
 | 
			
		||||
                fiber = janet_fiber(f, 64, 0, NULL);
 | 
			
		||||
                fiber->env = env;
 | 
			
		||||
                JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
 | 
			
		||||
                if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
 | 
			
		||||
@@ -112,9 +113,14 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
 | 
			
		||||
#ifdef JANET_EV
 | 
			
		||||
    /* Enter the event loop if we are not already in it */
 | 
			
		||||
    if (janet_vm.stackn == 0) {
 | 
			
		||||
        janet_gcroot(ret);
 | 
			
		||||
        if (fiber) {
 | 
			
		||||
            janet_gcroot(janet_wrap_fiber(fiber));
 | 
			
		||||
        }
 | 
			
		||||
        janet_loop();
 | 
			
		||||
        janet_gcunroot(ret);
 | 
			
		||||
        if (fiber) {
 | 
			
		||||
            janet_gcunroot(janet_wrap_fiber(fiber));
 | 
			
		||||
            ret = fiber->last_value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    if (out) *out = ret;
 | 
			
		||||
 
 | 
			
		||||
@@ -531,17 +531,11 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check if a form matches the pattern (= nil _) or (not= nil _) */
 | 
			
		||||
static int janetc_check_nil_form(JanetFopts opts, Janet x, Janet *capture, uint32_t fun_tag) {
 | 
			
		||||
static int janetc_check_nil_form(Janet x, Janet *capture, uint32_t fun_tag) {
 | 
			
		||||
    if (!janet_checktype(x, JANET_TUPLE)) return 0;
 | 
			
		||||
    JanetTuple tup = janet_unwrap_tuple(x);
 | 
			
		||||
    if (3 != janet_tuple_length(tup)) return 0;
 | 
			
		||||
    Janet op1 = tup[0];
 | 
			
		||||
    if (janet_checktype(op1, JANET_SYMBOL)) {
 | 
			
		||||
        Janet entry = janet_table_get(opts.compiler->env, op1);
 | 
			
		||||
        if (janet_checktype(entry, JANET_TABLE)) {
 | 
			
		||||
            op1 = janet_table_get(janet_unwrap_table(entry), janet_ckeywordv("value"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!janet_checktype(op1, JANET_FUNCTION)) return 0;
 | 
			
		||||
    JanetFunction *fun = janet_unwrap_function(op1);
 | 
			
		||||
    uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
 | 
			
		||||
@@ -601,10 +595,9 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
 | 
			
		||||
    janetc_scope(&condscope, c, 0, "if");
 | 
			
		||||
 | 
			
		||||
    Janet condform = argv[0];
 | 
			
		||||
    if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_EQ)) {
 | 
			
		||||
    if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
 | 
			
		||||
        ifnjmp = JOP_JUMP_IF_NOT_NIL;
 | 
			
		||||
    }
 | 
			
		||||
    if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_NEQ)) {
 | 
			
		||||
    } else if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
 | 
			
		||||
        ifnjmp = JOP_JUMP_IF_NIL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -613,7 +606,11 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
 | 
			
		||||
    /* Check constant condition. */
 | 
			
		||||
    /* TODO: Use type info for more short circuits */
 | 
			
		||||
    if (cond.flags & JANET_SLOT_CONSTANT) {
 | 
			
		||||
        if (!janet_truthy(cond.constant)) {
 | 
			
		||||
        int swap_condition = 0;
 | 
			
		||||
        if (ifnjmp == JOP_JUMP_IF_NOT && !janet_truthy(cond.constant)) swap_condition = 1;
 | 
			
		||||
        if (ifnjmp == JOP_JUMP_IF_NIL && janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
 | 
			
		||||
        if (ifnjmp == JOP_JUMP_IF_NOT_NIL && !janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
 | 
			
		||||
        if (swap_condition) {
 | 
			
		||||
            /* Swap the true and false bodies */
 | 
			
		||||
            Janet temp = falsebody;
 | 
			
		||||
            falsebody = truebody;
 | 
			
		||||
@@ -808,12 +805,12 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
 | 
			
		||||
     * jmpnl or jmpnn instructions. This let's us implement `(each ...)`
 | 
			
		||||
     * more efficiently. */
 | 
			
		||||
    Janet condform = argv[0];
 | 
			
		||||
    if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_EQ)) {
 | 
			
		||||
    if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
 | 
			
		||||
        is_nil_form = 1;
 | 
			
		||||
        ifjmp = JOP_JUMP_IF_NIL;
 | 
			
		||||
        ifnjmp = JOP_JUMP_IF_NOT_NIL;
 | 
			
		||||
    }
 | 
			
		||||
    if (janetc_check_nil_form(opts, condform, &condform, JANET_FUN_NEQ)) {
 | 
			
		||||
    if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
 | 
			
		||||
        is_notnil_form = 1;
 | 
			
		||||
        ifjmp = JOP_JUMP_IF_NOT_NIL;
 | 
			
		||||
        ifnjmp = JOP_JUMP_IF_NIL;
 | 
			
		||||
 
 | 
			
		||||
@@ -549,8 +549,8 @@ JANET_CORE_FN(cfun_string_format,
 | 
			
		||||
              "- `a`, `A`: floating point number, formatted as a hexadecimal number.\n"
 | 
			
		||||
              "- `s`: formatted as a string, precision indicates padding and maximum length.\n"
 | 
			
		||||
              "- `t`: emit the type of the given value.\n"
 | 
			
		||||
              "- `v`: format with (describe x)"
 | 
			
		||||
              "- `V`: format with (string x)"
 | 
			
		||||
              "- `v`: format with (describe x)\n"
 | 
			
		||||
              "- `V`: format with (string x)\n"
 | 
			
		||||
              "- `j`: format to jdn (Janet data notation).\n"
 | 
			
		||||
              "\n"
 | 
			
		||||
              "The following conversion specifiers are used for \"pretty-printing\", where the upper-case "
 | 
			
		||||
 
 | 
			
		||||
@@ -234,6 +234,7 @@ const uint8_t *janet_symbol_gen(void) {
 | 
			
		||||
    head->hash = hash;
 | 
			
		||||
    sym = (uint8_t *)(head->data);
 | 
			
		||||
    memcpy(sym, janet_vm.gensym_counter, sizeof(janet_vm.gensym_counter));
 | 
			
		||||
    sym[head->length] = 0;
 | 
			
		||||
    janet_symcache_put((const uint8_t *)sym, bucket);
 | 
			
		||||
    return (const uint8_t *)sym;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -960,6 +960,7 @@ void arc4random_buf(void *buf, size_t nbytes);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int janet_cryptorand(uint8_t *out, size_t n) {
 | 
			
		||||
#ifndef JANET_NO_CRYPTORAND
 | 
			
		||||
#ifdef JANET_WINDOWS
 | 
			
		||||
    for (size_t i = 0; i < n; i += sizeof(unsigned int)) {
 | 
			
		||||
        unsigned int v;
 | 
			
		||||
@@ -971,7 +972,10 @@ int janet_cryptorand(uint8_t *out, size_t n) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
#elif defined(JANET_LINUX) || defined(JANET_CYGWIN) || ( defined(JANET_APPLE) && !defined(MAC_OS_X_VERSION_10_7) )
 | 
			
		||||
#elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
 | 
			
		||||
    arc4random_buf(out, n);
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    /* We should be able to call getrandom on linux, but it doesn't seem
 | 
			
		||||
       to be uniformly supported on linux distros.
 | 
			
		||||
       On Mac, arc4random_buf wasn't available on until 10.7.
 | 
			
		||||
@@ -993,12 +997,10 @@ int janet_cryptorand(uint8_t *out, size_t n) {
 | 
			
		||||
    }
 | 
			
		||||
    RETRY_EINTR(rc, close(randfd));
 | 
			
		||||
    return 0;
 | 
			
		||||
#elif defined(JANET_BSD) || defined(MAC_OS_X_VERSION_10_7)
 | 
			
		||||
    arc4random_buf(out, n);
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
    (void) n;
 | 
			
		||||
    (void) out;
 | 
			
		||||
    (void) n;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -596,8 +596,7 @@ typedef enum {
 | 
			
		||||
    JANET_ASYNC_EVENT_READ = 6,
 | 
			
		||||
    JANET_ASYNC_EVENT_WRITE = 7,
 | 
			
		||||
    JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */
 | 
			
		||||
    JANET_ASYNC_EVENT_FAILED = 9, /* Used on windows for IOCP */
 | 
			
		||||
    JANET_ASYNC_EVENT_USER = 10
 | 
			
		||||
    JANET_ASYNC_EVENT_FAILED = 9 /* Used on windows for IOCP */
 | 
			
		||||
} JanetAsyncEvent;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
@@ -606,9 +605,7 @@ typedef enum {
 | 
			
		||||
    JANET_ASYNC_LISTEN_BOTH
 | 
			
		||||
} JanetAsyncMode;
 | 
			
		||||
 | 
			
		||||
/* Typedefs */
 | 
			
		||||
typedef struct JanetStream JanetStream;
 | 
			
		||||
typedef void (*JanetEVCallback)(JanetFiber *fiber, JanetAsyncEvent event);
 | 
			
		||||
 | 
			
		||||
/* Wrapper around file descriptors and HANDLEs that can be polled. */
 | 
			
		||||
struct JanetStream {
 | 
			
		||||
@@ -620,9 +617,24 @@ struct JanetStream {
 | 
			
		||||
    const void *methods; /* Methods for this stream */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void (*JanetEVCallback)(JanetFiber *fiber, JanetAsyncEvent event);
 | 
			
		||||
 | 
			
		||||
/* Start listening for events from a stream on the current root fiber. After
 | 
			
		||||
 * calling this, users should call janet_await() before returning from the
 | 
			
		||||
 * current C Function. This also will call janet_await.
 | 
			
		||||
 * mode is which events to listen for, and callback is the function pointer to
 | 
			
		||||
 * call when ever an event is sent from the event loop. state is an optional (can be NULL)
 | 
			
		||||
 * pointer to data allocated with janet_malloc. This pointer will be passed to callback as
 | 
			
		||||
 * fiber->ev_state. It will also be freed for you by the runtime when the event loop determines
 | 
			
		||||
 * it can no longer be referenced. On windows, the contents of state MUST contained an OVERLAPPED struct. */
 | 
			
		||||
JANET_API JANET_NO_RETURN void janet_async_start(JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, void *state);
 | 
			
		||||
 | 
			
		||||
/* Do not send any more events to the given callback. Call this after scheduling fiber to be resume
 | 
			
		||||
 * or canceled. */
 | 
			
		||||
JANET_API void janet_async_end(JanetFiber *fiber);
 | 
			
		||||
JANET_API void *janet_async_start(JanetFiber *fiber, JanetStream *stream,
 | 
			
		||||
                                  JanetAsyncMode mode, JanetEVCallback callback, size_t data_size);
 | 
			
		||||
 | 
			
		||||
/* Needed for windows to mark a fiber as waiting for an IOCP completion event. Noop on other platforms. */
 | 
			
		||||
JANET_API void janet_async_in_flight(JanetFiber *fiber);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -635,6 +647,7 @@ typedef int32_t JanetAtomicInt;
 | 
			
		||||
#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
 | 
			
		||||
 * nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
 | 
			
		||||
@@ -1488,22 +1501,22 @@ JANET_API void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGeneric
 | 
			
		||||
JANET_API void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value);
 | 
			
		||||
 | 
			
		||||
/* Read async from a stream */
 | 
			
		||||
JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
 | 
			
		||||
JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_readchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes);
 | 
			
		||||
#ifdef JANET_NET
 | 
			
		||||
JANET_API void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
 | 
			
		||||
JANET_API void janet_ev_recvchunk(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
 | 
			
		||||
JANET_API void janet_ev_recvfrom(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_recv(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags);
 | 
			
		||||
JANET_NO_RETURN 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);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Write async to a stream */
 | 
			
		||||
JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf);
 | 
			
		||||
JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_write_buffer(JanetStream *stream, JanetBuffer *buf);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_write_string(JanetStream *stream, JanetString str);
 | 
			
		||||
#ifdef JANET_NET
 | 
			
		||||
JANET_API void janet_ev_send_buffer(JanetStream *stream, JanetBuffer *buf, int flags);
 | 
			
		||||
JANET_API void janet_ev_send_string(JanetStream *stream, JanetString str, int flags);
 | 
			
		||||
JANET_API void janet_ev_sendto_buffer(JanetStream *stream, JanetBuffer *buf, void *dest, int flags);
 | 
			
		||||
JANET_API void janet_ev_sendto_string(JanetStream *stream, JanetString str, void *dest, int flags);
 | 
			
		||||
JANET_NO_RETURN JANET_API void janet_ev_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_NO_RETURN 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);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2127,7 +2140,8 @@ typedef enum {
 | 
			
		||||
    RULE_LINE,         /* [tag] */
 | 
			
		||||
    RULE_COLUMN,       /* [tag] */
 | 
			
		||||
    RULE_UNREF,        /* [rule, tag] */
 | 
			
		||||
    RULE_CAPTURE_NUM   /* [rule, tag] */
 | 
			
		||||
    RULE_CAPTURE_NUM,  /* [rule, tag] */
 | 
			
		||||
    RULE_SUB           /* [rule, rule] */
 | 
			
		||||
} JanetPegOpcod;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -502,10 +502,10 @@ static void kright(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++;
 | 
			
		||||
    }
 | 
			
		||||
    while (gbl_pos != gbl_len && isspace(gbl_buf[gbl_pos])) {
 | 
			
		||||
    while (gbl_pos != gbl_len && !isspace(gbl_buf[gbl_pos])) {
 | 
			
		||||
        gbl_pos++;
 | 
			
		||||
    }
 | 
			
		||||
    refresh();
 | 
			
		||||
 
 | 
			
		||||
@@ -241,6 +241,16 @@
 | 
			
		||||
  (assert (pos? (% x 4)) "generate in loop"))
 | 
			
		||||
(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
 | 
			
		||||
# ff163a5ae
 | 
			
		||||
(assert (odd? 9) "odd? 1")
 | 
			
		||||
@@ -951,4 +961,15 @@
 | 
			
		||||
# (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)
 | 
			
		||||
 
 | 
			
		||||
@@ -366,4 +366,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -263,6 +263,8 @@
 | 
			
		||||
(marshpeg '(if-not "abcdf" 123))
 | 
			
		||||
(marshpeg ~(cmt "abcdf" ,identity))
 | 
			
		||||
(marshpeg '(group "abc"))
 | 
			
		||||
(marshpeg '(sub "abcdf" "abc"))
 | 
			
		||||
(marshpeg '(* (sub 1 1)))
 | 
			
		||||
 | 
			
		||||
# Peg swallowing errors
 | 
			
		||||
# 159651117
 | 
			
		||||
@@ -660,5 +662,53 @@
 | 
			
		||||
  (peg/match '(if (not (* (constant 7) "a")) "hello") "hello")
 | 
			
		||||
  @[]) "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"
 | 
			
		||||
  @[])
 | 
			
		||||
 | 
			
		||||
(end-suite)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -198,5 +198,9 @@
 | 
			
		||||
 | 
			
		||||
(assert (= (test) '(1 ())) "issue #919")
 | 
			
		||||
 | 
			
		||||
(end-suite)
 | 
			
		||||
# Regression #1327
 | 
			
		||||
(def x "A")
 | 
			
		||||
(def x (if (= nil x) "B" x))
 | 
			
		||||
(assert (= x "A"))
 | 
			
		||||
 | 
			
		||||
(end-suite)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user