mirror of
https://github.com/janet-lang/janet
synced 2025-11-06 02:23:03 +00:00
Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cff718f37d | ||
|
|
40e9430278 | ||
|
|
62fc55fc74 | ||
|
|
80729353c8 | ||
|
|
105ba5e124 | ||
|
|
ad1b50d1f5 | ||
|
|
1905437abe | ||
|
|
87fc339c45 | ||
|
|
3af7d61d3e | ||
|
|
a45ef7a856 | ||
|
|
299998055d | ||
|
|
c9586d39ed | ||
|
|
2e9f67f4e4 | ||
|
|
e318170fea | ||
|
|
73c4289792 | ||
|
|
ea45d7ee47 | ||
|
|
6d970725e7 | ||
|
|
458c2c6d88 | ||
|
|
0cc53a8964 | ||
|
|
0bc96304a9 | ||
|
|
c75b088ff8 | ||
|
|
181f0341f5 | ||
|
|
33bb08d53b | ||
|
|
6d188f6e44 | ||
|
|
c3648331f1 | ||
|
|
a5b66029d3 | ||
|
|
49bfe80191 | ||
|
|
a5def77bfe | ||
|
|
9ecb5b4791 | ||
|
|
1cc48a370a | ||
|
|
f1ec8d1e11 | ||
|
|
55c34cd84f | ||
|
|
aca52d1e36 | ||
|
|
6f90df26a5 | ||
|
|
9d9cb378ff | ||
|
|
f92aac14aa | ||
|
|
3f27d78ab5 | ||
|
|
282d1ba22f | ||
|
|
94c19575b1 | ||
|
|
e3e485285b | ||
|
|
986e36720e | ||
|
|
74348ab6c2 | ||
|
|
8d1ad99f42 | ||
|
|
e69bbff195 | ||
|
|
c9f33bbde0 | ||
|
|
9c9f9d4fa6 | ||
|
|
2f64a6b0cb | ||
|
|
dfa78ad3c6 | ||
|
|
677ae46f0c | ||
|
|
6ada2a458f | ||
|
|
8145f3b68d | ||
|
|
48289acee6 | ||
|
|
e5a989c6f9 | ||
|
|
4c56704935 | ||
|
|
9cda44f443 | ||
|
|
431451bac2 | ||
|
|
395ca7feea | ||
|
|
5b2a402930 | ||
|
|
85129a1873 | ||
|
|
487d333024 | ||
|
|
fe7d35171f | ||
|
|
b3aed13567 | ||
|
|
a9d4d2bfa3 | ||
|
|
1ff521683f | ||
|
|
0395a03b6b | ||
|
|
7fda7709ff | ||
|
|
65a9200cff | ||
|
|
473eec26c1 | ||
|
|
9fa945ad93 | ||
|
|
a895219d2f | ||
|
|
427f7c362e | ||
|
|
73f5c41fae | ||
|
|
b4ec168401 | ||
|
|
726d35c766 | ||
|
|
6db796e10c | ||
|
|
c38d9134cd | ||
|
|
471204b163 | ||
|
|
7f23bfa66d | ||
|
|
9287b26042 | ||
|
|
e22936fbf8 | ||
|
|
04ace9fc16 | ||
|
|
8466b333fb | ||
|
|
96602612ba | ||
|
|
690b98bff9 | ||
|
|
8329131bfe | ||
|
|
9986aab326 | ||
|
|
0b105bc535 | ||
|
|
51ac9c9506 | ||
|
|
0310176696 | ||
|
|
84a7a2bc3e | ||
|
|
1e66a7e555 | ||
|
|
2bffb9d682 | ||
|
|
811125a760 | ||
|
|
0dd91082a1 | ||
|
|
c80587868e | ||
|
|
8c52dc86c7 | ||
|
|
be24592bc3 | ||
|
|
0d1a5c621d | ||
|
|
8a3eff3b65 | ||
|
|
b1050b884d | ||
|
|
181d883a1d | ||
|
|
e01b65fd3d | ||
|
|
bbd74b5ae2 | ||
|
|
d5a5c49357 | ||
|
|
a964b164a6 | ||
|
|
1aac0489d7 | ||
|
|
e474755887 | ||
|
|
bf9a60f70d | ||
|
|
a2ba0913d3 | ||
|
|
f74df41fff | ||
|
|
2a950e4ce9 | ||
|
|
f05e5f908e | ||
|
|
43139b43b1 | ||
|
|
5811b47aad | ||
|
|
54e3db4d8c | ||
|
|
7491421c31 | ||
|
|
9d0da74347 | ||
|
|
e9870b293f | ||
|
|
ab910d060b | ||
|
|
c9986936ed |
@@ -13,7 +13,7 @@ tasks:
|
||||
gmake test-install
|
||||
- meson_min: |
|
||||
cd janet
|
||||
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dtyped_array=false -Dreduced_os=true
|
||||
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dtyped_array=false -Dreduced_os=true -Dffi=false
|
||||
cd build_meson_min
|
||||
ninja
|
||||
- meson_prf: |
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,5 +1,3 @@
|
||||
*.janet linguist-language=Clojure
|
||||
|
||||
*.janet text eol=lf
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
|
||||
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -5,9 +5,14 @@ on:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
release:
|
||||
permissions:
|
||||
contents: write # for softprops/action-gh-release to create GitHub release
|
||||
name: Build release binaries
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -35,6 +40,8 @@ jobs:
|
||||
build/c/shell.c
|
||||
|
||||
release-windows:
|
||||
permissions:
|
||||
contents: write # for softprops/action-gh-release to create GitHub release
|
||||
name: Build release binaries for windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@@ -2,6 +2,9 @@ name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
test-posix:
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,7 +1,34 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.21.0 - 2022-03-21
|
||||
## Unreleased - ???
|
||||
- Add experimental `ffi/` module for interfacing with dynamic libraries and raw function pointers.
|
||||
- Allow using `&named` in function prototypes for named arguments. This is a more ergonomic
|
||||
variant of `&keys` that isn't as redundant, more self documenting, and allows extension to
|
||||
things like default arguments.
|
||||
- Add `delay` macro for lazy evaluate-and-save thunks.
|
||||
- Remove pthread.h from janet.h for easier includes.
|
||||
- Add `debugger` - an easy to use debugger function that just takes a fiber.
|
||||
- `dofile` will now start a debugger on errors if the environment it is passed has `:debug` set.
|
||||
- Add `debugger-on-status` function, which can be passed to `run-context` to start a debugger on
|
||||
abnormal fiber signals.
|
||||
- Allow running scripts with the `-d` flag to use the built-in debugger on errors and breakpoints.
|
||||
- Add mutexes (locks) and reader-writer locks to ev module for thread coordination.
|
||||
- Add `parse-all` as a generalization of the `parse` function.
|
||||
- Add `os/cpu-count` to get the number of available processors on a machine
|
||||
|
||||
## 1.22.0 - 2022-05-09
|
||||
- Prohibit negative size argument to `table/new`.
|
||||
- Add `module/value`.
|
||||
- Remove `file/popen`. Use `os/spawn` with the `:pipe` options instead.
|
||||
- Fix bug in peg `thru` and `to` combinators.
|
||||
- Fix printing issue in `doc` macro.
|
||||
- Numerous updates to function docstrings
|
||||
- Add `defdyn` aliases for various dynamic bindings used in core.
|
||||
- Install `janet.h` symlink to make Janet native libraries and applications
|
||||
easier to build without `jpm`.
|
||||
|
||||
## 1.21.2 - 2022-04-01
|
||||
- C functions `janet_dobytes` and `janet_dostring` will now enter the event loop if it is enabled.
|
||||
- Fix hashing regression - hash of negative 0 must be the same as positive 0 since they are equal.
|
||||
- The `flycheck` function no longer pollutes the module/cache
|
||||
|
||||
22
Makefile
22
Makefile
@@ -58,6 +58,7 @@ UNAME:=$(shell uname -s)
|
||||
ifeq ($(UNAME), Darwin)
|
||||
CLIBS:=$(CLIBS) -ldl
|
||||
SONAME_SETTER:=-Wl,-install_name,
|
||||
JANET_LIBRARY=build/libjanet.dylib
|
||||
LDCONFIG:=true
|
||||
else ifeq ($(UNAME), Linux)
|
||||
CLIBS:=$(CLIBS) -lrt -ldl
|
||||
@@ -107,6 +108,7 @@ JANET_CORE_SOURCES=src/core/abstract.c \
|
||||
src/core/debug.c \
|
||||
src/core/emit.c \
|
||||
src/core/ev.c \
|
||||
src/core/ffi.c \
|
||||
src/core/fiber.c \
|
||||
src/core/gc.c \
|
||||
src/core/inttypes.c \
|
||||
@@ -165,7 +167,11 @@ build/c/janet.c: build/janet_boot src/boot/boot.janet
|
||||
##### Amalgamation #####
|
||||
########################
|
||||
|
||||
SONAME=libjanet.so.1.20
|
||||
ifeq ($(UNAME), Darwin)
|
||||
SONAME=libjanet.1.22.dylib
|
||||
else
|
||||
SONAME=libjanet.so.1.22
|
||||
endif
|
||||
|
||||
build/c/shell.c: src/mainclient/shell.c
|
||||
cp $< $@
|
||||
@@ -277,12 +283,19 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
|
||||
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
||||
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
ln -sf '$(DESTDIR)$(INCLUDEDIR)/janet/janet.h' '$(DESTDIR)$(INCLUDEDIR)/janet.h'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
||||
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')'
|
||||
if test $(UNAME) = Darwin ; then \
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib' ; \
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.dylib' ; \
|
||||
ln -sf libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||
else \
|
||||
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')' ; \
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so' ; \
|
||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
|
||||
fi
|
||||
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
|
||||
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so'
|
||||
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME)
|
||||
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
|
||||
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
|
||||
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
||||
@@ -304,6 +317,7 @@ install-jpm-git: $(JANET_TARGET)
|
||||
uninstall:
|
||||
-rm '$(DESTDIR)$(BINDIR)/janet'
|
||||
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet.h'
|
||||
-rm -rf '$(DESTDIR)$(LIBDIR)'/libjanet.*
|
||||
-rm '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||
-rm '$(DESTDIR)$(JANET_MANPATH)/janet.1'
|
||||
|
||||
10
README.md
10
README.md
@@ -1,7 +1,7 @@
|
||||
[](https://gitter.im/janet-language/community)
|
||||
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/freebsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/openbsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/master/freebsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/master/openbsd.yml?)
|
||||
[](https://github.com/janet-lang/janet/actions/workflows/test.yml)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
||||
@@ -89,6 +89,8 @@ cd somewhere/my/projects/janet
|
||||
make
|
||||
make test
|
||||
make repl
|
||||
make install
|
||||
make install-jpm-git
|
||||
```
|
||||
|
||||
Find out more about the available make targets by running `make help`.
|
||||
@@ -103,6 +105,8 @@ cd somewhere/my/projects/janet
|
||||
make CC=gcc-x86
|
||||
make test
|
||||
make repl
|
||||
make install
|
||||
make install-jpm-git
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
@@ -116,6 +120,8 @@ cd somewhere/my/projects/janet
|
||||
gmake
|
||||
gmake test
|
||||
gmake repl
|
||||
gmake install
|
||||
gmake install-jpm-git
|
||||
```
|
||||
|
||||
### NetBSD
|
||||
|
||||
45
examples/evlocks.janet
Normal file
45
examples/evlocks.janet
Normal file
@@ -0,0 +1,45 @@
|
||||
(defn sleep
|
||||
"Sleep the entire thread, not just a single fiber."
|
||||
[n]
|
||||
(os/sleep (* 0.1 n)))
|
||||
|
||||
(defn work [lock n]
|
||||
(ev/acquire-lock lock)
|
||||
(print "working " n "...")
|
||||
(sleep n)
|
||||
(print "done working...")
|
||||
(ev/release-lock lock))
|
||||
|
||||
(defn reader
|
||||
[rwlock n]
|
||||
(ev/acquire-rlock rwlock)
|
||||
(print "reading " n "...")
|
||||
(sleep n)
|
||||
(print "done reading " n "...")
|
||||
(ev/release-rlock rwlock))
|
||||
|
||||
(defn writer
|
||||
[rwlock n]
|
||||
(ev/acquire-wlock rwlock)
|
||||
(print "writing " n "...")
|
||||
(sleep n)
|
||||
(print "done writing...")
|
||||
(ev/release-wlock rwlock))
|
||||
|
||||
(defn test-lock
|
||||
[]
|
||||
(def lock (ev/lock))
|
||||
(for i 3 7
|
||||
(ev/spawn-thread
|
||||
(work lock i))))
|
||||
|
||||
(defn test-rwlock
|
||||
[]
|
||||
(def rwlock (ev/rwlock))
|
||||
(for i 0 20
|
||||
(if (> 0.1 (math/random))
|
||||
(ev/spawn-thread (writer rwlock i))
|
||||
(ev/spawn-thread (reader rwlock i)))))
|
||||
|
||||
(test-rwlock)
|
||||
(test-lock)
|
||||
56
examples/ffi/gtk.janet
Normal file
56
examples/ffi/gtk.janet
Normal file
@@ -0,0 +1,56 @@
|
||||
# :lazy true needed for jpm quickbin
|
||||
# lazily loads library on first function use
|
||||
# so the `main` function
|
||||
# can be marshalled.
|
||||
(ffi/context "/usr/lib/libgtk-3.so" :lazy true)
|
||||
|
||||
(ffi/defbind
|
||||
gtk-application-new :ptr
|
||||
"Add docstrings as needed."
|
||||
[a :ptr b :uint])
|
||||
|
||||
(ffi/defbind
|
||||
g-signal-connect-data :ulong
|
||||
[a :ptr b :ptr c :ptr d :ptr e :ptr f :int])
|
||||
|
||||
(ffi/defbind
|
||||
g-application-run :int
|
||||
[a :ptr b :int c :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-application-window-new :ptr
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-button-new-with-label :ptr
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-container-add :void
|
||||
[a :ptr b :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-widget-show-all :void
|
||||
[a :ptr])
|
||||
|
||||
(ffi/defbind
|
||||
gtk-button-set-label :void
|
||||
[a :ptr b :ptr])
|
||||
|
||||
(def cb (delay (ffi/trampoline :default)))
|
||||
|
||||
(defn on-active
|
||||
[app]
|
||||
(def window (gtk-application-window-new app))
|
||||
(def btn (gtk-button-new-with-label "Click Me!"))
|
||||
(g-signal-connect-data btn "clicked" (cb)
|
||||
(fn [btn] (gtk-button-set-label btn "Hello World"))
|
||||
nil 1)
|
||||
(gtk-container-add window btn)
|
||||
(gtk-widget-show-all window))
|
||||
|
||||
(defn main
|
||||
[&]
|
||||
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
|
||||
(g-signal-connect-data app "activate" (cb) on-active nil 1)
|
||||
(g-application-run app 0 nil))
|
||||
87
examples/ffi/so.c
Normal file
87
examples/ffi/so.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
int int_fn(int a, int b) {
|
||||
return (a << 2) + b;
|
||||
}
|
||||
|
||||
double my_fn(int64_t a, int64_t b, const char *x) {
|
||||
return (double)(a + b) + 0.5 + strlen(x);
|
||||
}
|
||||
|
||||
double double_fn(double x, double y, double z) {
|
||||
return (x + y) * z * 3;
|
||||
}
|
||||
|
||||
double double_many(double x, double y, double z, double w, double a, double b) {
|
||||
return x + y + z + w + a + b;
|
||||
}
|
||||
|
||||
double double_lots(
|
||||
double a,
|
||||
double b,
|
||||
double c,
|
||||
double d,
|
||||
double e,
|
||||
double f,
|
||||
double g,
|
||||
double h,
|
||||
double i,
|
||||
double j) {
|
||||
return i + j;
|
||||
}
|
||||
|
||||
double float_fn(float x, float y, float z) {
|
||||
return (x + y) * z;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} intint;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} intintint;
|
||||
|
||||
int intint_fn(double x, intint ii) {
|
||||
printf("double: %g\n", x);
|
||||
return ii.a + ii.b;
|
||||
}
|
||||
|
||||
int intintint_fn(double x, intintint iii) {
|
||||
printf("double: %g\n", x);
|
||||
return iii.a + iii.b + iii.c;
|
||||
}
|
||||
|
||||
intint return_struct(int i) {
|
||||
intint ret;
|
||||
ret.a = i;
|
||||
ret.b = i * i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int64_t a;
|
||||
int64_t b;
|
||||
int64_t c;
|
||||
} big;
|
||||
|
||||
big struct_big(int i, double d) {
|
||||
big ret;
|
||||
ret.a = i;
|
||||
ret.b = (int64_t) d;
|
||||
ret.c = ret.a + ret.b + 1000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void void_fn(void) {
|
||||
printf("void fn ran\n");
|
||||
}
|
||||
|
||||
void void_ret_fn(int x) {
|
||||
printf("void fn ran: %d\n", x);
|
||||
}
|
||||
128
examples/ffi/test.janet
Normal file
128
examples/ffi/test.janet
Normal file
@@ -0,0 +1,128 @@
|
||||
(def ffi/loc "ffitest/so.so")
|
||||
(def ffi/source-loc "ffitest/so.c")
|
||||
|
||||
(os/execute ["cc" ffi/source-loc "-shared" "-o" ffi/loc] :px)
|
||||
(def module (ffi/native ffi/loc))
|
||||
|
||||
(def int-fn-sig (ffi/signature :default :int :int :int))
|
||||
(def int-fn-pointer (ffi/lookup module "int_fn"))
|
||||
(defn int-fn
|
||||
[x y]
|
||||
(ffi/call int-fn-pointer int-fn-sig x y))
|
||||
|
||||
(def double-fn-sig (ffi/signature :default :double :double :double :double))
|
||||
(def double-fn-pointer (ffi/lookup module "double_fn"))
|
||||
(defn double-fn
|
||||
[x y z]
|
||||
(ffi/call double-fn-pointer double-fn-sig x y z))
|
||||
|
||||
(def double-many-sig (ffi/signature :default :double :double :double :double :double :double :double))
|
||||
(def double-many-pointer (ffi/lookup module "double_many"))
|
||||
(defn double-many
|
||||
[x y z w a b]
|
||||
(ffi/call double-many-pointer double-many-sig x y z w a b))
|
||||
|
||||
(def double-lots-sig (ffi/signature :default :double
|
||||
:double :double :double :double :double
|
||||
:double :double :double :double :double))
|
||||
(def double-lots-pointer (ffi/lookup module "double_lots"))
|
||||
(defn double-lots
|
||||
[a b c d e f g h i j]
|
||||
(ffi/call double-lots-pointer double-lots-sig a b c d e f g h i j))
|
||||
|
||||
(def float-fn-sig (ffi/signature :default :double :float :float :float))
|
||||
(def float-fn-pointer (ffi/lookup module "float_fn"))
|
||||
(defn float-fn
|
||||
[x y z]
|
||||
(ffi/call float-fn-pointer float-fn-sig x y z))
|
||||
|
||||
(def intint-fn-sig (ffi/signature :default :int :double [:int :int]))
|
||||
(def intint-fn-pointer (ffi/lookup module "intint_fn"))
|
||||
(defn intint-fn
|
||||
[x ii]
|
||||
(ffi/call intint-fn-pointer intint-fn-sig x ii))
|
||||
|
||||
(def return-struct-sig (ffi/signature :default [:int :int] :int))
|
||||
(def return-struct-pointer (ffi/lookup module "return_struct"))
|
||||
(defn return-struct-fn
|
||||
[i]
|
||||
(ffi/call return-struct-pointer return-struct-sig i))
|
||||
|
||||
(def intintint (ffi/struct :int :int :int))
|
||||
(def intintint-fn-sig (ffi/signature :default :int :double intintint))
|
||||
(def intintint-fn-pointer (ffi/lookup module "intintint_fn"))
|
||||
(defn intintint-fn
|
||||
[x iii]
|
||||
(ffi/call intintint-fn-pointer intintint-fn-sig x iii))
|
||||
|
||||
(def big (ffi/struct :s64 :s64 :s64))
|
||||
(def struct-big-fn-sig (ffi/signature :default big :int :double))
|
||||
(def struct-big-fn-pointer (ffi/lookup module "struct_big"))
|
||||
(defn struct-big-fn
|
||||
[i d]
|
||||
(ffi/call struct-big-fn-pointer struct-big-fn-sig i d))
|
||||
|
||||
(def void-fn-pointer (ffi/lookup module "void_fn"))
|
||||
(def void-fn-sig (ffi/signature :default :void))
|
||||
(defn void-fn
|
||||
[]
|
||||
(ffi/call void-fn-pointer void-fn-sig))
|
||||
|
||||
#
|
||||
# Call functions
|
||||
#
|
||||
|
||||
(pp (void-fn))
|
||||
(pp (int-fn 10 20))
|
||||
(pp (double-fn 1.5 2.5 3.5))
|
||||
(pp (double-many 1 2 3 4 5 6))
|
||||
(pp (double-lots 1 2 3 4 5 6 7 8 9 10))
|
||||
(pp (float-fn 8 4 17))
|
||||
(pp (intint-fn 123.456 [10 20]))
|
||||
(pp (intintint-fn 123.456 [10 20 30]))
|
||||
(pp (return-struct-fn 42))
|
||||
(pp (struct-big-fn 11 99.5))
|
||||
|
||||
(assert (= 60 (int-fn 10 20)))
|
||||
(assert (= 42 (double-fn 1.5 2.5 3.5)))
|
||||
(assert (= 21 (double-many 1 2 3 4 5 6)))
|
||||
(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10)))
|
||||
(assert (= 204 (float-fn 8 4 17)))
|
||||
|
||||
#
|
||||
# Struct reading and writing
|
||||
#
|
||||
|
||||
(defn check-round-trip
|
||||
[t value]
|
||||
(def buf (ffi/write t value))
|
||||
(def same-value (ffi/read t buf))
|
||||
(assert (deep= value same-value)
|
||||
(string/format "round trip %j (got %j)" value same-value)))
|
||||
|
||||
(check-round-trip :bool true)
|
||||
(check-round-trip :bool false)
|
||||
(check-round-trip :void nil)
|
||||
(check-round-trip :void nil)
|
||||
(check-round-trip :s8 10)
|
||||
(check-round-trip :s8 0)
|
||||
(check-round-trip :s8 -10)
|
||||
(check-round-trip :u8 10)
|
||||
(check-round-trip :u8 0)
|
||||
(check-round-trip :s16 10)
|
||||
(check-round-trip :s16 0)
|
||||
(check-round-trip :s16 -12312)
|
||||
(check-round-trip :u16 10)
|
||||
(check-round-trip :u16 0)
|
||||
(check-round-trip :u32 0)
|
||||
(check-round-trip :u32 10)
|
||||
(check-round-trip :u32 0xFFFF7777)
|
||||
(check-round-trip :s32 0x7FFF7777)
|
||||
(check-round-trip :s32 0)
|
||||
(check-round-trip :s32 -1234567)
|
||||
|
||||
(def s (ffi/struct :s8 :s8 :s8 :float))
|
||||
(check-round-trip s [1 3 5 123.5])
|
||||
(check-round-trip s [-1 -3 -5 -123.5])
|
||||
|
||||
(print "Done.")
|
||||
10
meson.build
10
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.20.1')
|
||||
version : '1.22.1')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
@@ -76,6 +76,7 @@ conf.set('JANET_SIMPLE_GETLINE', get_option('simple_getline'))
|
||||
conf.set('JANET_EV_NO_EPOLL', not get_option('epoll'))
|
||||
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'))
|
||||
if get_option('os_name') != ''
|
||||
conf.set('JANET_OS_NAME', get_option('os_name'))
|
||||
endif
|
||||
@@ -116,6 +117,7 @@ core_src = [
|
||||
'src/core/debug.c',
|
||||
'src/core/emit.c',
|
||||
'src/core/ev.c',
|
||||
'src/core/ffi.c',
|
||||
'src/core/fiber.c',
|
||||
'src/core/gc.c',
|
||||
'src/core/inttypes.c',
|
||||
@@ -263,3 +265,9 @@ patched_janet = custom_target('patched-janeth',
|
||||
build_by_default : true,
|
||||
output : ['janet.h'],
|
||||
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@'])
|
||||
|
||||
# Create a version of the janet.h header that matches what jpm often expects
|
||||
if meson.version().version_compare('>=0.61')
|
||||
install_symlink('janet.h', pointing_to: 'janet/janet.h', install_dir: get_option('includedir'))
|
||||
endif
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ option('simple_getline', type : 'boolean', value : false)
|
||||
option('epoll', type : 'boolean', value : false)
|
||||
option('kqueue', type : 'boolean', value : false)
|
||||
option('interpreter_interrupt', type : 'boolean', value : false)
|
||||
option('ffi', type : 'boolean', value : true)
|
||||
|
||||
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
|
||||
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
|
||||
|
||||
1026
src/boot/boot.janet
1026
src/boot/boot.janet
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,10 @@
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 20
|
||||
#define JANET_VERSION_MINOR 22
|
||||
#define JANET_VERSION_PATCH 1
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.20.1"
|
||||
#define JANET_VERSION_EXTRA "-dev"
|
||||
#define JANET_VERSION "1.22.1-dev"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#include "gc.h"
|
||||
#include "state.h"
|
||||
#ifdef JANET_EV
|
||||
@@ -85,6 +86,14 @@ void *janet_abstract_threaded(const JanetAbstractType *atype, size_t size) {
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
|
||||
void janet_os_mutex_size(void) {
|
||||
return sizeof(CRITICAL_SECTION);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_size(void) {
|
||||
return sizeof(SRWLock);
|
||||
}
|
||||
|
||||
static int32_t janet_incref(JanetAbstractHead *ab) {
|
||||
return InterlockedIncrement(&ab->gc.data.refcount);
|
||||
}
|
||||
@@ -106,11 +115,45 @@ void janet_os_mutex_lock(JanetOSMutex *mutex) {
|
||||
}
|
||||
|
||||
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
|
||||
/* error handling? May want to keep counter */
|
||||
LeaveCriticalSection((CRITICAL_SECTION *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
|
||||
InitializeSRWLock((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
|
||||
/* no op? */
|
||||
(void) rwlock;
|
||||
}
|
||||
|
||||
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
|
||||
AcquireSRWLockShared((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
|
||||
AcquireSRWLockExclusive((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
|
||||
ReleaseSRWLockShared((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
|
||||
ReleaseSRWLockExclusive((PSRWLOCK) rwlock);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
size_t janet_os_mutex_size(void) {
|
||||
return sizeof(pthread_mutex_t);
|
||||
}
|
||||
|
||||
size_t janet_os_rwlock_size(void) {
|
||||
return sizeof(pthread_rwlock_t);
|
||||
}
|
||||
|
||||
static int32_t janet_incref(JanetAbstractHead *ab) {
|
||||
return __atomic_add_fetch(&ab->gc.data.refcount, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
@@ -120,19 +163,47 @@ static int32_t janet_decref(JanetAbstractHead *ab) {
|
||||
}
|
||||
|
||||
void janet_os_mutex_init(JanetOSMutex *mutex) {
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init((pthread_mutex_t *) mutex, &attr);
|
||||
}
|
||||
|
||||
void janet_os_mutex_deinit(JanetOSMutex *mutex) {
|
||||
pthread_mutex_destroy(mutex);
|
||||
pthread_mutex_destroy((pthread_mutex_t *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_lock(JanetOSMutex *mutex) {
|
||||
pthread_mutex_lock(mutex);
|
||||
pthread_mutex_lock((pthread_mutex_t *) mutex);
|
||||
}
|
||||
|
||||
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
|
||||
pthread_mutex_unlock(mutex);
|
||||
int ret = pthread_mutex_unlock((pthread_mutex_t *) mutex);
|
||||
if (ret) janet_panic("cannot release lock");
|
||||
}
|
||||
|
||||
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_init((pthread_rwlock_t *) rwlock, NULL);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_destroy((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -125,7 +125,7 @@ Janet janet_array_peek(JanetArray *array) {
|
||||
JANET_CORE_FN(cfun_array_new,
|
||||
"(array/new capacity)",
|
||||
"Creates a new empty array with a pre-allocated capacity. The same as "
|
||||
"(array) but can be more efficient if the maximum size of an array is known.") {
|
||||
"`(array)` but can be more efficient if the maximum size of an array is known.") {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
JanetArray *array = janet_array(cap);
|
||||
@@ -136,7 +136,7 @@ JANET_CORE_FN(cfun_array_new_filled,
|
||||
"(array/new-filled count &opt value)",
|
||||
"Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getinteger(argv, 0);
|
||||
int32_t count = janet_getnat(argv, 0);
|
||||
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
|
||||
JanetArray *array = janet_array(count);
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
@@ -194,7 +194,7 @@ JANET_CORE_FN(cfun_array_push,
|
||||
JANET_CORE_FN(cfun_array_ensure,
|
||||
"(array/ensure arr capacity growth)",
|
||||
"Ensures that the memory backing the array is large enough for `capacity` "
|
||||
"items at the given rate of growth. Capacity and growth must be integers. "
|
||||
"items at the given rate of growth. `capacity` and `growth` must be integers. "
|
||||
"If the backing capacity is already enough, then this function does nothing. "
|
||||
"Otherwise, the backing memory will be reallocated so that there is enough space.") {
|
||||
janet_fixarity(argc, 3);
|
||||
|
||||
@@ -553,6 +553,10 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
||||
x = janet_get1(s, janet_ckeywordv("vararg"));
|
||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
|
||||
|
||||
/* Check structarg */
|
||||
x = janet_get1(s, janet_ckeywordv("structarg"));
|
||||
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
|
||||
|
||||
/* Check source */
|
||||
x = janet_get1(s, janet_ckeywordv("source"));
|
||||
if (janet_checktype(x, JANET_STRING)) def->source = janet_unwrap_string(x);
|
||||
@@ -884,6 +888,10 @@ static Janet janet_disasm_vararg(JanetFuncDef *def) {
|
||||
return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_VARARG);
|
||||
}
|
||||
|
||||
static Janet janet_disasm_structarg(JanetFuncDef *def) {
|
||||
return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_STRUCTARG);
|
||||
}
|
||||
|
||||
static Janet janet_disasm_constants(JanetFuncDef *def) {
|
||||
JanetArray *constants = janet_array(def->constants_length);
|
||||
for (int32_t i = 0; i < def->constants_length; i++) {
|
||||
@@ -933,6 +941,7 @@ Janet janet_disasm(JanetFuncDef *def) {
|
||||
janet_table_put(ret, janet_ckeywordv("bytecode"), janet_disasm_bytecode(def));
|
||||
janet_table_put(ret, janet_ckeywordv("source"), janet_disasm_source(def));
|
||||
janet_table_put(ret, janet_ckeywordv("vararg"), janet_disasm_vararg(def));
|
||||
janet_table_put(ret, janet_ckeywordv("structarg"), janet_disasm_structarg(def));
|
||||
janet_table_put(ret, janet_ckeywordv("name"), janet_disasm_name(def));
|
||||
janet_table_put(ret, janet_ckeywordv("slotcount"), janet_disasm_slotcount(def));
|
||||
janet_table_put(ret, janet_ckeywordv("constants"), janet_disasm_constants(def));
|
||||
@@ -986,6 +995,7 @@ JANET_CORE_FN(cfun_disasm,
|
||||
if (!janet_cstrcmp(kw, "source")) return janet_disasm_source(f->def);
|
||||
if (!janet_cstrcmp(kw, "name")) return janet_disasm_name(f->def);
|
||||
if (!janet_cstrcmp(kw, "vararg")) return janet_disasm_vararg(f->def);
|
||||
if (!janet_cstrcmp(kw, "structarg")) return janet_disasm_structarg(f->def);
|
||||
if (!janet_cstrcmp(kw, "slotcount")) return janet_disasm_slotcount(f->def);
|
||||
if (!janet_cstrcmp(kw, "constants")) return janet_disasm_constants(f->def);
|
||||
if (!janet_cstrcmp(kw, "sourcemap")) return janet_disasm_sourcemap(f->def);
|
||||
|
||||
@@ -164,7 +164,7 @@ void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_new,
|
||||
"(buffer/new capacity)",
|
||||
"Creates a new, empty buffer with enough backing memory for capacity bytes. "
|
||||
"Creates a new, empty buffer with enough backing memory for `capacity` bytes. "
|
||||
"Returns a new buffer of length 0.") {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
@@ -174,16 +174,17 @@ JANET_CORE_FN(cfun_buffer_new,
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_new_filled,
|
||||
"(buffer/new-filled count &opt byte)",
|
||||
"Creates a new buffer of length count filled with byte. By default, byte is 0. "
|
||||
"Creates a new buffer of length `count` filled with `byte`. By default, `byte` is 0. "
|
||||
"Returns the new buffer.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t count = janet_getinteger(argv, 0);
|
||||
if (count < 0) count = 0;
|
||||
int32_t byte = 0;
|
||||
if (argc == 2) {
|
||||
byte = janet_getinteger(argv, 1) & 0xFF;
|
||||
}
|
||||
JanetBuffer *buffer = janet_buffer(count);
|
||||
if (buffer->data)
|
||||
if (buffer->data && count > 0)
|
||||
memset(buffer->data, byte, count);
|
||||
buffer->count = count;
|
||||
return janet_wrap_buffer(buffer);
|
||||
@@ -312,7 +313,7 @@ JANET_CORE_FN(cfun_buffer_clear,
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_popn,
|
||||
"(buffer/popn buffer n)",
|
||||
"Removes the last n bytes from the buffer. Returns the modified buffer.") {
|
||||
"Removes the last `n` bytes from the buffer. Returns the modified buffer.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetBuffer *buffer = janet_getbuffer(argv, 0);
|
||||
int32_t n = janet_getinteger(argv, 1);
|
||||
@@ -327,9 +328,9 @@ JANET_CORE_FN(cfun_buffer_popn,
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_slice,
|
||||
"(buffer/slice bytes &opt start end)",
|
||||
"Takes a slice of a byte sequence from start to end. The range is half open, "
|
||||
"Takes a slice of a byte sequence from `start` to `end`. The range is half open, "
|
||||
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
|
||||
"end of the array. By default, start is 0 and end is the length of the buffer. "
|
||||
"end of the array. By default, `start` is 0 and `end` is the length of the buffer. "
|
||||
"Returns a new buffer.") {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
@@ -399,9 +400,9 @@ JANET_CORE_FN(cfun_buffer_bittoggle,
|
||||
|
||||
JANET_CORE_FN(cfun_buffer_blit,
|
||||
"(buffer/blit dest src &opt dest-start src-start src-end)",
|
||||
"Insert the contents of src into dest. Can optionally take indices that "
|
||||
"indicate which part of src to copy into which part of dest. Indices can be "
|
||||
"negative to index from the end of src or dest. Returns dest.") {
|
||||
"Insert the contents of `src` into `dest`. Can optionally take indices that "
|
||||
"indicate which part of `src` to copy into which part of `dest`. Indices can be "
|
||||
"negative in order to index from the end of `src` or `dest`. Returns `dest`.") {
|
||||
janet_arity(argc, 2, 5);
|
||||
JanetBuffer *dest = janet_getbuffer(argv, 0);
|
||||
JanetByteView src = janet_getbytes(argv, 1);
|
||||
|
||||
@@ -260,11 +260,27 @@ int32_t janet_getinteger(const Janet *argv, int32_t n) {
|
||||
}
|
||||
|
||||
int64_t janet_getinteger64(const Janet *argv, int32_t n) {
|
||||
#ifdef JANET_INTTYPES
|
||||
return janet_unwrap_s64(argv[n]);
|
||||
#else
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint64(x)) {
|
||||
janet_panicf("bad slot #%d, expected 64 bit signed integer, got %v", n, x);
|
||||
}
|
||||
return (int64_t) janet_unwrap_number(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t janet_getuinteger64(const Janet *argv, int32_t n) {
|
||||
#ifdef JANET_INTTYPES
|
||||
return janet_unwrap_u64(argv[n]);
|
||||
#else
|
||||
Janet x = argv[n];
|
||||
if (!janet_checkint64(x)) {
|
||||
janet_panicf("bad slot #%d, expected 64 bit unsigned integer, got %v", n, x);
|
||||
}
|
||||
return (uint64_t) janet_unwrap_number(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t janet_getsize(const Janet *argv, int32_t n) {
|
||||
|
||||
@@ -42,51 +42,6 @@ extern size_t janet_core_image_size;
|
||||
#define JDOC(x) NULL
|
||||
#endif
|
||||
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||
* with native code. */
|
||||
#if defined(JANET_NO_DYNAMIC_MODULES)
|
||||
typedef int Clib;
|
||||
#define load_clib(name) ((void) name, 0)
|
||||
#define symbol_clib(lib, sym) ((void) lib, (void) sym, NULL)
|
||||
#define error_clib() "dynamic libraries not supported"
|
||||
#elif defined(JANET_WINDOWS)
|
||||
#include <windows.h>
|
||||
typedef HINSTANCE Clib;
|
||||
#define load_clib(name) LoadLibrary((name))
|
||||
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
|
||||
static char error_clib_buf[256];
|
||||
static char *error_clib(void) {
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
error_clib_buf, sizeof(error_clib_buf), NULL);
|
||||
error_clib_buf[strlen(error_clib_buf) - 1] = '\0';
|
||||
return error_clib_buf;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
typedef void *Clib;
|
||||
#define load_clib(name) dlopen((name), RTLD_NOW)
|
||||
#define symbol_clib(lib, sym) dlsym((lib), (sym))
|
||||
#define error_clib() dlerror()
|
||||
#endif
|
||||
|
||||
static char *get_processed_name(const char *name) {
|
||||
if (name[0] == '.') return (char *) name;
|
||||
const char *c;
|
||||
for (c = name; *c; c++) {
|
||||
if (*c == '/') return (char *) name;
|
||||
}
|
||||
size_t l = (size_t)(c - name);
|
||||
char *ret = janet_malloc(l + 3);
|
||||
if (NULL == ret) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
ret[0] = '.';
|
||||
ret[1] = '/';
|
||||
memcpy(ret + 2, name, l + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JanetModule janet_native(const char *name, const uint8_t **error) {
|
||||
char *processed_name = get_processed_name(name);
|
||||
Clib lib = load_clib(processed_name);
|
||||
@@ -1016,6 +971,9 @@ static void janet_load_libs(JanetTable *env) {
|
||||
#ifdef JANET_NET
|
||||
janet_lib_net(env);
|
||||
#endif
|
||||
#ifdef JANET_FFI
|
||||
janet_lib_ffi(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
|
||||
124
src/core/ev.c
124
src/core/ev.c
@@ -79,7 +79,11 @@ typedef struct {
|
||||
int32_t limit;
|
||||
int closed;
|
||||
int is_threaded;
|
||||
JanetOSMutex lock;
|
||||
#ifdef JANET_WINDOWS
|
||||
CRITICAL_SECTION lock;
|
||||
#else
|
||||
pthread_mutex_t lock;
|
||||
#endif
|
||||
} JanetChannel;
|
||||
|
||||
typedef struct {
|
||||
@@ -643,7 +647,7 @@ static void janet_chan_init(JanetChannel *chan, int32_t limit, int threaded) {
|
||||
janet_q_init(&chan->items);
|
||||
janet_q_init(&chan->read_pending);
|
||||
janet_q_init(&chan->write_pending);
|
||||
janet_os_mutex_init(&chan->lock);
|
||||
janet_os_mutex_init((JanetOSMutex *) &chan->lock);
|
||||
}
|
||||
|
||||
static void janet_chan_deinit(JanetChannel *chan) {
|
||||
@@ -656,17 +660,17 @@ static void janet_chan_deinit(JanetChannel *chan) {
|
||||
}
|
||||
}
|
||||
janet_q_deinit(&chan->items);
|
||||
janet_os_mutex_deinit(&chan->lock);
|
||||
janet_os_mutex_deinit((JanetOSMutex *) &chan->lock);
|
||||
}
|
||||
|
||||
static void janet_chan_lock(JanetChannel *chan) {
|
||||
if (!janet_chan_is_threaded(chan)) return;
|
||||
janet_os_mutex_lock(&chan->lock);
|
||||
janet_os_mutex_lock((JanetOSMutex *) &chan->lock);
|
||||
}
|
||||
|
||||
static void janet_chan_unlock(JanetChannel *chan) {
|
||||
if (!janet_chan_is_threaded(chan)) return;
|
||||
janet_os_mutex_unlock(&chan->lock);
|
||||
janet_os_mutex_unlock((JanetOSMutex *) &chan->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3013,6 +3017,106 @@ JANET_CORE_FN(janet_cfun_stream_write,
|
||||
janet_await();
|
||||
}
|
||||
|
||||
static int mutexgc(void *p, size_t size) {
|
||||
(void) size;
|
||||
janet_os_mutex_deinit(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const JanetAbstractType janet_mutex_type = {
|
||||
"core/lock",
|
||||
mutexgc,
|
||||
JANET_ATEND_GC
|
||||
};
|
||||
|
||||
JANET_CORE_FN(janet_cfun_mutex,
|
||||
"(ev/lock)",
|
||||
"Create a new lock to coordinate threads.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
void *mutex = janet_abstract_threaded(&janet_mutex_type, janet_os_mutex_size());
|
||||
janet_os_mutex_init(mutex);
|
||||
return janet_wrap_abstract(mutex);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_mutex_acquire,
|
||||
"(ev/acquire-lock lock)",
|
||||
"Acquire a lock such that this operating system thread is the only thread with access to this resource."
|
||||
" This will block this entire thread until the lock becomes available, and will not yield to other fibers "
|
||||
"on this system thread.") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *mutex = janet_getabstract(argv, 0, &janet_mutex_type);
|
||||
janet_os_mutex_lock(mutex);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_mutex_release,
|
||||
"(ev/release-lock lock)",
|
||||
"Release a lock such that other threads may acquire it.") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *mutex = janet_getabstract(argv, 0, &janet_mutex_type);
|
||||
janet_os_mutex_unlock(mutex);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int rwlockgc(void *p, size_t size) {
|
||||
(void) size;
|
||||
janet_os_rwlock_deinit(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const JanetAbstractType janet_rwlock_type = {
|
||||
"core/rwlock",
|
||||
rwlockgc,
|
||||
JANET_ATEND_GC
|
||||
};
|
||||
|
||||
JANET_CORE_FN(janet_cfun_rwlock,
|
||||
"(ev/rwlock)",
|
||||
"Create a new read-write lock to coordinate threads.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
void *rwlock = janet_abstract_threaded(&janet_rwlock_type, janet_os_rwlock_size());
|
||||
janet_os_rwlock_init(rwlock);
|
||||
return janet_wrap_abstract(rwlock);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_rwlock_read_lock,
|
||||
"(ev/acquire-rlock rwlock)",
|
||||
"Acquire a read lock an a read-write lock.") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *rwlock = janet_getabstract(argv, 0, &janet_rwlock_type);
|
||||
janet_os_rwlock_rlock(rwlock);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_rwlock_write_lock,
|
||||
"(ev/acquire-wlock rwlock)",
|
||||
"Acquire a write lock on a read-write lock.") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *rwlock = janet_getabstract(argv, 0, &janet_rwlock_type);
|
||||
janet_os_rwlock_wlock(rwlock);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_rwlock_read_release,
|
||||
"(ev/release-rlock rwlock)",
|
||||
"Release a read lock on a read-write lock") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *rwlock = janet_getabstract(argv, 0, &janet_rwlock_type);
|
||||
janet_os_rwlock_runlock(rwlock);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
JANET_CORE_FN(janet_cfun_rwlock_write_release,
|
||||
"(ev/release-wlock rwlock)",
|
||||
"Release a write lock on a read-write lock") {
|
||||
janet_fixarity(argc, 1);
|
||||
void *rwlock = janet_getabstract(argv, 0, &janet_rwlock_type);
|
||||
janet_os_rwlock_wunlock(rwlock);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
void janet_lib_ev(JanetTable *env) {
|
||||
JanetRegExt ev_cfuns_ext[] = {
|
||||
JANET_CORE_REG("ev/give", cfun_channel_push),
|
||||
@@ -3035,12 +3139,22 @@ void janet_lib_ev(JanetTable *env) {
|
||||
JANET_CORE_REG("ev/read", janet_cfun_stream_read),
|
||||
JANET_CORE_REG("ev/chunk", janet_cfun_stream_chunk),
|
||||
JANET_CORE_REG("ev/write", janet_cfun_stream_write),
|
||||
JANET_CORE_REG("ev/lock", janet_cfun_mutex),
|
||||
JANET_CORE_REG("ev/acquire-lock", janet_cfun_mutex_acquire),
|
||||
JANET_CORE_REG("ev/release-lock", janet_cfun_mutex_release),
|
||||
JANET_CORE_REG("ev/rwlock", janet_cfun_rwlock),
|
||||
JANET_CORE_REG("ev/acquire-rlock", janet_cfun_rwlock_read_lock),
|
||||
JANET_CORE_REG("ev/acquire-wlock", janet_cfun_rwlock_write_lock),
|
||||
JANET_CORE_REG("ev/release-rlock", janet_cfun_rwlock_read_release),
|
||||
JANET_CORE_REG("ev/release-wlock", janet_cfun_rwlock_write_release),
|
||||
JANET_REG_END
|
||||
};
|
||||
|
||||
janet_core_cfuns_ext(env, NULL, ev_cfuns_ext);
|
||||
janet_register_abstract_type(&janet_stream_type);
|
||||
janet_register_abstract_type(&janet_channel_type);
|
||||
janet_register_abstract_type(&janet_mutex_type);
|
||||
janet_register_abstract_type(&janet_rwlock_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,13 +36,22 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Needed for sched.h for cpu count */
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Needed for realpath on linux */
|
||||
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
|
||||
#define _XOPEN_SOURCE 500
|
||||
/* Needed for realpath on linux, as well as pthread rwlocks. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#if _XOPEN_SOURCE < 600
|
||||
#undef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
/* Needed for timegm and other extensions when building with -std=c99.
|
||||
|
||||
1161
src/core/ffi.c
Normal file
1161
src/core/ffi.c
Normal file
File diff suppressed because it is too large
Load Diff
101
src/core/io.c
101
src/core/io.c
@@ -112,42 +112,6 @@ static void *makef(FILE *f, int32_t flags) {
|
||||
return iof;
|
||||
}
|
||||
|
||||
/* Open a process */
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
JANET_CORE_FN(cfun_io_popen,
|
||||
"(file/popen command &opt mode) (DEPRECATED for os/spawn)",
|
||||
"Open a file that is backed by a process. The file must be opened in either "
|
||||
"the :r (read) or the :w (write) mode. In :r mode, the stdout of the "
|
||||
"process can be read from the file. In :w mode, the stdin of the process "
|
||||
"can be written to. Returns the new file.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
const uint8_t *fname = janet_getstring(argv, 0);
|
||||
const uint8_t *fmode = NULL;
|
||||
int32_t flags;
|
||||
if (argc == 2) {
|
||||
fmode = janet_getkeyword(argv, 1);
|
||||
flags = JANET_FILE_PIPED | checkflags(fmode);
|
||||
if (flags & (JANET_FILE_UPDATE | JANET_FILE_BINARY | JANET_FILE_APPEND)) {
|
||||
janet_panicf("invalid popen file mode :%S, expected :r or :w", fmode);
|
||||
}
|
||||
fmode = (const uint8_t *)((fmode[0] == 'r') ? "r" : "w");
|
||||
} else {
|
||||
fmode = (const uint8_t *)"r";
|
||||
flags = JANET_FILE_PIPED | JANET_FILE_READ;
|
||||
}
|
||||
#ifdef JANET_WINDOWS
|
||||
#define popen _popen
|
||||
#endif
|
||||
FILE *f = popen((const char *)fname, (const char *)fmode);
|
||||
if (!f) {
|
||||
if (flags & JANET_FILE_NONIL)
|
||||
janet_panicf("failed to popen %s: %s", fname, strerror(errno));
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
return janet_makefile(f, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
JANET_CORE_FN(cfun_io_temp,
|
||||
"(file/temp)",
|
||||
"Open an anonymous temporary file that is removed on close. "
|
||||
@@ -296,7 +260,6 @@ JANET_CORE_FN(cfun_io_fflush,
|
||||
}
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#define pclose _pclose
|
||||
#define WEXITSTATUS(x) x
|
||||
#endif
|
||||
|
||||
@@ -304,14 +267,7 @@ JANET_CORE_FN(cfun_io_fflush,
|
||||
int janet_file_close(JanetFile *file) {
|
||||
int ret = 0;
|
||||
if (!(file->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
if (file->flags & JANET_FILE_PIPED) {
|
||||
ret = pclose(file->file);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ret = fclose(file->file);
|
||||
}
|
||||
ret = fclose(file->file);
|
||||
file->flags |= JANET_FILE_CLOSED;
|
||||
return ret;
|
||||
}
|
||||
@@ -331,30 +287,18 @@ JANET_CORE_FN(cfun_io_fclose,
|
||||
"(file/close f)",
|
||||
"Close a file and release all related resources. When you are "
|
||||
"done reading a file, close it to prevent a resource leak and let "
|
||||
"other processes read the file. If the file is the result of a file/popen "
|
||||
"call, close waits for and returns the process exit status.") {
|
||||
"other processes read the file.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||
if (iof->flags & JANET_FILE_CLOSED)
|
||||
return janet_wrap_nil();
|
||||
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
|
||||
janet_panic("file not closable");
|
||||
if (iof->flags & JANET_FILE_PIPED) {
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
int status = pclose(iof->file);
|
||||
iof->flags |= JANET_FILE_CLOSED;
|
||||
if (status == -1) janet_panic("could not close file");
|
||||
return janet_wrap_integer(WEXITSTATUS(status));
|
||||
#else
|
||||
return janet_wrap_nil();
|
||||
#endif
|
||||
} else {
|
||||
if (fclose(iof->file)) {
|
||||
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
|
||||
janet_panic("could not close file");
|
||||
}
|
||||
iof->flags |= JANET_FILE_CLOSED;
|
||||
if (fclose(iof->file)) {
|
||||
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
|
||||
janet_panic("could not close file");
|
||||
}
|
||||
iof->flags |= JANET_FILE_CLOSED;
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@@ -546,27 +490,27 @@ JANET_CORE_FN(cfun_io_print,
|
||||
"(print & xs)",
|
||||
"Print values to the console (standard out). Value are converted "
|
||||
"to strings if they are not already. After printing all values, a "
|
||||
"newline character is printed. Use the value of (dyn :out stdout) to determine "
|
||||
"what to push characters to. Expects (dyn :out stdout) to be either a core/file or "
|
||||
"newline character is printed. Use the value of `(dyn :out stdout)` to determine "
|
||||
"what to push characters to. Expects `(dyn :out stdout)` to be either a core/file or "
|
||||
"a buffer. Returns nil.") {
|
||||
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_prin,
|
||||
"(prin & xs)",
|
||||
"Same as print, but does not add trailing newline.") {
|
||||
"Same as `print`, but does not add trailing newline.") {
|
||||
return cfun_io_print_impl(argc, argv, 0, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprint,
|
||||
"(eprint & xs)",
|
||||
"Same as print, but uses (dyn :err stderr) instead of (dyn :out stdout).") {
|
||||
"Same as `print`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
|
||||
return cfun_io_print_impl(argc, argv, 1, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprin,
|
||||
"(eprin & xs)",
|
||||
"Same as prin, but uses (dyn :err stderr) instead of (dyn :out stdout).") {
|
||||
"Same as `prin`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
|
||||
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
|
||||
}
|
||||
|
||||
@@ -574,7 +518,7 @@ JANET_CORE_FN(cfun_io_xprint,
|
||||
"(xprint to & xs)",
|
||||
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
|
||||
"newline character. The value to print "
|
||||
"to is the first argument, and is otherwise the same as print. Returns nil.") {
|
||||
"to is the first argument, and is otherwise the same as `print`. Returns nil.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||
}
|
||||
@@ -582,7 +526,7 @@ JANET_CORE_FN(cfun_io_xprint,
|
||||
JANET_CORE_FN(cfun_io_xprin,
|
||||
"(xprin to & xs)",
|
||||
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
|
||||
"to is the first argument, and is otherwise the same as prin. Returns nil.") {
|
||||
"to is the first argument, and is otherwise the same as `prin`. Returns nil.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||
}
|
||||
@@ -640,38 +584,38 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
||||
|
||||
JANET_CORE_FN(cfun_io_printf,
|
||||
"(printf fmt & xs)",
|
||||
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :out stdout) with a trailing newline.") {
|
||||
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :out stdout)` with a trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_prinf,
|
||||
"(prinf fmt & xs)",
|
||||
"Like printf but with no trailing newline.") {
|
||||
"Like `printf` but with no trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 0, "out", stdout);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprintf,
|
||||
"(eprintf fmt & xs)",
|
||||
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :err stderr) with a trailing newline.") {
|
||||
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :err stderr)` with a trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 1, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_eprinf,
|
||||
"(eprinf fmt & xs)",
|
||||
"Like eprintf but with no trailing newline.") {
|
||||
"Like `eprintf` but with no trailing newline.") {
|
||||
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprintf,
|
||||
"(xprintf to fmt & xs)",
|
||||
"Like printf but prints to an explicit file or value to. Returns nil.") {
|
||||
"Like `printf` but prints to an explicit file or value `to`. Returns nil.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_io_xprinf,
|
||||
"(xprinf to fmt & xs)",
|
||||
"Like prinf but prints to an explicit file or value to. Returns nil.") {
|
||||
"Like `prinf` but prints to an explicit file or value `to`. Returns nil.") {
|
||||
janet_arity(argc, 2, -1);
|
||||
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||
}
|
||||
@@ -696,7 +640,7 @@ static void janet_flusher(const char *name, FILE *dflt_file) {
|
||||
|
||||
JANET_CORE_FN(cfun_io_flush,
|
||||
"(flush)",
|
||||
"Flush (dyn :out stdout) if it is a file, otherwise do nothing.") {
|
||||
"Flush `(dyn :out stdout)` if it is a file, otherwise do nothing.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
janet_flusher("out", stdout);
|
||||
@@ -705,7 +649,7 @@ JANET_CORE_FN(cfun_io_flush,
|
||||
|
||||
JANET_CORE_FN(cfun_io_eflush,
|
||||
"(eflush)",
|
||||
"Flush (dyn :err stderr) if it is a file, otherwise do nothing.") {
|
||||
"Flush `(dyn :err stderr)` if it is a file, otherwise do nothing.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
janet_flusher("err", stderr);
|
||||
@@ -802,9 +746,6 @@ void janet_lib_io(JanetTable *env) {
|
||||
JANET_CORE_REG("file/write", cfun_io_fwrite),
|
||||
JANET_CORE_REG("file/flush", cfun_io_fflush),
|
||||
JANET_CORE_REG("file/seek", cfun_io_fseek),
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
JANET_CORE_REG("file/popen", cfun_io_popen),
|
||||
#endif
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, io_cfuns);
|
||||
|
||||
@@ -231,7 +231,7 @@ static Janet janet_rng_next(void *p, Janet key) {
|
||||
/* Get a random number */
|
||||
JANET_CORE_FN(janet_rand,
|
||||
"(math/random)",
|
||||
"Returns a uniformly distributed random number between 0 and 1") {
|
||||
"Returns a uniformly distributed random number between 0 and 1.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_number(janet_rng_double(&janet_vm.rng));
|
||||
@@ -240,7 +240,7 @@ JANET_CORE_FN(janet_rand,
|
||||
/* Seed the random number generator */
|
||||
JANET_CORE_FN(janet_srand,
|
||||
"(math/seedrandom seed)",
|
||||
"Set the seed for the random number generator. seed should be "
|
||||
"Set the seed for the random number generator. `seed` should be "
|
||||
"an integer or a buffer."
|
||||
) {
|
||||
janet_fixarity(argc, 1);
|
||||
@@ -261,7 +261,7 @@ JANET_CORE_FN(janet_##name, "(math/" #name " x)", doc) {\
|
||||
return janet_wrap_number(fop(x)); \
|
||||
}
|
||||
|
||||
JANET_DEFINE_MATHOP(acos, acos, "Returns the arccosize of x.")
|
||||
JANET_DEFINE_MATHOP(acos, acos, "Returns the arccosine of x.")
|
||||
JANET_DEFINE_MATHOP(asin, asin, "Returns the arcsin of x.")
|
||||
JANET_DEFINE_MATHOP(atan, atan, "Returns the arctangent of x.")
|
||||
JANET_DEFINE_MATHOP(cos, cos, "Returns the cosine of x.")
|
||||
|
||||
125
src/core/os.c
125
src/core/os.c
@@ -39,8 +39,12 @@
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef JANET_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#ifdef JANET_BSD
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef JANET_LINUX
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
@@ -67,12 +71,6 @@ extern char **environ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For macos */
|
||||
#ifdef JANET_APPLE
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
/* Not POSIX, but all Unixes but Solaris have this function. */
|
||||
#if defined(JANET_POSIX) && !defined(__sun)
|
||||
time_t timegm(struct tm *tm);
|
||||
@@ -211,6 +209,47 @@ JANET_CORE_FN(os_exit,
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_cpu_count,
|
||||
"(os/cpu-count &opt dflt)",
|
||||
"Get an approximate number of CPUs available on for this process to use. If "
|
||||
"unable to get an approximation, will return a default value dflt.") {
|
||||
janet_arity(argc, 0, 1);
|
||||
Janet dflt = argc > 0 ? argv[0] : janet_wrap_nil();
|
||||
#ifdef JANET_WINDOWS
|
||||
(void) dflt;
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
return janet_wrap_integer(info.dwNumberOfProcessors);
|
||||
#elif defined(JANET_LINUX)
|
||||
(void) dflt;
|
||||
cpu_set_t cs;
|
||||
CPU_ZERO(&cs);
|
||||
sched_getaffinity(0, sizeof(cs), &cs);
|
||||
int count = CPU_COUNT(&cs);
|
||||
return janet_wrap_integer(count);
|
||||
#elif defined(JANET_BSD) && defined(HW_NCPUONLINE)
|
||||
(void) dflt;
|
||||
const int name[2] = {CTL_HW, HW_NCPUONLINE};
|
||||
int result = 0;
|
||||
size_t len = sizeof(int);
|
||||
if (-1 == sysctl(name, 2, &result, &len, NULL, 0)) {
|
||||
return dflt;
|
||||
}
|
||||
return janet_wrap_integer(result);
|
||||
#elif defined(JANET_BSD) && defined(HW_NCPU)
|
||||
(void) dflt;
|
||||
const int name[2] = {CTL_HW, HW_NCPU};
|
||||
int result = 0;
|
||||
size_t len = sizeof(int);
|
||||
if (-1 == sysctl(name, 2, &result, &len, NULL, 0)) {
|
||||
return dflt;
|
||||
}
|
||||
return janet_wrap_integer(result);
|
||||
#else
|
||||
return dflt;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef JANET_REDUCED_OS
|
||||
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
@@ -405,7 +444,7 @@ typedef struct {
|
||||
static JanetEVGenericMessage janet_proc_wait_subr(JanetEVGenericMessage args) {
|
||||
JanetProc *proc = (JanetProc *) args.argp;
|
||||
WaitForSingleObject(proc->pHandle, INFINITE);
|
||||
GetExitCodeProcess(proc->pHandle, &args.argi);
|
||||
GetExitCodeProcess(proc->pHandle, &args.tag);
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -560,8 +599,8 @@ JANET_CORE_FN(os_proc_wait,
|
||||
JANET_CORE_FN(os_proc_kill,
|
||||
"(os/proc-kill proc &opt wait)",
|
||||
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
|
||||
"handle on windows. If wait is truthy, will wait for the process to finish and "
|
||||
"returns the exit code. Otherwise, returns proc.") {
|
||||
"handle on windows. If `wait` is truthy, will wait for the process to finish and "
|
||||
"returns the exit code. Otherwise, returns `proc`.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||
if (proc->flags & JANET_PROC_WAITED) {
|
||||
@@ -846,19 +885,19 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
|
||||
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
|
||||
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
|
||||
Janet maybe_stderr = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("err"));
|
||||
if (janet_keyeq(maybe_stdin, "pipe")) {
|
||||
if (is_spawn && janet_keyeq(maybe_stdin, "pipe")) {
|
||||
new_in = make_pipes(&pipe_in, 1, &pipe_errflag);
|
||||
pipe_owner_flags |= JANET_PROC_OWNS_STDIN;
|
||||
} else if (!janet_checktype(maybe_stdin, JANET_NIL)) {
|
||||
new_in = janet_getjstream(&maybe_stdin, 0, &orig_in);
|
||||
}
|
||||
if (janet_keyeq(maybe_stdout, "pipe")) {
|
||||
if (is_spawn && janet_keyeq(maybe_stdout, "pipe")) {
|
||||
new_out = make_pipes(&pipe_out, 0, &pipe_errflag);
|
||||
pipe_owner_flags |= JANET_PROC_OWNS_STDOUT;
|
||||
} else if (!janet_checktype(maybe_stdout, JANET_NIL)) {
|
||||
new_out = janet_getjstream(&maybe_stdout, 0, &orig_out);
|
||||
}
|
||||
if (janet_keyeq(maybe_stderr, "pipe")) {
|
||||
if (is_spawn && janet_keyeq(maybe_stderr, "pipe")) {
|
||||
new_err = make_pipes(&pipe_err, 0, &pipe_errflag);
|
||||
pipe_owner_flags |= JANET_PROC_OWNS_STDERR;
|
||||
} else if (!janet_checktype(maybe_stderr, JANET_NIL)) {
|
||||
@@ -1073,21 +1112,20 @@ JANET_CORE_FN(os_execute,
|
||||
"`env` is a table or struct mapping environment variables to values. It can also "
|
||||
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
|
||||
"These arguments should be core/file values. "
|
||||
"One can also pass in the :pipe keyword "
|
||||
"for these arguments to create files that will read (for :err and :out) or write (for :in) "
|
||||
"to the file descriptor of the subprocess. This is only useful in `os/spawn`, which takes "
|
||||
"the same parameters as `os/execute`, but will return an object that contains references to these "
|
||||
"files via (return-value :in), (return-value :out), and (return-value :err). "
|
||||
"Returns the exit status of the program.") {
|
||||
return os_execute_impl(argc, argv, 0);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(os_spawn,
|
||||
"(os/spawn args &opt flags env)",
|
||||
"Execute a program on the system and return a handle to the process. Otherwise, the "
|
||||
"same arguments as os/execute. Does not wait for the process. "
|
||||
"The returned value has the fields :in, :out, :err, :return-code and "
|
||||
"the additional field :pid on unix like platforms.") {
|
||||
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
||||
"same arguments as `os/execute`. Does not wait for the process. "
|
||||
"For each of the :in, :out, and :err keys to the `env` argument, one "
|
||||
"can also pass in the keyword `:pipe`"
|
||||
"to get streams for standard IO of the subprocess that can be read from and written to."
|
||||
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
|
||||
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
|
||||
"subprocess or `(os/proc-kill proc)`.") {
|
||||
return os_execute_impl(argc, argv, 1);
|
||||
}
|
||||
|
||||
@@ -1127,7 +1165,7 @@ JANET_CORE_FN(os_shell,
|
||||
|
||||
JANET_CORE_FN(os_environ,
|
||||
"(os/environ)",
|
||||
"Get a copy of the os environment table.") {
|
||||
"Get a copy of the OS environment table.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
int32_t nenv = 0;
|
||||
@@ -1208,7 +1246,7 @@ JANET_CORE_FN(os_time,
|
||||
JANET_CORE_FN(os_clock,
|
||||
"(os/clock)",
|
||||
"Return the number of whole + fractional seconds since some fixed point in time. The clock "
|
||||
"is guaranteed to be non decreasing in real time.") {
|
||||
"is guaranteed to be non-decreasing in real time.") {
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
struct timespec tv;
|
||||
@@ -1219,7 +1257,7 @@ JANET_CORE_FN(os_clock,
|
||||
|
||||
JANET_CORE_FN(os_sleep,
|
||||
"(os/sleep n)",
|
||||
"Suspend the program for n seconds. 'nsec' can be a real number. Returns "
|
||||
"Suspend the program for `n` seconds. `n` can be a real number. Returns "
|
||||
"nil.") {
|
||||
janet_fixarity(argc, 1);
|
||||
double delay = janet_getnumber(argv, 0);
|
||||
@@ -1256,7 +1294,7 @@ JANET_CORE_FN(os_cwd,
|
||||
|
||||
JANET_CORE_FN(os_cryptorand,
|
||||
"(os/cryptorand n &opt buf)",
|
||||
"Get or append n bytes of good quality random data provided by the OS. Returns a new buffer or buf.") {
|
||||
"Get or append `n` bytes of good quality random data provided by the OS. Returns a new buffer or `buf`.") {
|
||||
JanetBuffer *buffer;
|
||||
janet_arity(argc, 1, 2);
|
||||
int32_t offset;
|
||||
@@ -1393,9 +1431,9 @@ static timeint_t entry_getint(Janet env_entry, char *field) {
|
||||
JANET_CORE_FN(os_mktime,
|
||||
"(os/mktime date-struct &opt local)",
|
||||
"Get the broken down date-struct time expressed as the number "
|
||||
" of seconds since January 1, 1970, the Unix epoch. "
|
||||
"of seconds since January 1, 1970, the Unix epoch. "
|
||||
"Returns a real number. "
|
||||
"Date is given in UTC unless local is truthy, in which case the "
|
||||
"Date is given in UTC unless `local` is truthy, in which case the "
|
||||
"date is computed for the local timezone.\n\n"
|
||||
"Inverse function to os/date.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
@@ -1466,7 +1504,7 @@ JANET_CORE_FN(os_link,
|
||||
|
||||
JANET_CORE_FN(os_symlink,
|
||||
"(os/symlink oldpath newpath)",
|
||||
"Create a symlink from oldpath to newpath, returning nil. Same as (os/link oldpath newpath true).") {
|
||||
"Create a symlink from oldpath to newpath, returning nil. Same as `(os/link oldpath newpath true)`.") {
|
||||
janet_fixarity(argc, 2);
|
||||
#ifdef JANET_WINDOWS
|
||||
(void) argc;
|
||||
@@ -1841,10 +1879,10 @@ JANET_CORE_FN(os_stat,
|
||||
"* :uid - File uid\n\n"
|
||||
"* :gid - File gid\n\n"
|
||||
"* :nlink - number of links to file\n\n"
|
||||
"* :rdev - Real device of file. 0 on windows.\n\n"
|
||||
"* :rdev - Real device of file. 0 on Windows\n\n"
|
||||
"* :size - size of file in bytes\n\n"
|
||||
"* :blocks - number of blocks in file. 0 on windows\n\n"
|
||||
"* :blocksize - size of blocks in file. 0 on windows\n\n"
|
||||
"* :blocks - number of blocks in file. 0 on Windows\n\n"
|
||||
"* :blocksize - size of blocks in file. 0 on Windows\n\n"
|
||||
"* :accessed - timestamp when file last accessed\n\n"
|
||||
"* :changed - timestamp when file last changed (permissions changed)\n\n"
|
||||
"* :modified - timestamp when file last modified (content changed)\n") {
|
||||
@@ -1859,9 +1897,9 @@ JANET_CORE_FN(os_lstat,
|
||||
|
||||
JANET_CORE_FN(os_chmod,
|
||||
"(os/chmod path mode)",
|
||||
"Change file permissions, where mode is a permission string as returned by "
|
||||
"os/perm-string, or an integer as returned by os/perm-int. "
|
||||
"When mode is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
|
||||
"Change file permissions, where `mode` is a permission string as returned by "
|
||||
"`os/perm-string`, or an integer as returned by `os/perm-int`. "
|
||||
"When `mode` is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
|
||||
"8r666 or 8r400. Windows will not differentiate between user, group, and other permissions, and thus will combine all of these permissions. Returns nil.") {
|
||||
janet_fixarity(argc, 2);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
@@ -1963,9 +2001,9 @@ JANET_CORE_FN(os_realpath,
|
||||
|
||||
JANET_CORE_FN(os_permission_string,
|
||||
"(os/perm-string int)",
|
||||
"Convert a Unix octal permission value from a permission integer as returned by os/stat "
|
||||
"Convert a Unix octal permission value from a permission integer as returned by `os/stat` "
|
||||
"to a human readable string, that follows the formatting "
|
||||
"of unix tools like ls. Returns the string as a 9 character string of r, w, x and - characters. Does not "
|
||||
"of Unix tools like `ls`. Returns the string as a 9-character string of r, w, x and - characters. Does not "
|
||||
"include the file/directory/symlink character as rendered by `ls`.") {
|
||||
janet_fixarity(argc, 1);
|
||||
return os_make_permstring(os_get_unix_mode(argv, 0));
|
||||
@@ -1973,7 +2011,7 @@ JANET_CORE_FN(os_permission_string,
|
||||
|
||||
JANET_CORE_FN(os_permission_int,
|
||||
"(os/perm-int bytes)",
|
||||
"Parse a 9 character permission string and return an integer that can be used by chmod.") {
|
||||
"Parse a 9-character permission string and return an integer that can be used by chmod.") {
|
||||
janet_fixarity(argc, 1);
|
||||
return janet_wrap_integer(os_get_unix_mode(argv, 0));
|
||||
}
|
||||
@@ -1992,7 +2030,7 @@ static jmode_t os_optmode(int32_t argc, const Janet *argv, int32_t n, int32_t df
|
||||
JANET_CORE_FN(os_open,
|
||||
"(os/open path &opt flags mode)",
|
||||
"Create a stream from a file, like the POSIX open system call. Returns a new stream. "
|
||||
"mode should be a file mode as passed to os/chmod, but only if the create flag is given. "
|
||||
"`mode` should be a file mode as passed to `os/chmod`, but only if the create flag is given. "
|
||||
"The default mode is 8r666. "
|
||||
"Allowed flags are as follows:\n\n"
|
||||
" * :r - open this file for reading\n"
|
||||
@@ -2000,11 +2038,11 @@ JANET_CORE_FN(os_open,
|
||||
" * :c - create a new file (O_CREATE)\n"
|
||||
" * :e - fail if the file exists (O_EXCL)\n"
|
||||
" * :t - shorten an existing file to length 0 (O_TRUNC)\n\n"
|
||||
"Posix only flags:\n\n"
|
||||
"Posix-only flags:\n\n"
|
||||
" * :a - append to a file (O_APPEND)\n"
|
||||
" * :x - O_SYNC\n"
|
||||
" * :C - O_NOCTTY\n\n"
|
||||
"Windows only flags:\n\n"
|
||||
"Windows-only flags:\n\n"
|
||||
" * :R - share reads (FILE_SHARE_READ)\n"
|
||||
" * :W - share writes (FILE_SHARE_WRITE)\n"
|
||||
" * :D - share deletes (FILE_SHARE_DELETE)\n"
|
||||
@@ -2157,7 +2195,7 @@ JANET_CORE_FN(os_open,
|
||||
|
||||
JANET_CORE_FN(os_pipe,
|
||||
"(os/pipe)",
|
||||
"Create a readable stream and a writable stream that are connected. Returns a two element "
|
||||
"Create a readable stream and a writable stream that are connected. Returns a two-element "
|
||||
"tuple where the first element is a readable stream and the second element is the writable "
|
||||
"stream.") {
|
||||
(void) argv;
|
||||
@@ -2206,6 +2244,7 @@ void janet_lib_os(JanetTable *env) {
|
||||
JANET_CORE_REG("os/chmod", os_chmod),
|
||||
JANET_CORE_REG("os/touch", os_touch),
|
||||
JANET_CORE_REG("os/cd", os_cd),
|
||||
JANET_CORE_REG("os/cpu-count", os_cpu_count),
|
||||
#ifndef JANET_NO_UMASK
|
||||
JANET_CORE_REG("os/umask", os_umask),
|
||||
#endif
|
||||
|
||||
@@ -883,7 +883,7 @@ const JanetAbstractType janet_parser_type = {
|
||||
JANET_CORE_FN(cfun_parse_parser,
|
||||
"(parser/new)",
|
||||
"Creates and returns a new parser object. Parsers are state machines "
|
||||
"that can receive bytes, and generate a stream of values.") {
|
||||
"that can receive bytes and generate a stream of values.") {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
JanetParser *p = janet_abstract(&janet_parser_type, sizeof(JanetParser));
|
||||
@@ -894,7 +894,7 @@ JANET_CORE_FN(cfun_parse_parser,
|
||||
JANET_CORE_FN(cfun_parse_consume,
|
||||
"(parser/consume parser bytes &opt index)",
|
||||
"Input bytes into the parser and parse them. Will not throw errors "
|
||||
"if there is a parse error. Starts at the byte index given by index. Returns "
|
||||
"if there is a parse error. Starts at the byte index given by `index`. Returns "
|
||||
"the number of bytes read.") {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||
@@ -922,7 +922,7 @@ JANET_CORE_FN(cfun_parse_consume,
|
||||
|
||||
JANET_CORE_FN(cfun_parse_eof,
|
||||
"(parser/eof parser)",
|
||||
"Indicate that the end of file was reached to the parser. This puts the parser in the :dead state.") {
|
||||
"Indicate to the parser that the end of file was reached. This puts the parser in the :dead state.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||
janet_parser_eof(p);
|
||||
@@ -982,7 +982,7 @@ JANET_CORE_FN(cfun_parse_has_more,
|
||||
|
||||
JANET_CORE_FN(cfun_parse_byte,
|
||||
"(parser/byte parser b)",
|
||||
"Input a single byte into the parser byte stream. Returns the parser.") {
|
||||
"Input a single byte `b` into the parser byte stream. Returns the parser.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||
int32_t i = janet_getinteger(argv, 1);
|
||||
@@ -1022,7 +1022,7 @@ JANET_CORE_FN(cfun_parse_error,
|
||||
"If the parser is in the error state, returns the message associated with "
|
||||
"that error. Otherwise, returns nil. Also flushes the parser state and parser "
|
||||
"queue, so be sure to handle everything in the queue before calling "
|
||||
"parser/error.") {
|
||||
"`parser/error`.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||
const char *err = janet_parser_error(p);
|
||||
|
||||
@@ -293,6 +293,7 @@ tail:
|
||||
if (rule[0] == RULE_TO) cap_load(s, cs2);
|
||||
break;
|
||||
}
|
||||
cap_load(s, cs2);
|
||||
text++;
|
||||
}
|
||||
up1(s);
|
||||
|
||||
@@ -983,8 +983,9 @@ void janet_buffer_format(
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const uint8_t *s = janet_getstring(argv, arg);
|
||||
int32_t l = janet_string_length(s);
|
||||
JanetByteView bytes = janet_getbytes(argv, arg);
|
||||
const uint8_t *s = bytes.bytes;
|
||||
int32_t l = bytes.len;
|
||||
if (form[2] == '\0')
|
||||
janet_buffer_push_bytes(b, s, l);
|
||||
else {
|
||||
|
||||
@@ -305,6 +305,9 @@ static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv)
|
||||
for (i = 1; i < argn - 1; i++) {
|
||||
Janet attr = argv[i];
|
||||
switch (janet_type(attr)) {
|
||||
case JANET_TUPLE:
|
||||
janetc_cerror(c, "unexpected form - did you intend to use defn?");
|
||||
break;
|
||||
default:
|
||||
janetc_cerror(c, "could not add metadata to binding");
|
||||
break;
|
||||
@@ -390,10 +393,11 @@ static int varleaf(
|
||||
static JanetSlot janetc_var(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
Janet head;
|
||||
JanetTable *attr_table = handleattr(c, argn, argv);
|
||||
JanetSlot ret = dohead(c, opts, &head, argn, argv);
|
||||
if (c->result.status == JANET_COMPILE_ERROR)
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv));
|
||||
destructure(c, argv[0], ret, varleaf, attr_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -439,10 +443,11 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
JanetCompiler *c = opts.compiler;
|
||||
Janet head;
|
||||
opts.flags &= ~JANET_FOPTS_HINT;
|
||||
JanetTable *attr_table = handleattr(c, argn, argv);
|
||||
JanetSlot ret = dohead(c, opts, &head, argn, argv);
|
||||
if (c->result.status == JANET_COMPILE_ERROR)
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv));
|
||||
destructure(c, argv[0], ret, defleaf, attr_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -817,6 +822,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
int selfref = 0;
|
||||
int seenamp = 0;
|
||||
int seenopt = 0;
|
||||
int namedargs = 0;
|
||||
|
||||
/* Begin function */
|
||||
c->scope->flags |= JANET_SCOPE_CLOSURE;
|
||||
@@ -841,6 +847,9 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
|
||||
/* Keep track of destructured parameters */
|
||||
JanetSlot *destructed_params = NULL;
|
||||
JanetSlot *named_params = NULL;
|
||||
JanetTable *named_table = NULL;
|
||||
JanetSlot named_slot;
|
||||
|
||||
/* Compile function parameters */
|
||||
params = janet_unwrap_tuple(argv[parami]);
|
||||
@@ -848,49 +857,74 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
arity = paramcount;
|
||||
for (i = 0; i < paramcount; i++) {
|
||||
Janet param = params[i];
|
||||
if (janet_checktype(param, JANET_SYMBOL)) {
|
||||
if (namedargs) {
|
||||
if (!janet_checktype(param, JANET_SYMBOL)) {
|
||||
errmsg = "only named arguments can follow &named";
|
||||
goto error;
|
||||
}
|
||||
Janet key = janet_wrap_keyword(janet_unwrap_symbol(param));
|
||||
janet_table_put(named_table, key, param);
|
||||
janet_v_push(named_params, janetc_farslot(c));
|
||||
} else if (janet_checktype(param, JANET_SYMBOL)) {
|
||||
/* Check for varargs and unfixed arity */
|
||||
if (!janet_cstrcmp(janet_unwrap_symbol(param), "&")) {
|
||||
if (seenamp) {
|
||||
errmsg = "& in unexpected location";
|
||||
goto error;
|
||||
} else if (i == paramcount - 1) {
|
||||
allow_extra = 1;
|
||||
const uint8_t *sym = janet_unwrap_symbol(param);
|
||||
if (sym[0] == '&') {
|
||||
if (!janet_cstrcmp(sym, "&")) {
|
||||
if (seenamp) {
|
||||
errmsg = "& in unexpected location";
|
||||
goto error;
|
||||
} else if (i == paramcount - 1) {
|
||||
allow_extra = 1;
|
||||
arity--;
|
||||
} else if (i == paramcount - 2) {
|
||||
vararg = 1;
|
||||
arity -= 2;
|
||||
} else {
|
||||
errmsg = "& in unexpected location";
|
||||
goto error;
|
||||
}
|
||||
seenamp = 1;
|
||||
} else if (!janet_cstrcmp(sym, "&opt")) {
|
||||
if (seenopt) {
|
||||
errmsg = "only one &opt allowed";
|
||||
goto error;
|
||||
} else if (i == paramcount - 1) {
|
||||
errmsg = "&opt cannot be last item in parameter list";
|
||||
goto error;
|
||||
}
|
||||
min_arity = i;
|
||||
arity--;
|
||||
} else if (i == paramcount - 2) {
|
||||
vararg = 1;
|
||||
arity -= 2;
|
||||
} else {
|
||||
errmsg = "& in unexpected location";
|
||||
goto error;
|
||||
}
|
||||
seenamp = 1;
|
||||
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&opt")) {
|
||||
if (seenopt) {
|
||||
errmsg = "only one &opt allowed";
|
||||
goto error;
|
||||
} else if (i == paramcount - 1) {
|
||||
errmsg = "&opt cannot be last item in parameter list";
|
||||
goto error;
|
||||
}
|
||||
min_arity = i;
|
||||
arity--;
|
||||
seenopt = 1;
|
||||
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&keys")) {
|
||||
if (seenamp) {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
} else if (i == paramcount - 2) {
|
||||
seenopt = 1;
|
||||
} else if (!janet_cstrcmp(sym, "&keys")) {
|
||||
if (seenamp) {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
} else if (i == paramcount - 2) {
|
||||
vararg = 1;
|
||||
structarg = 1;
|
||||
arity -= 2;
|
||||
} else {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
}
|
||||
seenamp = 1;
|
||||
} else if (!janet_cstrcmp(sym, "&named")) {
|
||||
if (seenamp) {
|
||||
errmsg = "&named in unexpected location";
|
||||
goto error;
|
||||
}
|
||||
vararg = 1;
|
||||
structarg = 1;
|
||||
arity -= 2;
|
||||
arity = i;
|
||||
seenamp = 1;
|
||||
namedargs = 1;
|
||||
named_table = janet_table(10);
|
||||
named_slot = janetc_farslot(c);
|
||||
} else {
|
||||
errmsg = "&keys in unexpected location";
|
||||
goto error;
|
||||
janetc_nameslot(c, sym, janetc_farslot(c));
|
||||
}
|
||||
seenamp = 1;
|
||||
} else {
|
||||
janetc_nameslot(c, janet_unwrap_symbol(param), janetc_farslot(c));
|
||||
janetc_nameslot(c, sym, janetc_farslot(c));
|
||||
}
|
||||
} else {
|
||||
janet_v_push(destructed_params, janetc_farslot(c));
|
||||
@@ -909,6 +943,14 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
}
|
||||
janet_v_free(destructed_params);
|
||||
|
||||
/* Compile named arguments */
|
||||
if (namedargs) {
|
||||
Janet param = janet_wrap_table(named_table);
|
||||
destructure(c, param, named_slot, defleaf, NULL);
|
||||
janetc_freeslot(c, named_slot);
|
||||
janet_v_free(named_params);
|
||||
}
|
||||
|
||||
max_arity = (vararg || allow_extra) ? INT32_MAX : arity;
|
||||
if (!seenopt) min_arity = arity;
|
||||
|
||||
|
||||
@@ -173,10 +173,10 @@ static int32_t kmp_next(struct kmp_state *state) {
|
||||
JANET_CORE_FN(cfun_string_slice,
|
||||
"(string/slice bytes &opt start end)",
|
||||
"Returns a substring from a byte sequence. The substring is from "
|
||||
"index start inclusive to index end exclusive. All indexing "
|
||||
"is from 0. 'start' and 'end' can also be negative to indicate indexing "
|
||||
"index `start` inclusive to index `end`, exclusive. All indexing "
|
||||
"is from 0. `start` and `end` can also be negative to indicate indexing "
|
||||
"from the end of the string. Note that index -1 is synonymous with "
|
||||
"index (length bytes) to allow a full negative slice range. ") {
|
||||
"index `(length bytes)` to allow a full negative slice range. ") {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
return janet_stringv(view.bytes + range.start, range.end - range.start);
|
||||
@@ -184,7 +184,7 @@ JANET_CORE_FN(cfun_string_slice,
|
||||
|
||||
JANET_CORE_FN(cfun_symbol_slice,
|
||||
"(symbol/slice bytes &opt start end)",
|
||||
"Same a string/slice, but returns a symbol.") {
|
||||
"Same as string/slice, but returns a symbol.") {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
return janet_symbolv(view.bytes + range.start, range.end - range.start);
|
||||
@@ -192,7 +192,7 @@ JANET_CORE_FN(cfun_symbol_slice,
|
||||
|
||||
JANET_CORE_FN(cfun_keyword_slice,
|
||||
"(keyword/slice bytes &opt start end)",
|
||||
"Same a string/slice, but returns a keyword.") {
|
||||
"Same as string/slice, but returns a keyword.") {
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
return janet_keywordv(view.bytes + range.start, range.end - range.start);
|
||||
@@ -200,7 +200,7 @@ JANET_CORE_FN(cfun_keyword_slice,
|
||||
|
||||
JANET_CORE_FN(cfun_string_repeat,
|
||||
"(string/repeat bytes n)",
|
||||
"Returns a string that is n copies of bytes concatenated.") {
|
||||
"Returns a string that is `n` copies of `bytes` concatenated.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
int32_t rep = janet_getinteger(argv, 1);
|
||||
@@ -282,7 +282,7 @@ JANET_CORE_FN(cfun_string_asciiupper,
|
||||
|
||||
JANET_CORE_FN(cfun_string_reverse,
|
||||
"(string/reverse str)",
|
||||
"Returns a string that is the reversed version of str.") {
|
||||
"Returns a string that is the reversed version of `str`.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetByteView view = janet_getbytes(argv, 0);
|
||||
uint8_t *buf = janet_string_begin(view.len);
|
||||
@@ -308,8 +308,8 @@ static void findsetup(int32_t argc, Janet *argv, struct kmp_state *s, int32_t ex
|
||||
|
||||
JANET_CORE_FN(cfun_string_find,
|
||||
"(string/find patt str &opt start-index)",
|
||||
"Searches for the first instance of pattern patt in string "
|
||||
"str. Returns the index of the first character in patt if found, "
|
||||
"Searches for the first instance of pattern `patt` in string "
|
||||
"`str`. Returns the index of the first character in `patt` if found, "
|
||||
"otherwise returns nil.") {
|
||||
int32_t result;
|
||||
struct kmp_state state;
|
||||
@@ -323,7 +323,7 @@ JANET_CORE_FN(cfun_string_find,
|
||||
|
||||
JANET_CORE_FN(cfun_string_hasprefix,
|
||||
"(string/has-prefix? pfx str)",
|
||||
"Tests whether str starts with pfx.") {
|
||||
"Tests whether `str` starts with `pfx`.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetByteView prefix = janet_getbytes(argv, 0);
|
||||
JanetByteView str = janet_getbytes(argv, 1);
|
||||
@@ -334,7 +334,7 @@ JANET_CORE_FN(cfun_string_hasprefix,
|
||||
|
||||
JANET_CORE_FN(cfun_string_hassuffix,
|
||||
"(string/has-suffix? sfx str)",
|
||||
"Tests whether str ends with sfx.") {
|
||||
"Tests whether `str` ends with `sfx`.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetByteView suffix = janet_getbytes(argv, 0);
|
||||
JanetByteView str = janet_getbytes(argv, 1);
|
||||
@@ -347,9 +347,9 @@ JANET_CORE_FN(cfun_string_hassuffix,
|
||||
|
||||
JANET_CORE_FN(cfun_string_findall,
|
||||
"(string/find-all patt str &opt start-index)",
|
||||
"Searches for all instances of pattern patt in string "
|
||||
"str. Returns an array of all indices of found patterns. Overlapping "
|
||||
"instances of the pattern are counted individually, meaning a byte in str "
|
||||
"Searches for all instances of pattern `patt` in string "
|
||||
"`str`. Returns an array of all indices of found patterns. Overlapping "
|
||||
"instances of the pattern are counted individually, meaning a byte in `str` "
|
||||
"may contribute to multiple found patterns.") {
|
||||
int32_t result;
|
||||
struct kmp_state state;
|
||||
@@ -386,8 +386,8 @@ static void replacesetup(int32_t argc, Janet *argv, struct replace_state *s) {
|
||||
|
||||
JANET_CORE_FN(cfun_string_replace,
|
||||
"(string/replace patt subst str)",
|
||||
"Replace the first occurrence of patt with subst in the string str. "
|
||||
"Will return the new string if patt is found, otherwise returns str.") {
|
||||
"Replace the first occurrence of `patt` with `subst` in the string `str`. "
|
||||
"Will return the new string if `patt` is found, otherwise returns `str`.") {
|
||||
int32_t result;
|
||||
struct replace_state s;
|
||||
uint8_t *buf;
|
||||
@@ -409,9 +409,9 @@ JANET_CORE_FN(cfun_string_replace,
|
||||
|
||||
JANET_CORE_FN(cfun_string_replaceall,
|
||||
"(string/replace-all patt subst str)",
|
||||
"Replace all instances of patt with subst in the string str. Overlapping "
|
||||
"Replace all instances of `patt` with `subst` in the string `str`. Overlapping "
|
||||
"matches will not be counted, only the first match in such a span will be replaced. "
|
||||
"Will return the new string if patt is found, otherwise returns str.") {
|
||||
"Will return the new string if `patt` is found, otherwise returns `str`.") {
|
||||
int32_t result;
|
||||
struct replace_state s;
|
||||
JanetBuffer b;
|
||||
@@ -433,11 +433,11 @@ JANET_CORE_FN(cfun_string_replaceall,
|
||||
|
||||
JANET_CORE_FN(cfun_string_split,
|
||||
"(string/split delim str &opt start limit)",
|
||||
"Splits a string str with delimiter delim and returns an array of "
|
||||
"substrings. The substrings will not contain the delimiter delim. If delim "
|
||||
"Splits a string `str` with delimiter `delim` and returns an array of "
|
||||
"substrings. The substrings will not contain the delimiter `delim`. If `delim` "
|
||||
"is not found, the returned array will have one element. Will start searching "
|
||||
"for delim at the index start (if provided), and return up to a maximum "
|
||||
"of limit results (if provided).") {
|
||||
"for `delim` at the index `start` (if provided), and return up to a maximum "
|
||||
"of `limit` results (if provided).") {
|
||||
int32_t result;
|
||||
JanetArray *array;
|
||||
struct kmp_state state;
|
||||
@@ -461,9 +461,9 @@ JANET_CORE_FN(cfun_string_split,
|
||||
|
||||
JANET_CORE_FN(cfun_string_checkset,
|
||||
"(string/check-set set str)",
|
||||
"Checks that the string str only contains bytes that appear in the string set. "
|
||||
"Returns true if all bytes in str appear in set, false if some bytes in str do "
|
||||
"not appear in set.") {
|
||||
"Checks that the string `str` only contains bytes that appear in the string `set`. "
|
||||
"Returns true if all bytes in `str` appear in `set`, false if some bytes in `str` do "
|
||||
"not appear in `set`.") {
|
||||
uint32_t bitset[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
janet_fixarity(argc, 2);
|
||||
JanetByteView set = janet_getbytes(argv, 0);
|
||||
@@ -488,7 +488,7 @@ JANET_CORE_FN(cfun_string_checkset,
|
||||
JANET_CORE_FN(cfun_string_join,
|
||||
"(string/join parts &opt sep)",
|
||||
"Joins an array of strings into one string, optionally separated by "
|
||||
"a separator string sep.") {
|
||||
"a separator string `sep`.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetView parts = janet_getindexed(argv, 0);
|
||||
JanetByteView joiner;
|
||||
@@ -530,7 +530,7 @@ JANET_CORE_FN(cfun_string_join,
|
||||
|
||||
JANET_CORE_FN(cfun_string_format,
|
||||
"(string/format format & values)",
|
||||
"Similar to snprintf, but specialized for operating with Janet values. Returns "
|
||||
"Similar to `snprintf`, but specialized for operating with Janet values. Returns "
|
||||
"a new string.") {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetBuffer *buffer = janet_buffer(0);
|
||||
@@ -574,7 +574,7 @@ static void trim_help_args(int32_t argc, Janet *argv, JanetByteView *str, JanetB
|
||||
JANET_CORE_FN(cfun_string_trim,
|
||||
"(string/trim str &opt set)",
|
||||
"Trim leading and trailing whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.") {
|
||||
"`set` is provided, consider only characters in `set` to be whitespace.") {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t left_edge = trim_help_leftedge(str, set);
|
||||
@@ -587,7 +587,7 @@ JANET_CORE_FN(cfun_string_trim,
|
||||
JANET_CORE_FN(cfun_string_triml,
|
||||
"(string/triml str &opt set)",
|
||||
"Trim leading whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.") {
|
||||
"`set` is provided, consider only characters in `set` to be whitespace.") {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t left_edge = trim_help_leftedge(str, set);
|
||||
@@ -597,7 +597,7 @@ JANET_CORE_FN(cfun_string_triml,
|
||||
JANET_CORE_FN(cfun_string_trimr,
|
||||
"(string/trimr str &opt set)",
|
||||
"Trim trailing whitespace from a byte sequence. If the argument "
|
||||
"set is provided, consider only characters in set to be whitespace.") {
|
||||
"`set` is provided, consider only characters in `set` to be whitespace.") {
|
||||
JanetByteView str, set;
|
||||
trim_help_args(argc, argv, &str, &set);
|
||||
int32_t right_edge = trim_help_rightedge(str, set);
|
||||
|
||||
@@ -296,17 +296,17 @@ JanetTable *janet_table_proto_flatten(JanetTable *t) {
|
||||
JANET_CORE_FN(cfun_table_new,
|
||||
"(table/new capacity)",
|
||||
"Creates a new empty table with pre-allocated memory "
|
||||
"for capacity entries. This means that if one knows the number of "
|
||||
"entries going to go in a table on creation, extra memory allocation "
|
||||
"for `capacity` entries. This means that if one knows the number of "
|
||||
"entries going into a table on creation, extra memory allocation "
|
||||
"can be avoided. Returns the new table.") {
|
||||
janet_fixarity(argc, 1);
|
||||
int32_t cap = janet_getinteger(argv, 0);
|
||||
int32_t cap = janet_getnat(argv, 0);
|
||||
return janet_wrap_table(janet_table(cap));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_table_getproto,
|
||||
"(table/getproto tab)",
|
||||
"Get the prototype table of a table. Returns nil if a table "
|
||||
"Get the prototype table of a table. Returns nil if the table "
|
||||
"has no prototype, otherwise returns the prototype.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetTable *t = janet_gettable(argv, 0);
|
||||
@@ -317,7 +317,7 @@ JANET_CORE_FN(cfun_table_getproto,
|
||||
|
||||
JANET_CORE_FN(cfun_table_setproto,
|
||||
"(table/setproto tab proto)",
|
||||
"Set the prototype of a table. Returns the original table tab.") {
|
||||
"Set the prototype of a table. Returns the original table `tab`.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetTable *table = janet_gettable(argv, 0);
|
||||
JanetTable *proto = NULL;
|
||||
@@ -339,8 +339,8 @@ JANET_CORE_FN(cfun_table_tostruct,
|
||||
|
||||
JANET_CORE_FN(cfun_table_rawget,
|
||||
"(table/rawget tab key)",
|
||||
"Gets a value from a table without looking at the prototype table. "
|
||||
"If a table tab does not contain t directly, the function will return "
|
||||
"Gets a value from a table `tab` without looking at the prototype table. "
|
||||
"If `tab` does not contain the key directly, the function will return "
|
||||
"nil without checking the prototype. Returns the value in the table.") {
|
||||
janet_fixarity(argc, 2);
|
||||
JanetTable *table = janet_gettable(argv, 0);
|
||||
|
||||
@@ -65,12 +65,12 @@ JANET_CORE_FN(cfun_tuple_brackets,
|
||||
|
||||
JANET_CORE_FN(cfun_tuple_slice,
|
||||
"(tuple/slice arrtup [,start=0 [,end=(length arrtup)]])",
|
||||
"Take a sub sequence of an array or tuple from index start "
|
||||
"inclusive to index end exclusive. If start or end are not provided, "
|
||||
"they default to 0 and the length of arrtup respectively. "
|
||||
"'start' and 'end' can also be negative to indicate indexing "
|
||||
"Take a sub-sequence of an array or tuple from index `start` "
|
||||
"inclusive to index `end` exclusive. If `start` or `end` are not provided, "
|
||||
"they default to 0 and the length of `arrtup`, respectively. "
|
||||
"`start` and `end` can also be negative to indicate indexing "
|
||||
"from the end of the input. Note that index -1 is synonymous with "
|
||||
"index '(length arrtup)' to allow a full negative slice range. "
|
||||
"index `(length arrtup)` to allow a full negative slice range. "
|
||||
"Returns the new tuple.") {
|
||||
JanetView view = janet_getindexed(argv, 0);
|
||||
JanetRange range = janet_getslice(argc, argv);
|
||||
@@ -96,7 +96,7 @@ JANET_CORE_FN(cfun_tuple_type,
|
||||
JANET_CORE_FN(cfun_tuple_sourcemap,
|
||||
"(tuple/sourcemap tup)",
|
||||
"Returns the sourcemap metadata attached to a tuple, "
|
||||
" which is another tuple (line, column).") {
|
||||
"which is another tuple (line, column).") {
|
||||
janet_fixarity(argc, 1);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
Janet contents[2];
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JANET_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Base 64 lookup table for digits */
|
||||
@@ -254,6 +258,7 @@ int32_t janet_kv_calchash(const JanetKV *kvs, int32_t len) {
|
||||
/* Calculate next power of 2. May overflow. If n is 0,
|
||||
* will return 0. */
|
||||
int32_t janet_tablen(int32_t n) {
|
||||
if (n < 0) return 0;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
@@ -734,6 +739,13 @@ int janet_checkint64(Janet x) {
|
||||
return janet_checkint64range(dval);
|
||||
}
|
||||
|
||||
int janet_checkuint64(Janet x) {
|
||||
if (!janet_checktype(x, JANET_NUMBER))
|
||||
return 0;
|
||||
double dval = janet_unwrap_number(x);
|
||||
return dval >= 0 && dval <= JANET_INTMAX_DOUBLE && dval == (uint64_t) dval;
|
||||
}
|
||||
|
||||
int janet_checksize(Janet x) {
|
||||
if (!janet_checktype(x, JANET_NUMBER))
|
||||
return 0;
|
||||
@@ -789,11 +801,6 @@ int32_t janet_sorted_keys(const JanetKV *dict, int32_t cap, int32_t *index_buffe
|
||||
|
||||
/* Clock shims for various platforms */
|
||||
#ifdef JANET_GETTIME
|
||||
/* For macos */
|
||||
#ifdef JANET_APPLE
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
#ifdef JANET_WINDOWS
|
||||
int janet_gettime(struct timespec *spec) {
|
||||
FILETIME ftime;
|
||||
@@ -806,7 +813,10 @@ int janet_gettime(struct timespec *spec) {
|
||||
spec->tv_nsec = wintime % 10000000LL * 100;
|
||||
return 0;
|
||||
}
|
||||
#elif defined(JANET_APPLE)
|
||||
/* clock_gettime() wasn't available on Mac until 10.12. */
|
||||
#elif defined(JANET_APPLE) && !defined(MAC_OS_X_VERSION_10_12)
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
int janet_gettime(struct timespec *spec) {
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
@@ -874,6 +884,35 @@ int janet_cryptorand(uint8_t *out, size_t n) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Dynamic library loading */
|
||||
|
||||
char *get_processed_name(const char *name) {
|
||||
if (name[0] == '.') return (char *) name;
|
||||
const char *c;
|
||||
for (c = name; *c; c++) {
|
||||
if (*c == '/') return (char *) name;
|
||||
}
|
||||
size_t l = (size_t)(c - name);
|
||||
char *ret = janet_malloc(l + 3);
|
||||
if (NULL == ret) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
ret[0] = '.';
|
||||
ret[1] = '/';
|
||||
memcpy(ret + 2, name, l + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(JANET_WINDOWS)
|
||||
static char error_clib_buf[256];
|
||||
char *error_clib(void) {
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
error_clib_buf, sizeof(error_clib_buf), NULL);
|
||||
error_clib_buf[strlen(error_clib_buf) - 1] = '\0';
|
||||
return error_clib_buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Alloc function macro fills */
|
||||
void *(janet_malloc)(size_t size) {
|
||||
|
||||
@@ -31,6 +31,16 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef JANET_EV
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#if !defined(JANET_REDUCED_OS) || !defined(JANET_SINGLE_THREADED)
|
||||
#include <time.h>
|
||||
@@ -121,6 +131,31 @@ int janet_gettime(struct timespec *spec);
|
||||
#define strdup(x) _strdup(x)
|
||||
#endif
|
||||
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||
* with native code. */
|
||||
#if defined(JANET_NO_DYNAMIC_MODULES)
|
||||
typedef int Clib;
|
||||
#define load_clib(name) ((void) name, 0)
|
||||
#define symbol_clib(lib, sym) ((void) lib, (void) sym, NULL)
|
||||
#define error_clib() "dynamic libraries not supported"
|
||||
#define free_clib(c) ((void) (c), 0)
|
||||
#elif defined(JANET_WINDOWS)
|
||||
#include <windows.h>
|
||||
typedef HINSTANCE Clib;
|
||||
#define load_clib(name) LoadLibrary((name))
|
||||
#define free_clib(c) FreeLibrary((c))
|
||||
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
|
||||
char *error_clib(void);
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
typedef void *Clib;
|
||||
#define load_clib(name) dlopen((name), RTLD_NOW)
|
||||
#define free_clib(lib) dlclose((lib))
|
||||
#define symbol_clib(lib, sym) dlsym((lib), (sym))
|
||||
#define error_clib() dlerror()
|
||||
#endif
|
||||
char *get_processed_name(const char *name);
|
||||
|
||||
#define RETRY_EINTR(RC, CALL) do { (RC) = CALL; } while((RC) < 0 && errno == EINTR)
|
||||
|
||||
/* Initialize builtin libraries */
|
||||
@@ -159,5 +194,8 @@ void janet_lib_ev(JanetTable *env);
|
||||
void janet_ev_mark(void);
|
||||
int janet_make_pipe(JanetHandle handles[2], int mode);
|
||||
#endif
|
||||
#ifdef JANET_FFI
|
||||
void janet_lib_ffi(JanetTable *env);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -163,6 +163,14 @@ extern "C" {
|
||||
#define JANET_DYNAMIC_MODULES
|
||||
#endif
|
||||
|
||||
/* Enable or disable the FFI library. Currently, FFI only enabled on
|
||||
* x86-64, non-windows operating systems. */
|
||||
#ifndef JANET_NO_FFI
|
||||
#if !defined(JANET_WINDOWS) && (defined(__x86_64__) || defined(_M_X64))
|
||||
#define JANET_FFI
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable or disable the assembler. Enabled by default. */
|
||||
#ifndef JANET_NO_ASSEMBLER
|
||||
#define JANET_ASSEMBLER
|
||||
@@ -299,10 +307,10 @@ typedef struct {
|
||||
JANET_CURRENT_CONFIG_BITS })
|
||||
#endif
|
||||
|
||||
/* What to do when out of memory */
|
||||
#ifndef JANET_OUT_OF_MEMORY
|
||||
#include <stdio.h>
|
||||
#define JANET_OUT_OF_MEMORY do { fprintf(stderr, "janet out of memory\n"); exit(1); } while (0)
|
||||
/* Some extra includes if EV is enabled */
|
||||
#ifdef JANET_EV
|
||||
typedef struct JanetOSMutex JanetOSMutex;
|
||||
typedef struct JanetOSRWLock JanetOSRWLock;
|
||||
#endif
|
||||
|
||||
/***** END SECTION CONFIG *****/
|
||||
@@ -322,23 +330,10 @@ typedef struct {
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Some extra includes if EV is enabled */
|
||||
#ifdef JANET_EV
|
||||
#ifdef JANET_WINDOWS
|
||||
typedef struct JanetDudCriticalSection {
|
||||
/* Avoid including windows.h here - instead, create a structure of the same size */
|
||||
/* Needs to be same size as crtical section see WinNT.h for CRITCIAL_SECTION definition */
|
||||
void *debug_info;
|
||||
long lock_count;
|
||||
long recursion_count;
|
||||
void *owning_thread;
|
||||
void *lock_semaphore;
|
||||
unsigned long spin_count;
|
||||
} JanetOSMutex;
|
||||
#else
|
||||
#include <pthread.h>
|
||||
typedef pthread_mutex_t JanetOSMutex;
|
||||
#endif
|
||||
|
||||
/* What to do when out of memory */
|
||||
#ifndef JANET_OUT_OF_MEMORY
|
||||
#define JANET_OUT_OF_MEMORY do { fprintf(stderr, "janet out of memory\n"); exit(1); } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef JANET_BSD
|
||||
@@ -849,6 +844,7 @@ JANET_API Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer);
|
||||
|
||||
JANET_API int janet_checkint(Janet x);
|
||||
JANET_API int janet_checkint64(Janet x);
|
||||
JANET_API int janet_checkuint64(Janet x);
|
||||
JANET_API int janet_checksize(Janet x);
|
||||
JANET_API JanetAbstract janet_checkabstract(Janet x, const JanetAbstractType *at);
|
||||
#define janet_checkintrange(x) ((x) >= INT32_MIN && (x) <= INT32_MAX && (x) == (int32_t)(x))
|
||||
@@ -1180,17 +1176,6 @@ typedef struct {
|
||||
Janet payload;
|
||||
} JanetTryState;
|
||||
|
||||
/* Thread types */
|
||||
#ifdef JANET_THREADS
|
||||
typedef struct JanetThread JanetThread;
|
||||
typedef struct JanetMailbox JanetMailbox;
|
||||
struct JanetThread {
|
||||
JanetMailbox *mailbox;
|
||||
JanetTable *encode;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/***** END SECTION TYPES *****/
|
||||
|
||||
/***** START SECTION OPCODES *****/
|
||||
@@ -1379,11 +1364,19 @@ JANET_API void *janet_abstract_threaded(const JanetAbstractType *atype, size_t s
|
||||
JANET_API int32_t janet_abstract_incref(void *abst);
|
||||
JANET_API int32_t janet_abstract_decref(void *abst);
|
||||
|
||||
/* Expose some OS sync primitives to make portable abstract types easier to implement */
|
||||
/* Expose some OS sync primitives */
|
||||
JANET_API size_t janet_os_mutex_size(void);
|
||||
JANET_API size_t janet_os_rwlock_size(void);
|
||||
JANET_API void janet_os_mutex_init(JanetOSMutex *mutex);
|
||||
JANET_API void janet_os_mutex_deinit(JanetOSMutex *mutex);
|
||||
JANET_API void janet_os_mutex_lock(JanetOSMutex *mutex);
|
||||
JANET_API void janet_os_mutex_unlock(JanetOSMutex *mutex);
|
||||
JANET_API void janet_os_rwlock_init(JanetOSRWLock *rwlock);
|
||||
JANET_API void janet_os_rwlock_deinit(JanetOSRWLock *rwlock);
|
||||
JANET_API void janet_os_rwlock_rlock(JanetOSRWLock *rwlock);
|
||||
JANET_API void janet_os_rwlock_wlock(JanetOSRWLock *rwlock);
|
||||
JANET_API void janet_os_rwlock_runlock(JanetOSRWLock *rwlock);
|
||||
JANET_API void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock);
|
||||
|
||||
/* Get last error from an IO operation */
|
||||
JANET_API Janet janet_ev_lasterr(void);
|
||||
@@ -1925,6 +1918,7 @@ JANET_API void *janet_getpointer(const Janet *argv, int32_t n);
|
||||
JANET_API int32_t janet_getnat(const Janet *argv, int32_t n);
|
||||
JANET_API int32_t janet_getinteger(const Janet *argv, int32_t n);
|
||||
JANET_API int64_t janet_getinteger64(const Janet *argv, int32_t n);
|
||||
JANET_API uint64_t janet_getuinteger64(const Janet *argv, int32_t n);
|
||||
JANET_API size_t janet_getsize(const Janet *argv, int32_t n);
|
||||
JANET_API JanetView janet_getindexed(const Janet *argv, int32_t n);
|
||||
JANET_API JanetByteView janet_getbytes(const Janet *argv, int32_t n);
|
||||
@@ -1972,7 +1966,6 @@ extern JANET_API const JanetAbstractType janet_file_type;
|
||||
#define JANET_FILE_CLOSED 32
|
||||
#define JANET_FILE_BINARY 64
|
||||
#define JANET_FILE_SERIALIZABLE 128
|
||||
#define JANET_FILE_PIPED 256
|
||||
#define JANET_FILE_NONIL 512
|
||||
|
||||
JANET_API Janet janet_makefile(FILE *f, int32_t flags);
|
||||
@@ -2079,16 +2072,6 @@ JANET_API int janet_scan_uint64(const uint8_t *str, int32_t len, uint64_t *out);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JANET_THREADS
|
||||
|
||||
extern JANET_API const JanetAbstractType janet_thread_type;
|
||||
|
||||
JANET_API int janet_thread_receive(Janet *msg_out, double timeout);
|
||||
JANET_API int janet_thread_send(JanetThread *thread, Janet msg, double timeout);
|
||||
JANET_API JanetThread *janet_thread_current(void);
|
||||
|
||||
#endif
|
||||
|
||||
/* Custom allocator support */
|
||||
JANET_API void *(janet_malloc)(size_t);
|
||||
JANET_API void *(janet_realloc)(void *, size_t);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021 Calvin Rose & contributors
|
||||
# Copyright (c) 2022 Calvin Rose & contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
@@ -50,5 +50,42 @@
|
||||
|
||||
(assert (= (hash 0) (hash (* -1 0))) "hash -0 same as hash 0")
|
||||
|
||||
# os/execute regressions
|
||||
(for i 0 10
|
||||
(assert (= i (os/execute [(dyn :executable) "-e" (string/format "(os/exit %d)" i)] :p)) (string "os/execute " i)))
|
||||
|
||||
# to/thru bug
|
||||
(def pattern
|
||||
(peg/compile
|
||||
'{:dd (sequence :d :d)
|
||||
:sep (set "/-")
|
||||
:date (sequence :dd :sep :dd)
|
||||
:wsep (some (set " \t"))
|
||||
:entry (group (sequence (capture :date) :wsep (capture :date)))
|
||||
:main (some (thru :entry))}))
|
||||
|
||||
(def alt-pattern
|
||||
(peg/compile
|
||||
'{:dd (sequence :d :d)
|
||||
:sep (set "/-")
|
||||
:date (sequence :dd :sep :dd)
|
||||
:wsep (some (set " \t"))
|
||||
:entry (group (sequence (capture :date) :wsep (capture :date)))
|
||||
:main (some (choice :entry 1))}))
|
||||
|
||||
(def text "1800-10-818-9-818 16/12\n17/12 19/12\n20/12 11/01")
|
||||
(assert (deep= (peg/match pattern text) (peg/match alt-pattern text)) "to/thru bug #971")
|
||||
|
||||
(assert-error
|
||||
"table rawget regression"
|
||||
(table/new -1))
|
||||
|
||||
# Named arguments
|
||||
(defn named-arguments
|
||||
[&named bob sally joe]
|
||||
(+ bob sally joe))
|
||||
|
||||
(assert (= 15 (named-arguments :bob 3 :sally 5 :joe 7)) "named arguments 1")
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
32
test/suite0012.janet
Normal file
32
test/suite0012.janet
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2022 Calvin Rose & contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
(import ./helper :prefix "" :exit true)
|
||||
(start-suite 12)
|
||||
|
||||
(var counter 0)
|
||||
(def thunk (delay (++ counter)))
|
||||
(assert (= (thunk) 1) "delay 1")
|
||||
(assert (= counter 1) "delay 2")
|
||||
(assert (= (thunk) 1) "delay 3")
|
||||
(assert (= counter 1) "delay 4")
|
||||
|
||||
(end-suite)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"quote"
|
||||
"quasiquote"
|
||||
"unquote"
|
||||
"upscope"
|
||||
"splice"]
|
||||
(all-bindings)))
|
||||
(def allsyms (dyn :allsyms))
|
||||
|
||||
Reference in New Issue
Block a user