mirror of
https://github.com/janet-lang/janet
synced 2025-04-29 06:03:21 +00:00
Merge branch 'master' into net
This commit is contained in:
commit
596111c988
3
.gitignore
vendored
3
.gitignore
vendored
@ -13,6 +13,9 @@ janet
|
|||||||
janet-*.tar.gz
|
janet-*.tar.gz
|
||||||
dist
|
dist
|
||||||
|
|
||||||
|
# jpm lockfile
|
||||||
|
lockfile.janet
|
||||||
|
|
||||||
# Kakoune (fzf via fd)
|
# Kakoune (fzf via fd)
|
||||||
.fdignore
|
.fdignore
|
||||||
|
|
||||||
|
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,9 +1,40 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased - ???
|
||||||
|
- Fix bug in `getline`.
|
||||||
|
- Add `sh-rule` and `sh-phony` to jpm's dialect of Janet.
|
||||||
|
- Change C api's `janet_formatb` -> `janet_formatbv`.
|
||||||
|
- Add C `janet_formatb` to C api.
|
||||||
|
- Add `edefer` macro to core.
|
||||||
|
- A struct/table literal/constructor with duplicate keys will use the last value given.
|
||||||
|
Previously, this was inconsistent between tables and structs, literals and constructor functions.
|
||||||
|
- Add debugger to core. The debugger functions are only available
|
||||||
|
in a debug repl, and are prefixed by a `.`.
|
||||||
|
- Add `sort-by` and `sorted-by` to core.
|
||||||
|
- Support UTF-8 escapes in strings via `\uXXXX` or `\UXXXXXX`.
|
||||||
|
- Add `math/erf`
|
||||||
|
- Add `math/erfc`
|
||||||
|
- Add `math/log1p`
|
||||||
|
- Add `math/next`
|
||||||
|
- Add os/umask
|
||||||
|
- Add os/perm-int
|
||||||
|
- Add os/perm-string
|
||||||
|
- Add :octal-permissions option for os/stat.
|
||||||
|
- Add `jpm repl` subcommand, as well as `post-deps` macro in project.janet files.
|
||||||
|
|
||||||
|
## 1.8.1 - 2020-03-31
|
||||||
|
- Fix bugs for big endian systems
|
||||||
|
- Fix 1.8.0 regression on BSDs
|
||||||
|
|
||||||
|
## 1.8.0 - 2020-03-29
|
||||||
|
- Add `reduce2`, `accumulate`, and `accumulate2`.
|
||||||
|
- Add lockfiles to `jpm` via `jpm make-lockfile` and `jpm load-lockfile`.
|
||||||
|
- Add `os/realpath` (Not supported on windows).
|
||||||
|
- Add `os/chmod`.
|
||||||
|
- Add `chr` macro.
|
||||||
- Allow `_` in the `match` macro to match anything without creating a binding
|
- Allow `_` in the `match` macro to match anything without creating a binding
|
||||||
or doing unification.
|
or doing unification. Also change behavior of matching nil.
|
||||||
- Add `:range-to` and `:down-to` verbs in the `loop` macro.
|
- Add `:range-to` and `:down-to` verbs in the `loop` macro.
|
||||||
- Fix `and` and `or` macros returning nil instead of false in some cases.
|
- Fix `and` and `or` macros returning nil instead of false in some cases.
|
||||||
- Allow matching successfully against nil values in the `match` macro.
|
- Allow matching successfully against nil values in the `match` macro.
|
||||||
@ -17,7 +48,8 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Correct arity for `marshal`
|
- Correct arity for `marshal`
|
||||||
- Add `flush` and `eflush`
|
- Add `flush` and `eflush`
|
||||||
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
|
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
|
||||||
- Fix possible segfault with malformed pegs.
|
- Fix bug in buffer/blit when using the offset-src argument.
|
||||||
|
- Fix segfault with malformed pegs.
|
||||||
|
|
||||||
## 1.7.0 - 2020-02-01
|
## 1.7.0 - 2020-02-01
|
||||||
- Remove `file/fileno` and `file/fdopen`.
|
- Remove `file/fileno` and `file/fdopen`.
|
||||||
|
10
Makefile
10
Makefile
@ -36,6 +36,7 @@ JANET_PATH?=$(LIBDIR)/janet
|
|||||||
MANPATH?=$(PREFIX)/share/man/man1/
|
MANPATH?=$(PREFIX)/share/man/man1/
|
||||||
PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
|
PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
|
||||||
DEBUGGER=gdb
|
DEBUGGER=gdb
|
||||||
|
SONAME_SETTER=-Wl,-soname,
|
||||||
|
|
||||||
CFLAGS:=$(CFLAGS) -std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fPIC -O2 -fvisibility=hidden
|
CFLAGS:=$(CFLAGS) -std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fPIC -O2 -fvisibility=hidden
|
||||||
LDFLAGS:=$(LDFLAGS) -rdynamic
|
LDFLAGS:=$(LDFLAGS) -rdynamic
|
||||||
@ -47,6 +48,7 @@ LDCONFIG:=ldconfig "$(LIBDIR)"
|
|||||||
UNAME:=$(shell uname -s)
|
UNAME:=$(shell uname -s)
|
||||||
ifeq ($(UNAME), Darwin)
|
ifeq ($(UNAME), Darwin)
|
||||||
CLIBS:=$(CLIBS) -ldl
|
CLIBS:=$(CLIBS) -ldl
|
||||||
|
SONAME_SETTER:=-Wl,-install_name,
|
||||||
LDCONFIG:=true
|
LDCONFIG:=true
|
||||||
else ifeq ($(UNAME), Linux)
|
else ifeq ($(UNAME), Linux)
|
||||||
CLIBS:=$(CLIBS) -lrt -ldl
|
CLIBS:=$(CLIBS) -lrt -ldl
|
||||||
@ -147,6 +149,8 @@ build/janet.c: build/janet_boot src/boot/boot.janet
|
|||||||
##### Amalgamation #####
|
##### Amalgamation #####
|
||||||
########################
|
########################
|
||||||
|
|
||||||
|
SONAME=libjanet.so.1.9
|
||||||
|
|
||||||
build/shell.c: src/mainclient/shell.c
|
build/shell.c: src/mainclient/shell.c
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
@ -166,7 +170,7 @@ $(JANET_TARGET): build/janet.o build/shell.o
|
|||||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(CLIBS)
|
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
$(JANET_LIBRARY): build/janet.o build/shell.o
|
$(JANET_LIBRARY): build/janet.o build/shell.o
|
||||||
$(CC) $(LDFLAGS) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
|
$(CC) $(LDFLAGS) $(CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
|
||||||
|
|
||||||
$(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
|
$(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
@ -229,8 +233,6 @@ build/doc.html: $(JANET_TARGET) tools/gendoc.janet
|
|||||||
##### Installation #####
|
##### Installation #####
|
||||||
########################
|
########################
|
||||||
|
|
||||||
SONAME=libjanet.so.1
|
|
||||||
|
|
||||||
.INTERMEDIATE: build/janet.pc
|
.INTERMEDIATE: build/janet.pc
|
||||||
build/janet.pc: $(JANET_TARGET)
|
build/janet.pc: $(JANET_TARGET)
|
||||||
echo 'prefix=$(PREFIX)' > $@
|
echo 'prefix=$(PREFIX)' > $@
|
||||||
@ -243,7 +245,7 @@ build/janet.pc: $(JANET_TARGET)
|
|||||||
echo "Description: Library for the Janet programming language." >> $@
|
echo "Description: Library for the Janet programming language." >> $@
|
||||||
$(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
|
$(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
|
||||||
echo 'Cflags: -I$${includedir}' >> $@
|
echo 'Cflags: -I$${includedir}' >> $@
|
||||||
echo 'Libs: -L$${libdir} -ljanet $(LDFLAGS)' >> $@
|
echo 'Libs: -L$${libdir} -ljanet' >> $@
|
||||||
echo 'Libs.private: $(CLIBS)' >> $@
|
echo 'Libs.private: $(CLIBS)' >> $@
|
||||||
|
|
||||||
install: $(JANET_TARGET) build/janet.pc
|
install: $(JANET_TARGET) build/janet.pc
|
||||||
|
14
README.md
14
README.md
@ -2,26 +2,28 @@
|
|||||||
|
|
||||||
[](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
|
[](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
|
||||||
[](https://travis-ci.org/janet-lang/janet)
|
[](https://travis-ci.org/janet-lang/janet)
|
||||||
[](https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml?)
|
[](https://builds.sr.ht/~bakpakin/janet/freebsd.yml?)
|
||||||
[](https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml?)
|
[](https://builds.sr.ht/~bakpakin/janet/openbsd.yml?)
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
|
||||||
|
|
||||||
**Janet** is a functional and imperative programming language and bytecode interpreter. It is a
|
**Janet** is a functional and imperative programming language and bytecode interpreter. It is a
|
||||||
modern lisp, but lists are replaced
|
modern lisp, but lists are replaced
|
||||||
by other data structures with better utility and performance (arrays, tables, structs, tuples).
|
by other data structures (arrays, tables (hash table), struct (immutable hash table), tuples).
|
||||||
The language also supports bridging to native code written in C, meta-programming with macros, and bytecode assembly.
|
The language also supports bridging to native code written in C, meta-programming with macros, and bytecode assembly.
|
||||||
|
|
||||||
There is a repl for trying out the language, as well as the ability
|
There is a repl for trying out the language, as well as the ability
|
||||||
to run script files. This client program is separate from the core runtime, so
|
to run script files. This client program is separate from the core runtime, so
|
||||||
janet can be embedded into other programs. Try janet in your browser at
|
Janet can be embedded into other programs. Try Janet in your browser at
|
||||||
[https://janet-lang.org](https://janet-lang.org).
|
[https://janet-lang.org](https://janet-lang.org).
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Use Cases
|
## Use Cases
|
||||||
|
|
||||||
Janet makes a good system scripting language, or a language to embed in other programs, like Lua or Guile.
|
Janet makes a good system scripting language, or a language to embed in other programs.
|
||||||
|
It's like Lua and Guile in that regard. It has more built-in functionality and a richer core language than
|
||||||
|
Lua, but smaller than GNU Guile or Python.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ Janet makes a good system scripting language, or a language to embed in other pr
|
|||||||
* Imperative programming as well as functional
|
* Imperative programming as well as functional
|
||||||
* REPL
|
* REPL
|
||||||
* Parsing Expression Grammars built in to the core library
|
* Parsing Expression Grammars built in to the core library
|
||||||
* 300+ functions and macros in the core library
|
* 400+ functions and macros in the core library
|
||||||
* Embedding Janet in other programs
|
* Embedding Janet in other programs
|
||||||
* Interactive environment with detailed stack traces
|
* Interactive environment with detailed stack traces
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ install:
|
|||||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
|
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
|
||||||
- build_win test-install
|
- build_win test-install
|
||||||
- set janet_outname=%appveyor_repo_tag_name%
|
- set janet_outname=%appveyor_repo_tag_name%
|
||||||
- if "%janet_outname%"=="" set janet_outname=v1.7.1
|
- if "%janet_outname%"=="" set /P janet_outname=<build\version.txt
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -49,8 +49,7 @@ artifacts:
|
|||||||
- name: "janet-$(janet_outname)-windows-%platform%"
|
- name: "janet-$(janet_outname)-windows-%platform%"
|
||||||
path: dist
|
path: dist
|
||||||
type: Zip
|
type: Zip
|
||||||
- path: "janet-$(janet_outname)-windows-installer.exe"
|
- path: "janet-$(janet_outname)-windows-%platform%-installer.exe"
|
||||||
name: "janet-$(janet_outname)-windows-%platform%-installer.exe"
|
|
||||||
type: File
|
type: File
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
204
auxbin/jpm
204
auxbin/jpm
@ -34,7 +34,7 @@
|
|||||||
(defmacro rule
|
(defmacro rule
|
||||||
"Add a rule to the rule graph."
|
"Add a rule to the rule graph."
|
||||||
[target deps & body]
|
[target deps & body]
|
||||||
~(,rule-impl ,target ,deps (fn [] nil ,;body)))
|
~(,rule-impl ,target ,deps (fn [] ,;body)))
|
||||||
|
|
||||||
(defmacro phony
|
(defmacro phony
|
||||||
"Add a phony rule to the rule graph. A phony rule will run every time
|
"Add a phony rule to the rule graph. A phony rule will run every time
|
||||||
@ -43,6 +43,16 @@
|
|||||||
[target deps & body]
|
[target deps & body]
|
||||||
~(,rule-impl ,target ,deps (fn [] nil ,;body) true))
|
~(,rule-impl ,target ,deps (fn [] nil ,;body) true))
|
||||||
|
|
||||||
|
(defmacro sh-rule
|
||||||
|
"Add a rule that invokes a shell command, and fails if the command returns non-zero."
|
||||||
|
[target deps & body]
|
||||||
|
~(,rule-impl ,target ,deps (fn [] (,assert (,zero? (,os/shell (,string ,;body)))))))
|
||||||
|
|
||||||
|
(defmacro sh-phony
|
||||||
|
"Add a phony rule that invokes a shell command, and fails if the command returns non-zero."
|
||||||
|
[target deps & body]
|
||||||
|
~(,rule-impl ,target ,deps (fn [] (,assert (,zero? (,os/shell (,string ,;body))))) true))
|
||||||
|
|
||||||
(defn add-dep
|
(defn add-dep
|
||||||
"Add a dependency to an existing rule. Useful for extending phony
|
"Add a dependency to an existing rule. Useful for extending phony
|
||||||
rules or extending the dependency graph of existing rules."
|
rules or extending the dependency graph of existing rules."
|
||||||
@ -177,24 +187,46 @@
|
|||||||
[into x]
|
[into x]
|
||||||
(when x
|
(when x
|
||||||
(proto-flatten into (table/getproto x))
|
(proto-flatten into (table/getproto x))
|
||||||
(loop [k :keys x]
|
(merge-into into x))
|
||||||
(put into k (x k))))
|
|
||||||
into)
|
into)
|
||||||
|
|
||||||
(defn import-rules
|
(defn make-jpm-env
|
||||||
"Import another file that defines more rules. This ruleset
|
"Build an environment table with jpm functions preloaded."
|
||||||
is merged into the current ruleset."
|
[&opt no-deps]
|
||||||
[path]
|
|
||||||
(def env (make-env))
|
(def env (make-env))
|
||||||
(unless (os/stat path :mode)
|
(put env :jpm-no-deps no-deps)
|
||||||
(error (string "cannot open " path)))
|
|
||||||
(loop [k :keys _env :when (symbol? k)]
|
(loop [k :keys _env :when (symbol? k)]
|
||||||
(unless ((_env k) :private) (put env k (_env k))))
|
(unless ((_env k) :private) (put env k (_env k))))
|
||||||
|
env)
|
||||||
|
|
||||||
|
(defn require-jpm
|
||||||
|
"Require a jpm file project file. This is different from a normal require
|
||||||
|
in that code is loaded in the jpm environment."
|
||||||
|
[path &opt no-deps]
|
||||||
|
(unless (os/stat path :mode)
|
||||||
|
(error (string "cannot open " path)))
|
||||||
|
(def env (make-jpm-env no-deps))
|
||||||
(def currenv (proto-flatten @{} (fiber/getenv (fiber/current))))
|
(def currenv (proto-flatten @{} (fiber/getenv (fiber/current))))
|
||||||
(loop [k :keys currenv :when (keyword? k)]
|
(loop [k :keys currenv :when (keyword? k)]
|
||||||
(put env k (currenv k)))
|
(put env k (currenv k)))
|
||||||
(dofile path :env env :exit true)
|
(dofile path :env env :exit true)
|
||||||
(when-let [rules (env :rules)] (merge-into (getrules) rules)))
|
env)
|
||||||
|
|
||||||
|
(defn import-rules
|
||||||
|
"Import another file that defines more rules. This ruleset
|
||||||
|
is merged into the current ruleset."
|
||||||
|
[path &opt no-deps]
|
||||||
|
(def env (require-jpm path no-deps))
|
||||||
|
(when-let [rules (env :rules)] (merge-into (getrules) rules))
|
||||||
|
env)
|
||||||
|
|
||||||
|
(defmacro post-deps
|
||||||
|
"Run code at the top level if jpm dependencies are installed. Build
|
||||||
|
code that imports dependencies should be wrapped with this macro, as project.janet
|
||||||
|
needs to be able to run successfully even without dependencies installed."
|
||||||
|
[& body]
|
||||||
|
(unless (dyn :jpm-no-deps)
|
||||||
|
~',(reduce |(eval $1) nil body)))
|
||||||
|
|
||||||
#
|
#
|
||||||
# OS and shell helpers
|
# OS and shell helpers
|
||||||
@ -251,11 +283,7 @@
|
|||||||
If we can't create it, give a friendly error. Return true if created, false if
|
If we can't create it, give a friendly error. Return true if created, false if
|
||||||
existing. Throw an error if we can't create it."
|
existing. Throw an error if we can't create it."
|
||||||
[dir]
|
[dir]
|
||||||
(if (os/mkdir dir)
|
(os/mkdir dir))
|
||||||
true
|
|
||||||
(if (os/stat dir :mode)
|
|
||||||
false
|
|
||||||
(error (string "Could not create " dir " - this could be a permission issue.")))))
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# C Compilation
|
# C Compilation
|
||||||
@ -557,6 +585,15 @@ int main(int argc, const char **argv) {
|
|||||||
# Public utilities
|
# Public utilities
|
||||||
#
|
#
|
||||||
|
|
||||||
|
(defn parse
|
||||||
|
"Read a string of Janet source and parse out the first expression."
|
||||||
|
[src]
|
||||||
|
(let [p (parser/new)]
|
||||||
|
(:consume p src)
|
||||||
|
(if (= :error (:status p))
|
||||||
|
(error (string "Could not parse: " (parser/error p))))
|
||||||
|
(:produce p)))
|
||||||
|
|
||||||
(defn find-manifest-dir
|
(defn find-manifest-dir
|
||||||
"Get the path to the directory containing manifests for installed
|
"Get the path to the directory containing manifests for installed
|
||||||
packages."
|
packages."
|
||||||
@ -566,7 +603,7 @@ int main(int argc, const char **argv) {
|
|||||||
(defn find-manifest
|
(defn find-manifest
|
||||||
"Get the full path of a manifest file given a package name."
|
"Get the full path of a manifest file given a package name."
|
||||||
[name]
|
[name]
|
||||||
(string (find-manifest-dir) sep name ".txt"))
|
(string (find-manifest-dir) sep name ".jdn"))
|
||||||
|
|
||||||
(defn find-cache
|
(defn find-cache
|
||||||
"Return the path to the global cache."
|
"Return the path to the global cache."
|
||||||
@ -578,17 +615,14 @@ int main(int argc, const char **argv) {
|
|||||||
"Uninstall bundle named name"
|
"Uninstall bundle named name"
|
||||||
[name]
|
[name]
|
||||||
(def manifest (find-manifest name))
|
(def manifest (find-manifest name))
|
||||||
(def f (file/open manifest :r))
|
(when-with [f (file/open manifest)]
|
||||||
(unless f (print manifest " does not exist") (break))
|
(def man (parse (:read f :all)))
|
||||||
(loop [line :iterate (:read f :line)]
|
(each path (get man :paths [])
|
||||||
(def path ((string/split "\n" line) 0))
|
|
||||||
(def path ((string/split "\r" path) 0))
|
|
||||||
(print "removing " path)
|
(print "removing " path)
|
||||||
(rm path))
|
(rm path))
|
||||||
(:close f)
|
|
||||||
(print "removing " manifest)
|
(print "removing " manifest)
|
||||||
(rm manifest)
|
(rm manifest)
|
||||||
(print "Uninstalled."))
|
(print "Uninstalled.")))
|
||||||
|
|
||||||
(defn- rimraf
|
(defn- rimraf
|
||||||
"Hard delete directory tree"
|
"Hard delete directory tree"
|
||||||
@ -610,7 +644,7 @@ int main(int argc, const char **argv) {
|
|||||||
(defn install-git
|
(defn install-git
|
||||||
"Install a bundle from git. If the bundle is already installed, the bundle
|
"Install a bundle from git. If the bundle is already installed, the bundle
|
||||||
is reinistalled (but not rebuilt if artifacts are cached)."
|
is reinistalled (but not rebuilt if artifacts are cached)."
|
||||||
[repotab &opt recurse]
|
[repotab &opt recurse no-deps]
|
||||||
(def repo (if (string? repotab) repotab (repotab :repo)))
|
(def repo (if (string? repotab) repotab (repotab :repo)))
|
||||||
(def tag (unless (string? repotab) (repotab :tag)))
|
(def tag (unless (string? repotab) (repotab :tag)))
|
||||||
# prevent infinite recursion (very unlikely, but consider
|
# prevent infinite recursion (very unlikely, but consider
|
||||||
@ -655,7 +689,7 @@ int main(int argc, const char **argv) {
|
|||||||
(os/execute ["git" "reset" "--hard" tag] :p))
|
(os/execute ["git" "reset" "--hard" tag] :p))
|
||||||
(os/execute ["git" "submodule" "update" "--init" "--recursive"] :p)
|
(os/execute ["git" "submodule" "update" "--init" "--recursive"] :p)
|
||||||
(import-rules "./project.janet")
|
(import-rules "./project.janet")
|
||||||
(do-rule "install-deps")
|
(unless no-deps (do-rule "install-deps"))
|
||||||
(do-rule "build")
|
(do-rule "build")
|
||||||
(do-rule "install"))
|
(do-rule "install"))
|
||||||
([err] (print "Error building git repository dependency: " err)))
|
([err] (print "Error building git repository dependency: " err)))
|
||||||
@ -672,6 +706,49 @@ int main(int argc, const char **argv) {
|
|||||||
(mkdir destdir)
|
(mkdir destdir)
|
||||||
(copy src destdir)))
|
(copy src destdir)))
|
||||||
|
|
||||||
|
(defn- pslurp
|
||||||
|
"Like slurp, but with file/popen instead file/open. Also trims output"
|
||||||
|
[cmd]
|
||||||
|
(string/trim (with [f (file/popen cmd)] (:read f :all))))
|
||||||
|
|
||||||
|
(defn- make-lockfile
|
||||||
|
[&opt filename]
|
||||||
|
(default filename "lockfile.janet")
|
||||||
|
(def cwd (os/cwd))
|
||||||
|
(def packages @[])
|
||||||
|
# Read installed modules from manifests
|
||||||
|
(def mdir (find-manifest-dir))
|
||||||
|
(each man (os/dir mdir)
|
||||||
|
(def package (parse (slurp (string mdir sep man))))
|
||||||
|
(if (and (dictionary? package) (package :repo) (package :sha))
|
||||||
|
(array/push packages package)
|
||||||
|
(print "Cannot add local or malformed package " mdir sep man " to lockfile, skipping...")))
|
||||||
|
# Put in correct order, such that a package is preceded by all of its dependencies
|
||||||
|
(def ordered-packages @[])
|
||||||
|
(def resolved @{})
|
||||||
|
(while (< (length ordered-packages) (length packages))
|
||||||
|
(var made-progress false)
|
||||||
|
(each p packages
|
||||||
|
(def {:repo r :sha s :dependencies d} p)
|
||||||
|
(def dep-urls (map |(if (string? $) $ ($ :repo)) d))
|
||||||
|
(unless (resolved r)
|
||||||
|
(when (all resolved dep-urls)
|
||||||
|
(array/push ordered-packages {:repo r :sha s})
|
||||||
|
(set made-progress true)
|
||||||
|
(put resolved r true))))
|
||||||
|
(unless made-progress
|
||||||
|
(error (string/format "could not resolve package order for: %j"
|
||||||
|
(filter (complement resolved) (map |($ :repo) packages))))))
|
||||||
|
# Write to file
|
||||||
|
(with [f (file/open filename :w)] (with-dyns [:out f] (printf "%j" ordered-packages))))
|
||||||
|
|
||||||
|
(defn- load-lockfile
|
||||||
|
[&opt filename]
|
||||||
|
(default filename "lockfile.janet")
|
||||||
|
(def lockarray (parse (slurp filename)))
|
||||||
|
(each {:repo url :sha sha} lockarray
|
||||||
|
(install-git {:repo url :tag sha} nil true)))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Declaring Artifacts - used in project.janet, targets specifically
|
# Declaring Artifacts - used in project.janet, targets specifically
|
||||||
# tailored for janet.
|
# tailored for janet.
|
||||||
@ -756,13 +833,15 @@ int main(int argc, const char **argv) {
|
|||||||
is marshalled into bytecode which is then embedded in a final executable for distribution.\n\n
|
is marshalled into bytecode which is then embedded in a final executable for distribution.\n\n
|
||||||
This executable can be installed as well to the --binpath given."
|
This executable can be installed as well to the --binpath given."
|
||||||
[&keys {:install install :name name :entry entry :headers headers
|
[&keys {:install install :name name :entry entry :headers headers
|
||||||
:cflags cflags :lflags lflags}]
|
:cflags cflags :lflags lflags :deps deps}]
|
||||||
(def name (if is-win (string name ".exe") name))
|
(def name (if is-win (string name ".exe") name))
|
||||||
(def dest (string "build" sep name))
|
(def dest (string "build" sep name))
|
||||||
(create-executable @{:cflags cflags :lflags lflags} entry dest)
|
(create-executable @{:cflags cflags :lflags lflags} entry dest)
|
||||||
(add-dep "build" dest)
|
(add-dep "build" dest)
|
||||||
(when headers
|
(when headers
|
||||||
(each h headers (add-dep dest h)))
|
(each h headers (add-dep dest h)))
|
||||||
|
(when deps
|
||||||
|
(each d deps (add-dep dest d)))
|
||||||
(when install
|
(when install
|
||||||
(install-rule dest (dyn :binpath JANET_BINPATH))))
|
(install-rule dest (dyn :binpath JANET_BINPATH))))
|
||||||
|
|
||||||
@ -817,7 +896,15 @@ int main(int argc, const char **argv) {
|
|||||||
(phony "manifest" []
|
(phony "manifest" []
|
||||||
(print "generating " manifest "...")
|
(print "generating " manifest "...")
|
||||||
(mkdir manifests)
|
(mkdir manifests)
|
||||||
(spit manifest (string (string/join installed-files "\n") "\n")))
|
(def sha (pslurp "git rev-parse HEAD"))
|
||||||
|
(def url (pslurp "git remote get-url origin"))
|
||||||
|
(def man
|
||||||
|
{:sha (if-not (empty? sha) sha)
|
||||||
|
:repo (if-not (empty? url) url)
|
||||||
|
:dependencies (array/slice (get meta :dependencies []))
|
||||||
|
:paths installed-files})
|
||||||
|
(spit manifest (string/format "%j\n" man)))
|
||||||
|
|
||||||
(phony "install" ["uninstall" "build" "manifest"]
|
(phony "install" ["uninstall" "build" "manifest"]
|
||||||
(when (dyn :test)
|
(when (dyn :test)
|
||||||
(do-rule "test"))
|
(do-rule "test"))
|
||||||
@ -861,8 +948,8 @@ int main(int argc, const char **argv) {
|
|||||||
'(* "--" '(some (if-not "=" 1)) (+ (* "=" '(any 1)) -1))))
|
'(* "--" '(some (if-not "=" 1)) (+ (* "=" '(any 1)) -1))))
|
||||||
|
|
||||||
(defn- local-rule
|
(defn- local-rule
|
||||||
[rule]
|
[rule &opt no-deps]
|
||||||
(import-rules "./project.janet")
|
(import-rules "./project.janet" no-deps)
|
||||||
(do-rule rule))
|
(do-rule rule))
|
||||||
|
|
||||||
(defn- help
|
(defn- help
|
||||||
@ -891,6 +978,14 @@ Subcommands are:
|
|||||||
rules : list rules available with run.
|
rules : list rules available with run.
|
||||||
update-pkgs : Update the current package listing from the remote git repository selected.
|
update-pkgs : Update the current package listing from the remote git repository selected.
|
||||||
quickbin entry executable : Create an executable from a janet script with a main function.
|
quickbin entry executable : Create an executable from a janet script with a main function.
|
||||||
|
make-lockfile (lockfile) : Create a lockfile based on repositories in the cache. The
|
||||||
|
lockfile will record the exact versions of dependencies used to ensure a reproducible
|
||||||
|
build. Lockfiles are best used with applications, not libraries. The default lockfile
|
||||||
|
name is lockfile.janet.
|
||||||
|
load-lockfile (lockfile) : Install modules from a lockfile in a reproducible way. The
|
||||||
|
default lockfile name is lockfile.janet.
|
||||||
|
repl : Run a repl in the context of the current project.janet file. This lets you run rules and
|
||||||
|
otherwise debug the current project.janet file.
|
||||||
|
|
||||||
Keys are:
|
Keys are:
|
||||||
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH, $JANET_PATH, or (dyn :syspath)
|
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH, $JANET_PATH, or (dyn :syspath)
|
||||||
@ -904,15 +999,16 @@ Keys are:
|
|||||||
--pkglist : URL of git repository for package listing. Defaults to $JANET_PKGLIST or https://github.com/janet-lang/pkgs.git
|
--pkglist : URL of git repository for package listing. Defaults to $JANET_PKGLIST or https://github.com/janet-lang/pkgs.git
|
||||||
|
|
||||||
Flags are:
|
Flags are:
|
||||||
|
--nocolor : Disable color in the jpm repl.
|
||||||
--verbose : Print shell commands as they are executed.
|
--verbose : Print shell commands as they are executed.
|
||||||
--test : If passed to jpm install, runs tests before installing. Will run tests recursively on dependencies.
|
--test : If passed to jpm install, runs tests before installing. Will run tests recursively on dependencies.
|
||||||
`))
|
`))
|
||||||
|
|
||||||
(defn- show-help
|
(defn show-help
|
||||||
[]
|
[]
|
||||||
(print help))
|
(print help))
|
||||||
|
|
||||||
(defn- show-paths
|
(defn show-paths
|
||||||
[]
|
[]
|
||||||
(print "binpath: " (dyn :binpath JANET_BINPATH))
|
(print "binpath: " (dyn :binpath JANET_BINPATH))
|
||||||
(print "modpath: " (dyn :modpath JANET_MODPATH))
|
(print "modpath: " (dyn :modpath JANET_MODPATH))
|
||||||
@ -920,21 +1016,21 @@ Flags are:
|
|||||||
(print "headerpath: " (dyn :headerpath JANET_HEADERPATH))
|
(print "headerpath: " (dyn :headerpath JANET_HEADERPATH))
|
||||||
(print "syspath: " (dyn :syspath)))
|
(print "syspath: " (dyn :syspath)))
|
||||||
|
|
||||||
(defn- build
|
(defn build
|
||||||
[]
|
[]
|
||||||
(local-rule "build"))
|
(local-rule "build"))
|
||||||
|
|
||||||
(defn- clean
|
(defn clean
|
||||||
[]
|
[]
|
||||||
(local-rule "clean"))
|
(local-rule "clean"))
|
||||||
|
|
||||||
(defn- install
|
(defn install
|
||||||
[&opt repo]
|
[&opt repo]
|
||||||
(if repo
|
(if repo
|
||||||
(install-git repo)
|
(install-git repo)
|
||||||
(local-rule "install")))
|
(local-rule "install")))
|
||||||
|
|
||||||
(defn- test
|
(defn test
|
||||||
[]
|
[]
|
||||||
(local-rule "test"))
|
(local-rule "test"))
|
||||||
|
|
||||||
@ -944,25 +1040,46 @@ Flags are:
|
|||||||
(uninstall what)
|
(uninstall what)
|
||||||
(local-rule "uninstall")))
|
(local-rule "uninstall")))
|
||||||
|
|
||||||
(defn- deps
|
(defn deps
|
||||||
[]
|
[]
|
||||||
(local-rule "install-deps"))
|
(local-rule "install-deps" true))
|
||||||
|
|
||||||
(defn- list-rules
|
(defn list-rules
|
||||||
[]
|
[&opt ctx]
|
||||||
(import-rules "./project.janet")
|
(import-rules "./project.janet" true)
|
||||||
(def ks (sort (seq [k :keys (dyn :rules)] k)))
|
(def ks (sort (seq [k :keys (dyn :rules)] k)))
|
||||||
(each k ks (print k)))
|
(each k ks (print k)))
|
||||||
|
|
||||||
(defn- update-pkgs
|
(defn update-pkgs
|
||||||
[]
|
[]
|
||||||
(install-git (dyn :pkglist default-pkglist)))
|
(install-git (dyn :pkglist default-pkglist)))
|
||||||
|
|
||||||
(defn- quickbin
|
(defn quickbin
|
||||||
[input output]
|
[input output]
|
||||||
(create-executable @{} input output)
|
(create-executable @{} input output)
|
||||||
(do-rule output))
|
(do-rule output))
|
||||||
|
|
||||||
|
(defn jpm-repl
|
||||||
|
[]
|
||||||
|
(def env
|
||||||
|
(try
|
||||||
|
(require-jpm "./project.janet")
|
||||||
|
([err f]
|
||||||
|
(if (= "cannot open ./project.janet" err)
|
||||||
|
(put (make-jpm-env) :project {})
|
||||||
|
(propagate err f)))))
|
||||||
|
(setdyn :pretty-format (if-not (dyn :nocolor) "%.20Q" "%.20q"))
|
||||||
|
(setdyn :err-color (if-not (dyn :nocolor) true))
|
||||||
|
(def p (env :project))
|
||||||
|
(def name (p :name))
|
||||||
|
(if name (print "Project: " name))
|
||||||
|
(if-let [r (p :repo)] (print "Repository: " r))
|
||||||
|
(if-let [a (p :author)] (print "Author: " a))
|
||||||
|
(defn getchunk [buf p]
|
||||||
|
(def [line] (parser/where p))
|
||||||
|
(getline (string "jpm[" (or name "repl") "]:" line ":" (parser/state p :delimiters) "> ") buf env))
|
||||||
|
(repl getchunk nil env))
|
||||||
|
|
||||||
(def- subcommands
|
(def- subcommands
|
||||||
{"build" build
|
{"build" build
|
||||||
"clean" clean
|
"clean" clean
|
||||||
@ -971,12 +1088,15 @@ Flags are:
|
|||||||
"test" test
|
"test" test
|
||||||
"help" help
|
"help" help
|
||||||
"deps" deps
|
"deps" deps
|
||||||
|
"repl" jpm-repl
|
||||||
"show-paths" show-paths
|
"show-paths" show-paths
|
||||||
"clear-cache" clear-cache
|
"clear-cache" clear-cache
|
||||||
"run" local-rule
|
"run" local-rule
|
||||||
"rules" list-rules
|
"rules" list-rules
|
||||||
"update-pkgs" update-pkgs
|
"update-pkgs" update-pkgs
|
||||||
"uninstall" uninstall-cmd
|
"uninstall" uninstall-cmd
|
||||||
|
"make-lockfile" make-lockfile
|
||||||
|
"load-lockfile" load-lockfile
|
||||||
"quickbin" quickbin})
|
"quickbin" quickbin})
|
||||||
|
|
||||||
(def- args (tuple/slice (dyn :args) 1))
|
(def- args (tuple/slice (dyn :args) 1))
|
||||||
|
@ -131,7 +131,7 @@ exit /b 0
|
|||||||
@rem Run the installer. (Installs to the local user with default settings)
|
@rem Run the installer. (Installs to the local user with default settings)
|
||||||
:INSTALL
|
:INSTALL
|
||||||
@echo Running Installer...
|
@echo Running Installer...
|
||||||
FOR %%a in (janet-*-windows-installer.exe) DO (
|
FOR %%a in (janet-*-windows-*-installer.exe) DO (
|
||||||
%%a /S /CurrentUser
|
%%a /S /CurrentUser
|
||||||
)
|
)
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
###
|
###
|
||||||
### A useful debugger library for Janet. Should be used
|
### A useful debugger library for Janet. Should be used
|
||||||
### inside a debug repl.
|
### inside a debug repl. This has been moved into the core.
|
||||||
###
|
###
|
||||||
|
|
||||||
(defn .fiber
|
(defn .fiber
|
||||||
"Get the current fiber being debugged."
|
"Get the current fiber being debugged."
|
||||||
[]
|
[]
|
||||||
(if-let [entry (dyn '_fiber)]
|
(dyn :fiber))
|
||||||
(entry :value)
|
|
||||||
(dyn :fiber)))
|
|
||||||
|
|
||||||
(defn .stack
|
(defn .stack
|
||||||
"Print the current fiber stack"
|
"Print the current fiber stack"
|
||||||
[]
|
[]
|
||||||
(print)
|
(print)
|
||||||
(debug/stacktrace (.fiber) "")
|
(with-dyns [:err-color false] (debug/stacktrace (.fiber) ""))
|
||||||
(print))
|
(print))
|
||||||
|
|
||||||
(defn .frame
|
(defn .frame
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# This file is invoked by build_win.bat
|
||||||
|
# Relevant configuration variables are set there.
|
||||||
|
|
||||||
Unicode True
|
Unicode True
|
||||||
|
|
||||||
!echo "Program Files: ${PROGRAMFILES}"
|
!echo "Program Files: ${PROGRAMFILES}"
|
||||||
@ -20,6 +23,9 @@ VIFileVersion "${PRODUCT_VERSION}"
|
|||||||
|
|
||||||
!if ${SIXTYFOUR} == "true"
|
!if ${SIXTYFOUR} == "true"
|
||||||
!define MULTIUSER_USE_PROGRAMFILES64
|
!define MULTIUSER_USE_PROGRAMFILES64
|
||||||
|
!define PLATNAME "x64"
|
||||||
|
!else
|
||||||
|
!define PLATNAME "x86"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
# Includes
|
# Includes
|
||||||
@ -36,12 +42,12 @@ Name "Janet"
|
|||||||
!define DOLLAR "$"
|
!define DOLLAR "$"
|
||||||
!ifdef CHECK_${DOLLAR}%APPVEYOR_REPO_TAG_NAME%
|
!ifdef CHECK_${DOLLAR}%APPVEYOR_REPO_TAG_NAME%
|
||||||
# We are not in the appveyor environment, use version name
|
# We are not in the appveyor environment, use version name
|
||||||
!define OUTNAME_PART v${VERSION}
|
!define OUTNAME_PART ${VERSION}
|
||||||
!else
|
!else
|
||||||
# We are in appveyor, use git tag name for installer
|
# We are in appveyor, use git tag name for installer
|
||||||
!define OUTNAME_PART ${OUTNAME}
|
!define OUTNAME_PART ${OUTNAME}
|
||||||
!endif
|
!endif
|
||||||
OutFile "janet-${OUTNAME_PART}-windows-installer.exe"
|
OutFile "janet-${OUTNAME_PART}-windows-${PLATNAME}-installer.exe"
|
||||||
|
|
||||||
# Some Configuration
|
# Some Configuration
|
||||||
!define APPNAME "Janet"
|
!define APPNAME "Janet"
|
||||||
|
10
janet.1
10
janet.1
@ -96,6 +96,10 @@ Delete everything before the cursor on the input line.
|
|||||||
.BR Ctrl\-W
|
.BR Ctrl\-W
|
||||||
Delete one word before the cursor.
|
Delete one word before the cursor.
|
||||||
|
|
||||||
|
.TP 16
|
||||||
|
.BR Ctrl\-G
|
||||||
|
Show documentation for the current symbol under the cursor.
|
||||||
|
|
||||||
.TP 16
|
.TP 16
|
||||||
.BR Alt\-B/Alt\-F
|
.BR Alt\-B/Alt\-F
|
||||||
Move cursor backwards and forwards one word.
|
Move cursor backwards and forwards one word.
|
||||||
@ -148,6 +152,12 @@ Read raw input from stdin and forgo prompt history and other readline-like featu
|
|||||||
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
|
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
|
||||||
arguments are executed before later ones.
|
arguments are executed before later ones.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-d
|
||||||
|
Enable debug mode. On all terminating signals as well the debug signal, this will
|
||||||
|
cause the debugger to come up in the REPL. Same as calling (setdyn :debug true) in a
|
||||||
|
default repl.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-n
|
.BR \-n
|
||||||
Disable ANSI colors in the repl. Has no effect if no repl is run.
|
Disable ANSI colors in the repl. Has no effect if no repl is run.
|
||||||
|
9
jpm.1
9
jpm.1
@ -24,6 +24,10 @@ More interesting are the local commands. For more information on jpm usage, see
|
|||||||
|
|
||||||
.SH FLAGS
|
.SH FLAGS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-\-nocolor
|
||||||
|
Disable color in the jpm repl.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-verbose
|
.BR \-\-verbose
|
||||||
Print detailed messages of what jpm is doing, including compilation commands and other shell commands.
|
Print detailed messages of what jpm is doing, including compilation commands and other shell commands.
|
||||||
@ -154,6 +158,11 @@ The main function is the entry point of the program and will receive command lin
|
|||||||
as function arguments. The entry file can import other modules, including native C modules, and
|
as function arguments. The entry file can import other modules, including native C modules, and
|
||||||
jpm will attempt to include the dependencies into the generated executable.
|
jpm will attempt to include the dependencies into the generated executable.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR repl
|
||||||
|
Load the current project.janet file and start a repl in it's environment. This lets a user better
|
||||||
|
debug the project file, as well as run rules manually.
|
||||||
|
|
||||||
.SH ENVIRONMENT
|
.SH ENVIRONMENT
|
||||||
|
|
||||||
.B JANET_PATH
|
.B JANET_PATH
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
project('janet', 'c',
|
project('janet', 'c',
|
||||||
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
|
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||||
version : '1.7.1-dev')
|
version : '1.9.0-dev')
|
||||||
|
|
||||||
# Global settings
|
# Global settings
|
||||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||||
@ -162,13 +162,15 @@ janetc = custom_target('janetc',
|
|||||||
output : 'janet.c',
|
output : 'janet.c',
|
||||||
capture : true,
|
capture : true,
|
||||||
command : [
|
command : [
|
||||||
janet_boot, '@CURRENT_SOURCE_DIR@',
|
janet_boot, meson.current_source_dir(),
|
||||||
'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path
|
'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path
|
||||||
])
|
])
|
||||||
|
|
||||||
libjanet = library('janet', janetc,
|
libjanet = library('janet', janetc,
|
||||||
include_directories : incdir,
|
include_directories : incdir,
|
||||||
dependencies : [m_dep, dl_dep, thread_dep],
|
dependencies : [m_dep, dl_dep, thread_dep],
|
||||||
|
version: meson.project_version(),
|
||||||
|
soversion: version_parts[0] + '.' + version_parts[1],
|
||||||
install : true)
|
install : true)
|
||||||
|
|
||||||
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
|
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
(def buf (buffer "(" name))
|
(def buf (buffer "(" name))
|
||||||
(while (< index arglen)
|
(while (< index arglen)
|
||||||
(buffer/push-string buf " ")
|
(buffer/push-string buf " ")
|
||||||
(buffer/format buf "%p" (in args index))
|
(buffer/format buf "%j" (in args index))
|
||||||
(set index (+ index 1)))
|
(set index (+ index 1)))
|
||||||
(array/push modifiers (string buf ")\n\n" docstr))
|
(array/push modifiers (string buf ")\n\n" docstr))
|
||||||
# Build return value
|
# Build return value
|
||||||
@ -79,8 +79,8 @@
|
|||||||
|
|
||||||
# Basic predicates
|
# Basic predicates
|
||||||
(defn nan? "Check if x is NaN" [x] (not= x x))
|
(defn nan? "Check if x is NaN" [x] (not= x x))
|
||||||
(defn even? "Check if x is even." [x] (= 0 (% x 2)))
|
(defn even? "Check if x is even." [x] (= 0 (mod x 2)))
|
||||||
(defn odd? "Check if x is odd." [x] (not= 0 (% x 2)))
|
(defn odd? "Check if x is odd." [x] (= 1 (mod x 2)))
|
||||||
(defn zero? "Check if x is zero." [x] (= x 0))
|
(defn zero? "Check if x is zero." [x] (= x 0))
|
||||||
(defn pos? "Check if x is greater than 0." [x] (> x 0))
|
(defn pos? "Check if x is greater than 0." [x] (> x 0))
|
||||||
(defn neg? "Check if x is less than 0." [x] (< x 0))
|
(defn neg? "Check if x is less than 0." [x] (< x 0))
|
||||||
@ -301,7 +301,19 @@
|
|||||||
,form
|
,form
|
||||||
(if (= (,fiber/status ,f) :dead)
|
(if (= (,fiber/status ,f) :dead)
|
||||||
,r
|
,r
|
||||||
(propagate ,r ,f)))))
|
(,propagate ,r ,f)))))
|
||||||
|
|
||||||
|
(defmacro edefer
|
||||||
|
"Run form after body in the case that body terminates abnormally (an error or user signal 0-4).
|
||||||
|
Otherwise, return last form in body."
|
||||||
|
[form & body]
|
||||||
|
(with-syms [f r]
|
||||||
|
~(do
|
||||||
|
(def ,f (,fiber/new (fn [] ,;body) :ti))
|
||||||
|
(def ,r (,resume ,f))
|
||||||
|
(if (= (,fiber/status ,f) :dead)
|
||||||
|
,r
|
||||||
|
(do ,form (,propagate ,r ,f))))))
|
||||||
|
|
||||||
(defmacro prompt
|
(defmacro prompt
|
||||||
"Set up a checkpoint that can be returned to. Tag should be a value
|
"Set up a checkpoint that can be returned to. Tag should be a value
|
||||||
@ -314,7 +326,14 @@
|
|||||||
(def [,target ,payload] ,res)
|
(def [,target ,payload] ,res)
|
||||||
(if (,= ,tag ,target)
|
(if (,= ,tag ,target)
|
||||||
,payload
|
,payload
|
||||||
(propagate ,res ,fib)))))
|
(,propagate ,res ,fib)))))
|
||||||
|
|
||||||
|
(defmacro chr
|
||||||
|
"Convert a string of length 1 to its byte (ascii) value at compile time."
|
||||||
|
[c]
|
||||||
|
(unless (and (string? c) (= (length c) 1))
|
||||||
|
(error (string/format "expected string of length 1, got %v" c)))
|
||||||
|
(c 0))
|
||||||
|
|
||||||
(defmacro label
|
(defmacro label
|
||||||
"Set a label point that is lexically scoped. Name should be a symbol
|
"Set a label point that is lexically scoped. Name should be a symbol
|
||||||
@ -460,7 +479,7 @@
|
|||||||
(for-template i start stop 1 < + body))
|
(for-template i start stop 1 < + body))
|
||||||
|
|
||||||
(defmacro eachk
|
(defmacro eachk
|
||||||
"loop over each key in ds. returns nil."
|
"Loop over each key in ds. Returns nil."
|
||||||
[x ds & body]
|
[x ds & body]
|
||||||
(keys-template x ds false body))
|
(keys-template x ds false body))
|
||||||
|
|
||||||
@ -482,7 +501,7 @@
|
|||||||
that define something to loop over. They are formatted like:\n\n
|
that define something to loop over. They are formatted like:\n\n
|
||||||
\tbinding :verb object/expression\n\n
|
\tbinding :verb object/expression\n\n
|
||||||
Where binding is a binding as passed to def, :verb is one of a set of keywords,
|
Where binding is a binding as passed to def, :verb is one of a set of keywords,
|
||||||
and object is any janet expression. The available verbs are:\n\n
|
and object is any expression. The available verbs are:\n\n
|
||||||
\t:iterate - repeatedly evaluate and bind to the expression while it is truthy.\n
|
\t:iterate - repeatedly evaluate and bind to the expression while it is truthy.\n
|
||||||
\t:range - loop over a range. The object should be two element tuple with a start
|
\t:range - loop over a range. The object should be two element tuple with a start
|
||||||
and end value, and an optional positive step. The range is half open, [start, end).\n
|
and end value, and an optional positive step. The range is half open, [start, end).\n
|
||||||
@ -641,7 +660,7 @@
|
|||||||
(defn last
|
(defn last
|
||||||
"Get the last element from an indexed data structure."
|
"Get the last element from an indexed data structure."
|
||||||
[xs]
|
[xs]
|
||||||
(in xs (- (length xs) 1)))
|
(get xs (- (length xs) 1)))
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -649,11 +668,7 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
(def sort
|
(defn- sort-part
|
||||||
"(sort xs [, by])\n\nSort an array in-place. Uses quick-sort and is not a stable sort."
|
|
||||||
(do
|
|
||||||
|
|
||||||
(defn part
|
|
||||||
[a lo hi by]
|
[a lo hi by]
|
||||||
(def pivot (in a hi))
|
(def pivot (in a hi))
|
||||||
(var i lo)
|
(var i lo)
|
||||||
@ -668,22 +683,39 @@
|
|||||||
(set (a i) pivot)
|
(set (a i) pivot)
|
||||||
i)
|
i)
|
||||||
|
|
||||||
(defn sort-help
|
(defn- sort-help
|
||||||
[a lo hi by]
|
[a lo hi by]
|
||||||
(when (> hi lo)
|
(when (> hi lo)
|
||||||
(def piv (part a lo hi by))
|
(def piv (sort-part a lo hi by))
|
||||||
(sort-help a lo (- piv 1) by)
|
(sort-help a lo (- piv 1) by)
|
||||||
(sort-help a (+ piv 1) hi by))
|
(sort-help a (+ piv 1) hi by))
|
||||||
a)
|
a)
|
||||||
|
|
||||||
(fn sort [a &opt by]
|
(defn sort
|
||||||
(sort-help a 0 (- (length a) 1) (or by <)))))
|
"Sort an array in-place. Uses quick-sort and is not a stable sort."
|
||||||
|
[a &opt by]
|
||||||
|
(sort-help a 0 (- (length a) 1) (or by <)))
|
||||||
|
|
||||||
|
(put _env 'sort-part nil)
|
||||||
|
(put _env 'sort-help nil)
|
||||||
|
|
||||||
|
(defn sort-by
|
||||||
|
"Returns a new sorted array that compares elements by invoking
|
||||||
|
a function on each element and comparing the result with <."
|
||||||
|
[f ind]
|
||||||
|
(sort ind (fn [x y] (< (f x) (f y)))))
|
||||||
|
|
||||||
(defn sorted
|
(defn sorted
|
||||||
"Returns a new sorted array without modifying the old one."
|
"Returns a new sorted array without modifying the old one."
|
||||||
[ind &opt by]
|
[ind &opt by]
|
||||||
(sort (array/slice ind) by))
|
(sort (array/slice ind) by))
|
||||||
|
|
||||||
|
(defn sorted-by
|
||||||
|
"Returns a new sorted array that compares elements by invoking
|
||||||
|
a function on each element and comparing the result with <."
|
||||||
|
[f ind]
|
||||||
|
(sorted ind (fn [x y] (< (f x) (f y)))))
|
||||||
|
|
||||||
(defn reduce
|
(defn reduce
|
||||||
"Reduce, also know as fold-left in many languages, transforms
|
"Reduce, also know as fold-left in many languages, transforms
|
||||||
an indexed type (array, tuple) with a function to produce a value."
|
an indexed type (array, tuple) with a function to produce a value."
|
||||||
@ -692,6 +724,45 @@
|
|||||||
(each x ind (set res (f res x)))
|
(each x ind (set res (f res x)))
|
||||||
res)
|
res)
|
||||||
|
|
||||||
|
(defn reduce2
|
||||||
|
"The 2 argument version of reduce that does not take an initialization value.
|
||||||
|
Instead the first element of the array is used for initialization."
|
||||||
|
[f ind]
|
||||||
|
(var k (next ind))
|
||||||
|
(if (= nil k) (break nil))
|
||||||
|
(var res (in ind k))
|
||||||
|
(set k (next ind k))
|
||||||
|
(while (not= nil k)
|
||||||
|
(set res (f res (in ind k)))
|
||||||
|
(set k (next ind k)))
|
||||||
|
res)
|
||||||
|
|
||||||
|
(defn accumulate
|
||||||
|
"Similar to reduce, but accumulates intermediate values into an array.
|
||||||
|
The last element in the array is what would be the return value from reduce.
|
||||||
|
The init value is not added to the array.
|
||||||
|
Returns a new array."
|
||||||
|
[f init ind]
|
||||||
|
(var res init)
|
||||||
|
(def ret (array/new (length ind)))
|
||||||
|
(each x ind (array/push ret (set res (f res x))))
|
||||||
|
ret)
|
||||||
|
|
||||||
|
(defn accumulate2
|
||||||
|
"The 2 argument version of accumulate that does not take an initialization value."
|
||||||
|
[f ind]
|
||||||
|
(var k (next ind))
|
||||||
|
(def ret (array/new (length ind)))
|
||||||
|
(if (= nil k) (break ret))
|
||||||
|
(var res (in ind k))
|
||||||
|
(array/push ret res)
|
||||||
|
(set k (next ind k))
|
||||||
|
(while (not= nil k)
|
||||||
|
(set res (f res (in ind k)))
|
||||||
|
(array/push ret res)
|
||||||
|
(set k (next ind k)))
|
||||||
|
ret)
|
||||||
|
|
||||||
(defn map
|
(defn map
|
||||||
"Map a function over every element in an indexed data structure and
|
"Map a function over every element in an indexed data structure and
|
||||||
return an array of the results."
|
return an array of the results."
|
||||||
@ -896,7 +967,7 @@
|
|||||||
(reduce fop x forms))
|
(reduce fop x forms))
|
||||||
|
|
||||||
(defmacro -?>
|
(defmacro -?>
|
||||||
"Short circuit threading macro. Inserts x as the last value in the first form
|
"Short circuit threading macro. Inserts x as the second value in the first form
|
||||||
in forms, and inserts the modified first form into the second form
|
in forms, and inserts the modified first form into the second form
|
||||||
in the same manner, and so on. The pipeline will return nil
|
in the same manner, and so on. The pipeline will return nil
|
||||||
if an intermediate value is nil.
|
if an intermediate value is nil.
|
||||||
@ -912,7 +983,7 @@
|
|||||||
(reduce fop x forms))
|
(reduce fop x forms))
|
||||||
|
|
||||||
(defmacro -?>>
|
(defmacro -?>>
|
||||||
"Threading macro. Inserts x as the last value in the first form
|
"Short circuit threading macro. Inserts x as the last value in the first form
|
||||||
in forms, and inserts the modified first form into the second form
|
in forms, and inserts the modified first form into the second form
|
||||||
in the same manner, and so on. The pipeline will return nil
|
in the same manner, and so on. The pipeline will return nil
|
||||||
if an intermediate value is nil.
|
if an intermediate value is nil.
|
||||||
@ -1411,10 +1482,10 @@
|
|||||||
###
|
###
|
||||||
|
|
||||||
(defn- env-walk
|
(defn- env-walk
|
||||||
[pred &opt env]
|
[pred &opt env local]
|
||||||
(default env (fiber/getenv (fiber/current)))
|
(default env (fiber/getenv (fiber/current)))
|
||||||
(def envs @[])
|
(def envs @[])
|
||||||
(do (var e env) (while e (array/push envs e) (set e (table/getproto e))))
|
(do (var e env) (while e (array/push envs e) (set e (table/getproto e)) (if local (break))))
|
||||||
(def ret-set @{})
|
(def ret-set @{})
|
||||||
(loop [envi :in envs
|
(loop [envi :in envs
|
||||||
k :keys envi
|
k :keys envi
|
||||||
@ -1423,22 +1494,24 @@
|
|||||||
(sort (keys ret-set)))
|
(sort (keys ret-set)))
|
||||||
|
|
||||||
(defn all-bindings
|
(defn all-bindings
|
||||||
"Get all symbols available in an enviroment. Defaults to the current
|
"Get all symbols available in an environment. Defaults to the current
|
||||||
fiber's environment."
|
fiber's environment. If local is truthy, will not show inherited bindings
|
||||||
[&opt env]
|
(from prototype tables)."
|
||||||
(env-walk symbol? env))
|
[&opt env local]
|
||||||
|
(env-walk symbol? env local))
|
||||||
|
|
||||||
(defn all-dynamics
|
(defn all-dynamics
|
||||||
"Get all dynamic bindings in an environment. Defaults to the current
|
"Get all dynamic bindings in an environment. Defaults to the current
|
||||||
fiber's environment."
|
fiber's environment. If local is truthy, will not show inherited bindings
|
||||||
[&opt env]
|
(from prototype tables)."
|
||||||
(env-walk keyword? env))
|
[&opt env local]
|
||||||
|
(env-walk keyword? env local))
|
||||||
|
|
||||||
(defn doc-format
|
(defn doc-format
|
||||||
"Reformat text to wrap at a given line."
|
"Reformat text to wrap at a given line."
|
||||||
[text]
|
[text &opt width]
|
||||||
|
|
||||||
(def maxcol (- (dyn :doc-width 80) 8))
|
(def maxcol (- (or width (dyn :doc-width 80)) 8))
|
||||||
(var buf @" ")
|
(var buf @" ")
|
||||||
(var word @"")
|
(var word @"")
|
||||||
(var current 0)
|
(var current 0)
|
||||||
@ -1630,7 +1703,7 @@
|
|||||||
ret)
|
ret)
|
||||||
|
|
||||||
(defn all
|
(defn all
|
||||||
"Returns true if all xs are truthy, otherwise the resulty of first
|
"Returns true if all xs are truthy, otherwise the result of first
|
||||||
falsey predicate value, (pred x)."
|
falsey predicate value, (pred x)."
|
||||||
[pred xs]
|
[pred xs]
|
||||||
(var ret true)
|
(var ret true)
|
||||||
@ -1844,8 +1917,9 @@
|
|||||||
(eflush))
|
(eflush))
|
||||||
|
|
||||||
(defn run-context
|
(defn run-context
|
||||||
"Run a context. This evaluates expressions of janet in an environment,
|
"Run a context. This evaluates expressions in an environment,
|
||||||
and is encapsulates the parsing, compilation, and evaluation.
|
and is encapsulates the parsing, compilation, and evaluation.
|
||||||
|
Returns (in environment :exit-value environment) when complete.
|
||||||
opts is a table or struct of options. The options are as follows:\n\n\t
|
opts is a table or struct of options. The options are as follows:\n\n\t
|
||||||
:chunks - callback to read into a buffer - default is getline\n\t
|
:chunks - callback to read into a buffer - default is getline\n\t
|
||||||
:on-parse-error - callback when parsing fails - default is bad-parse\n\t
|
:on-parse-error - callback when parsing fails - default is bad-parse\n\t
|
||||||
@ -2104,13 +2178,15 @@
|
|||||||
@{})
|
@{})
|
||||||
|
|
||||||
(defn dofile
|
(defn dofile
|
||||||
"Evaluate a file and return the resulting environment."
|
"Evaluate a file and return the resulting environment. :env, :expander, and
|
||||||
[path & args]
|
:evaluator are passed through to the underlying run-context call.
|
||||||
(def {:exit exit-on-error
|
If exit is true, any top level errors will trigger a call to (os/exit 1)
|
||||||
:source source
|
after printing the error."
|
||||||
|
[path &keys
|
||||||
|
{:exit exit
|
||||||
:env env
|
:env env
|
||||||
:expander expander
|
:expander expander
|
||||||
:evaluator evaluator} (table ;args))
|
:evaluator evaluator}]
|
||||||
(def f (if (= (type path) :core/file)
|
(def f (if (= (type path) :core/file)
|
||||||
path
|
path
|
||||||
(file/open path :rb)))
|
(file/open path :rb)))
|
||||||
@ -2122,11 +2198,11 @@
|
|||||||
(defn chunks [buf _] (file/read f 2048 buf))
|
(defn chunks [buf _] (file/read f 2048 buf))
|
||||||
(defn bp [&opt x y]
|
(defn bp [&opt x y]
|
||||||
(def ret (bad-parse x y))
|
(def ret (bad-parse x y))
|
||||||
(if exit-on-error (os/exit 1))
|
(if exit (os/exit 1))
|
||||||
ret)
|
ret)
|
||||||
(defn bc [&opt x y z]
|
(defn bc [&opt x y z]
|
||||||
(def ret (bad-compile x y z))
|
(def ret (bad-compile x y z))
|
||||||
(if exit-on-error (os/exit 1))
|
(if exit (os/exit 1))
|
||||||
ret)
|
ret)
|
||||||
(unless f
|
(unless f
|
||||||
(error (string "could not find file " path)))
|
(error (string "could not find file " path)))
|
||||||
@ -2138,7 +2214,7 @@
|
|||||||
:on-status (fn [f x]
|
:on-status (fn [f x]
|
||||||
(when (not= (fiber/status f) :dead)
|
(when (not= (fiber/status f) :dead)
|
||||||
(debug/stacktrace f x)
|
(debug/stacktrace f x)
|
||||||
(if exit-on-error (os/exit 1) (eflush))))
|
(if exit (os/exit 1) (eflush))))
|
||||||
:evaluator evaluator
|
:evaluator evaluator
|
||||||
:expander expander
|
:expander expander
|
||||||
:source (if path-is-file "<anonymous>" spath)}))
|
:source (if path-is-file "<anonymous>" spath)}))
|
||||||
@ -2199,18 +2275,171 @@
|
|||||||
any errors encountered at the top level in the module will cause (os/exit 1)
|
any errors encountered at the top level in the module will cause (os/exit 1)
|
||||||
to be called. Dynamic bindings will NOT be imported."
|
to be called. Dynamic bindings will NOT be imported."
|
||||||
[path & args]
|
[path & args]
|
||||||
(def argm (map (fn [x]
|
(def argm (map |(if (keyword? $) $ (string $)) args))
|
||||||
(if (keyword? x)
|
|
||||||
x
|
|
||||||
(string x)))
|
|
||||||
args))
|
|
||||||
(tuple import* (string path) ;argm))
|
(tuple import* (string path) ;argm))
|
||||||
|
|
||||||
(defmacro use
|
(defmacro use
|
||||||
"Similar to import, but imported bindings are not prefixed with a namespace
|
"Similar to import, but imported bindings are not prefixed with a namespace
|
||||||
identifier. Can also import multiple modules in one shot."
|
identifier. Can also import multiple modules in one shot."
|
||||||
[& modules]
|
[& modules]
|
||||||
~(do ,;(map (fn [x] ~(,import* ,(string x) :prefix "")) modules)))
|
~(do ,;(map |~(,import* ,(string $) :prefix "") modules)))
|
||||||
|
|
||||||
|
###
|
||||||
|
###
|
||||||
|
### Debugger
|
||||||
|
###
|
||||||
|
###
|
||||||
|
|
||||||
|
(defn .fiber
|
||||||
|
"Get the current fiber being debugged."
|
||||||
|
[]
|
||||||
|
(dyn :fiber))
|
||||||
|
|
||||||
|
(defn .signal
|
||||||
|
"Get the current signal being debugged."
|
||||||
|
[]
|
||||||
|
(dyn :signal))
|
||||||
|
|
||||||
|
(defn .stack
|
||||||
|
"Print the current fiber stack"
|
||||||
|
[]
|
||||||
|
(print)
|
||||||
|
(with-dyns [:err-color false] (debug/stacktrace (.fiber) (.signal)))
|
||||||
|
(print))
|
||||||
|
|
||||||
|
(defn .frame
|
||||||
|
"Show a stack frame"
|
||||||
|
[&opt n]
|
||||||
|
(def stack (debug/stack (.fiber)))
|
||||||
|
(in stack (or n 0)))
|
||||||
|
|
||||||
|
(defn .fn
|
||||||
|
"Get the current function"
|
||||||
|
[&opt n]
|
||||||
|
(in (.frame n) :function))
|
||||||
|
|
||||||
|
(defn .slots
|
||||||
|
"Get an array of slots in a stack frame"
|
||||||
|
[&opt n]
|
||||||
|
(in (.frame n) :slots))
|
||||||
|
|
||||||
|
(defn .slot
|
||||||
|
"Get the value of the nth slot."
|
||||||
|
[&opt nth frame-idx]
|
||||||
|
(in (.slots frame-idx) (or nth 0)))
|
||||||
|
|
||||||
|
(defn .disasm
|
||||||
|
"Gets the assembly for the current function."
|
||||||
|
[&opt n]
|
||||||
|
(def frame (.frame n))
|
||||||
|
(def func (frame :function))
|
||||||
|
(disasm func))
|
||||||
|
|
||||||
|
(defn .bytecode
|
||||||
|
"Get the bytecode for the current function."
|
||||||
|
[&opt n]
|
||||||
|
((.disasm n) 'bytecode))
|
||||||
|
|
||||||
|
(defn .ppasm
|
||||||
|
"Pretty prints the assembly for the current function"
|
||||||
|
[&opt n]
|
||||||
|
(def frame (.frame n))
|
||||||
|
(def func (frame :function))
|
||||||
|
(def dasm (disasm func))
|
||||||
|
(def bytecode (dasm 'bytecode))
|
||||||
|
(def pc (frame :pc))
|
||||||
|
(def sourcemap (dasm 'sourcemap))
|
||||||
|
(var last-loc [-2 -2])
|
||||||
|
(print "\n signal: " (.signal))
|
||||||
|
(print " function: " (dasm 'name) " [" (in dasm 'source "") "]")
|
||||||
|
(when-let [constants (dasm 'constants)]
|
||||||
|
(printf " constants: %.4q" constants))
|
||||||
|
(printf " slots: %.4q\n" (frame :slots))
|
||||||
|
(def padding (string/repeat " " 20))
|
||||||
|
(loop [i :range [0 (length bytecode)]
|
||||||
|
:let [instr (bytecode i)]]
|
||||||
|
(prin (if (= (tuple/type instr) :brackets) "*" " "))
|
||||||
|
(prin (if (= i pc) "> " " "))
|
||||||
|
(prinf "%.20s" (string (string/join (map string instr) " ") padding))
|
||||||
|
(when sourcemap
|
||||||
|
(let [[sl sc] (sourcemap i)
|
||||||
|
loc [sl sc]]
|
||||||
|
(when (not= loc last-loc)
|
||||||
|
(set last-loc loc)
|
||||||
|
(prin " # line " sl ", column " sc))))
|
||||||
|
(print))
|
||||||
|
(print))
|
||||||
|
|
||||||
|
(defn .source
|
||||||
|
"Show the source code for the function being debugged."
|
||||||
|
[&opt n]
|
||||||
|
(def frame (.frame n))
|
||||||
|
(def s (frame :source))
|
||||||
|
(def all-source (slurp s))
|
||||||
|
(print "\n" all-source "\n"))
|
||||||
|
|
||||||
|
(defn .breakall
|
||||||
|
"Set breakpoints on all instructions in the current function."
|
||||||
|
[&opt n]
|
||||||
|
(def fun (.fn n))
|
||||||
|
(def bytecode (.bytecode n))
|
||||||
|
(for i 0 (length bytecode)
|
||||||
|
(debug/fbreak fun i))
|
||||||
|
(print "Set " (length bytecode) " breakpoints in " fun))
|
||||||
|
|
||||||
|
(defn .clearall
|
||||||
|
"Clear all breakpoints on the current function."
|
||||||
|
[&opt n]
|
||||||
|
(def fun (.fn n))
|
||||||
|
(def bytecode (.bytecode n))
|
||||||
|
(for i 0 (length bytecode)
|
||||||
|
(debug/unfbreak fun i))
|
||||||
|
(print "Cleared " (length bytecode) " breakpoints in " fun))
|
||||||
|
|
||||||
|
(defn .break
|
||||||
|
"Set breakpoint at the current pc."
|
||||||
|
[]
|
||||||
|
(def frame (.frame))
|
||||||
|
(def fun (frame :function))
|
||||||
|
(def pc (frame :pc))
|
||||||
|
(debug/fbreak fun pc)
|
||||||
|
(print "Set breakpoint in " fun " at pc=" pc))
|
||||||
|
|
||||||
|
(defn .clear
|
||||||
|
"Clear the current breakpoint"
|
||||||
|
[]
|
||||||
|
(def frame (.frame))
|
||||||
|
(def fun (frame :function))
|
||||||
|
(def pc (frame :pc))
|
||||||
|
(debug/unfbreak fun pc)
|
||||||
|
(print "Cleared breakpoint in " fun " at pc=" pc))
|
||||||
|
|
||||||
|
(defn .next
|
||||||
|
"Go to the next breakpoint."
|
||||||
|
[&opt n]
|
||||||
|
(var res nil)
|
||||||
|
(for i 0 (or n 1)
|
||||||
|
(set res (resume (.fiber))))
|
||||||
|
res)
|
||||||
|
|
||||||
|
(defn .nextc
|
||||||
|
"Go to the next breakpoint, clearing the current breakpoint."
|
||||||
|
[&opt n]
|
||||||
|
(.clear)
|
||||||
|
(.next n))
|
||||||
|
|
||||||
|
(defn .step
|
||||||
|
"Execute the next n instructions."
|
||||||
|
[&opt n]
|
||||||
|
(var res nil)
|
||||||
|
(for i 0 (or n 1)
|
||||||
|
(set res (debug/step (.fiber))))
|
||||||
|
res)
|
||||||
|
|
||||||
|
(def- debugger-keys (filter (partial string/has-prefix? ".") (keys _env)))
|
||||||
|
(def- debugger-env @{})
|
||||||
|
(each k debugger-keys (put debugger-env k (_env k)) (put _env k nil))
|
||||||
|
(put _env 'debugger-keys nil)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -2226,7 +2455,11 @@
|
|||||||
the repl in."
|
the repl in."
|
||||||
[&opt chunks onsignal env]
|
[&opt chunks onsignal env]
|
||||||
(default env (make-env))
|
(default env (make-env))
|
||||||
(default chunks (fn [buf p] (getline (string "repl:"
|
(default chunks
|
||||||
|
(fn [buf p]
|
||||||
|
(getline
|
||||||
|
(string
|
||||||
|
"repl:"
|
||||||
((parser/where p) 0)
|
((parser/where p) 0)
|
||||||
":"
|
":"
|
||||||
(parser/state p :delimiters) "> ")
|
(parser/state p :delimiters) "> ")
|
||||||
@ -2240,13 +2473,14 @@
|
|||||||
(put nextenv :fiber f)
|
(put nextenv :fiber f)
|
||||||
(put nextenv :debug-level level)
|
(put nextenv :debug-level level)
|
||||||
(put nextenv :signal x)
|
(put nextenv :signal x)
|
||||||
|
(merge-into nextenv debugger-env)
|
||||||
(debug/stacktrace f x)
|
(debug/stacktrace f x)
|
||||||
(eflush)
|
(eflush)
|
||||||
(defn debugger-chunks [buf p]
|
(defn debugger-chunks [buf p]
|
||||||
(def status (parser/state p :delimiters))
|
(def status (parser/state p :delimiters))
|
||||||
(def c ((parser/where p) 0))
|
(def c ((parser/where p) 0))
|
||||||
(def prompt (string "debug[" level "]:" c ":" status "> "))
|
(def prpt (string "debug[" level "]:" c ":" status "> "))
|
||||||
(getline prompt buf nextenv))
|
(getline prpt buf nextenv))
|
||||||
(print "entering debug[" level "] - (quit) to exit")
|
(print "entering debug[" level "] - (quit) to exit")
|
||||||
(flush)
|
(flush)
|
||||||
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
|
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
|
||||||
@ -2266,6 +2500,8 @@
|
|||||||
:on-status (or onsignal (make-onsignal env 1))
|
:on-status (or onsignal (make-onsignal env 1))
|
||||||
:source "repl"}))
|
:source "repl"}))
|
||||||
|
|
||||||
|
(put _env 'debugger-env nil)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
### CLI Tool Main
|
### CLI Tool Main
|
||||||
@ -2309,6 +2545,7 @@
|
|||||||
(var *handleopts* true)
|
(var *handleopts* true)
|
||||||
(var *exit-on-error* true)
|
(var *exit-on-error* true)
|
||||||
(var *colorize* true)
|
(var *colorize* true)
|
||||||
|
(var *debug* false)
|
||||||
(var *compile-only* false)
|
(var *compile-only* false)
|
||||||
|
|
||||||
(if-let [jp (os/getenv "JANET_PATH")] (setdyn :syspath jp))
|
(if-let [jp (os/getenv "JANET_PATH")] (setdyn :syspath jp))
|
||||||
@ -2324,6 +2561,7 @@
|
|||||||
-v : Print the version string
|
-v : Print the version string
|
||||||
-s : Use raw stdin instead of getline like functionality
|
-s : Use raw stdin instead of getline like functionality
|
||||||
-e code : Execute a string of janet
|
-e code : Execute a string of janet
|
||||||
|
-d : Set the debug flag in the repl
|
||||||
-r : Enter the repl after running all scripts
|
-r : Enter the repl after running all scripts
|
||||||
-p : Keep on executing if there is a top level error (persistent)
|
-p : Keep on executing if there is a top level error (persistent)
|
||||||
-q : Hide prompt, logo, and repl output (quiet)
|
-q : Hide prompt, logo, and repl output (quiet)
|
||||||
@ -2356,7 +2594,8 @@
|
|||||||
"e" (fn [i &]
|
"e" (fn [i &]
|
||||||
(set *no-file* false)
|
(set *no-file* false)
|
||||||
(eval-string (in args (+ i 1)))
|
(eval-string (in args (+ i 1)))
|
||||||
2)})
|
2)
|
||||||
|
"d" (fn [&] (set *debug* true) 1)})
|
||||||
|
|
||||||
(defn- dohandler [n i &]
|
(defn- dohandler [n i &]
|
||||||
(def h (in handlers n))
|
(def h (in handlers n))
|
||||||
@ -2415,6 +2654,7 @@
|
|||||||
(file/flush stdout)
|
(file/flush stdout)
|
||||||
(file/read stdin :line buf))
|
(file/read stdin :line buf))
|
||||||
(def env (make-env))
|
(def env (make-env))
|
||||||
|
(if *debug* (put env :debug true))
|
||||||
(def getter (if *raw-stdin* getstdin getline))
|
(def getter (if *raw-stdin* getstdin getline))
|
||||||
(defn getchunk [buf p]
|
(defn getchunk [buf p]
|
||||||
(getter (prompter p) buf env))
|
(getter (prompter p) buf env))
|
||||||
@ -2435,7 +2675,7 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
(def root-env "The root environment used to create envionments with (make-env)" _env)
|
(def root-env "The root environment used to create environments with (make-env)" _env)
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(put _env 'boot/opts nil)
|
(put _env 'boot/opts nil)
|
||||||
@ -2483,9 +2723,10 @@
|
|||||||
|
|
||||||
# Create amalgamation
|
# Create amalgamation
|
||||||
|
|
||||||
|
(def feature-header "src/core/features.h")
|
||||||
|
|
||||||
(def local-headers
|
(def local-headers
|
||||||
["src/core/features.h"
|
["src/core/util.h"
|
||||||
"src/core/util.h"
|
|
||||||
"src/core/state.h"
|
"src/core/state.h"
|
||||||
"src/core/gc.h"
|
"src/core/gc.h"
|
||||||
"src/core/vector.h"
|
"src/core/vector.h"
|
||||||
@ -2540,21 +2781,23 @@
|
|||||||
(print "/* Generated from janet version " janet/version "-" janet/build " */")
|
(print "/* Generated from janet version " janet/version "-" janet/build " */")
|
||||||
(print "#define JANET_BUILD \"" janet/build "\"")
|
(print "#define JANET_BUILD \"" janet/build "\"")
|
||||||
(print ```#define JANET_AMALG```)
|
(print ```#define JANET_AMALG```)
|
||||||
(print ```#define _POSIX_C_SOURCE 200112L```)
|
|
||||||
(print ```#include "janet.h"```)
|
|
||||||
|
|
||||||
(defn do-one-flie
|
(defn do-one-file
|
||||||
[fname]
|
[fname]
|
||||||
(print "\n/* " fname " */")
|
(print "\n/* " fname " */")
|
||||||
(print "#line 0 \"" fname "\"\n")
|
(print "#line 0 \"" fname "\"\n")
|
||||||
(def source (slurp fname))
|
(def source (slurp fname))
|
||||||
(print (string/replace-all "\r" "" source)))
|
(print (string/replace-all "\r" "" source)))
|
||||||
|
|
||||||
|
(do-one-file feature-header)
|
||||||
|
|
||||||
|
(print ```#include "janet.h"```)
|
||||||
|
|
||||||
(each h local-headers
|
(each h local-headers
|
||||||
(do-one-flie h))
|
(do-one-file h))
|
||||||
|
|
||||||
(each s core-sources
|
(each s core-sources
|
||||||
(do-one-flie s))
|
(do-one-file s))
|
||||||
|
|
||||||
# Create C source file that contains images a uint8_t buffer. This
|
# Create C source file that contains images a uint8_t buffer. This
|
||||||
# can be compiled and linked statically into the main janet library
|
# can be compiled and linked statically into the main janet library
|
||||||
|
@ -27,10 +27,10 @@
|
|||||||
#define JANETCONF_H
|
#define JANETCONF_H
|
||||||
|
|
||||||
#define JANET_VERSION_MAJOR 1
|
#define JANET_VERSION_MAJOR 1
|
||||||
#define JANET_VERSION_MINOR 7
|
#define JANET_VERSION_MINOR 9
|
||||||
#define JANET_VERSION_PATCH 1
|
#define JANET_VERSION_PATCH 0
|
||||||
#define JANET_VERSION_EXTRA "-dev"
|
#define JANET_VERSION_EXTRA ""
|
||||||
#define JANET_VERSION "1.7.1-dev"
|
#define JANET_VERSION "1.9.0-dev"
|
||||||
|
|
||||||
/* #define JANET_BUILD "local" */
|
/* #define JANET_BUILD "local" */
|
||||||
|
|
||||||
|
@ -707,6 +707,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
|||||||
if (janet_indexed_view(x, &arr, &count)) {
|
if (janet_indexed_view(x, &arr, &count)) {
|
||||||
janet_asm_assert(&a, count == def->bytecode_length, "sourcemap must have the same length as the bytecode");
|
janet_asm_assert(&a, count == def->bytecode_length, "sourcemap must have the same length as the bytecode");
|
||||||
def->sourcemap = malloc(sizeof(JanetSourceMapping) * (size_t) count);
|
def->sourcemap = malloc(sizeof(JanetSourceMapping) * (size_t) count);
|
||||||
|
if (NULL == def->sourcemap) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
const Janet *tup;
|
const Janet *tup;
|
||||||
Janet entry = arr[i];
|
Janet entry = arr[i];
|
||||||
@ -730,6 +733,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
|||||||
/* Set environments */
|
/* Set environments */
|
||||||
def->environments =
|
def->environments =
|
||||||
realloc(def->environments, def->environments_length * sizeof(int32_t));
|
realloc(def->environments, def->environments_length * sizeof(int32_t));
|
||||||
|
if (NULL == def->environments) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
/* Verify the func def */
|
/* Verify the func def */
|
||||||
if (janet_verify(def)) {
|
if (janet_verify(def)) {
|
||||||
|
@ -334,13 +334,15 @@ static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
|
|||||||
} else {
|
} else {
|
||||||
length_src = src.len - offset_src;
|
length_src = src.len - offset_src;
|
||||||
}
|
}
|
||||||
int64_t last = ((int64_t) offset_dest - offset_src) + length_src;
|
int64_t last = (int64_t) offset_dest + length_src;
|
||||||
if (last > INT32_MAX)
|
if (last > INT32_MAX)
|
||||||
janet_panic("buffer blit out of range");
|
janet_panic("buffer blit out of range");
|
||||||
janet_buffer_ensure(dest, (int32_t) last, 2);
|
int32_t last32 = (int32_t) last;
|
||||||
if (last > dest->count) dest->count = (int32_t) last;
|
janet_buffer_ensure(dest, last32, 2);
|
||||||
|
if (last32 > dest->count) dest->count = last32;
|
||||||
if (length_src) {
|
if (length_src) {
|
||||||
if (same_buf) {
|
if (same_buf) {
|
||||||
|
/* janet_buffer_ensure may have invalidated src */
|
||||||
src.bytes = dest->data;
|
src.bytes = dest->data;
|
||||||
memmove(dest->data + offset_dest, src.bytes + offset_src, length_src);
|
memmove(dest->data + offset_dest, src.bytes + offset_src, length_src);
|
||||||
} else {
|
} else {
|
||||||
|
@ -212,6 +212,7 @@ JanetFuncDef *janet_funcdef_alloc(void) {
|
|||||||
def->environments = NULL;
|
def->environments = NULL;
|
||||||
def->constants = NULL;
|
def->constants = NULL;
|
||||||
def->bytecode = NULL;
|
def->bytecode = NULL;
|
||||||
|
def->closure_bitset = NULL;
|
||||||
def->flags = 0;
|
def->flags = 0;
|
||||||
def->slotcount = 0;
|
def->slotcount = 0;
|
||||||
def->arity = 0;
|
def->arity = 0;
|
||||||
|
@ -54,7 +54,7 @@ void janet_panicf(const char *format, ...) {
|
|||||||
while (format[len]) len++;
|
while (format[len]) len++;
|
||||||
janet_buffer_init(&buffer, len);
|
janet_buffer_init(&buffer, len);
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
janet_formatb(&buffer, format, args);
|
janet_formatbv(&buffer, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
ret = janet_string(buffer.data, buffer.count);
|
ret = janet_string(buffer.data, buffer.count);
|
||||||
janet_buffer_deinit(&buffer);
|
janet_buffer_deinit(&buffer);
|
||||||
@ -235,18 +235,20 @@ size_t janet_getsize(const Janet *argv, int32_t n) {
|
|||||||
|
|
||||||
int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
||||||
int32_t raw = janet_getinteger(argv, n);
|
int32_t raw = janet_getinteger(argv, n);
|
||||||
if (raw < 0) raw += length + 1;
|
int32_t not_raw = raw;
|
||||||
if (raw < 0 || raw > length)
|
if (not_raw < 0) not_raw += length + 1;
|
||||||
janet_panicf("%s index %d out of range [0,%d]", which, raw, length);
|
if (not_raw < 0 || not_raw > length)
|
||||||
return raw;
|
janet_panicf("%s index %d out of range [%d,%d]", which, raw, -length - 1, length);
|
||||||
|
return not_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which) {
|
||||||
int32_t raw = janet_getinteger(argv, n);
|
int32_t raw = janet_getinteger(argv, n);
|
||||||
if (raw < 0) raw += length;
|
int32_t not_raw = raw;
|
||||||
if (raw < 0 || raw > length)
|
if (not_raw < 0) not_raw += length;
|
||||||
janet_panicf("%s index %d out of range [0,%d)", which, raw, length);
|
if (not_raw < 0 || not_raw > length)
|
||||||
return raw;
|
janet_panicf("%s index %d out of range [%d,%d)", which, raw, -length, length);
|
||||||
|
return not_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
JanetView janet_getindexed(const Janet *argv, int32_t n) {
|
JanetView janet_getindexed(const Janet *argv, int32_t n) {
|
||||||
|
@ -102,6 +102,7 @@ void janetc_scope(JanetScope *s, JanetCompiler *c, int flags, const char *name)
|
|||||||
scope.bytecode_start = janet_v_count(c->buffer);
|
scope.bytecode_start = janet_v_count(c->buffer);
|
||||||
scope.flags = flags;
|
scope.flags = flags;
|
||||||
scope.parent = c->scope;
|
scope.parent = c->scope;
|
||||||
|
janetc_regalloc_init(&scope.ua);
|
||||||
/* Inherit slots */
|
/* Inherit slots */
|
||||||
if ((!(flags & JANET_SCOPE_FUNCTION)) && c->scope) {
|
if ((!(flags & JANET_SCOPE_FUNCTION)) && c->scope) {
|
||||||
janetc_regalloc_clone(&scope.ra, &(c->scope->ra));
|
janetc_regalloc_clone(&scope.ra, &(c->scope->ra));
|
||||||
@ -149,6 +150,7 @@ void janetc_popscope(JanetCompiler *c) {
|
|||||||
janet_v_free(oldscope->envs);
|
janet_v_free(oldscope->envs);
|
||||||
janet_v_free(oldscope->defs);
|
janet_v_free(oldscope->defs);
|
||||||
janetc_regalloc_deinit(&oldscope->ra);
|
janetc_regalloc_deinit(&oldscope->ra);
|
||||||
|
janetc_regalloc_deinit(&oldscope->ua);
|
||||||
/* Update pointer */
|
/* Update pointer */
|
||||||
if (newscope)
|
if (newscope)
|
||||||
newscope->child = NULL;
|
newscope->child = NULL;
|
||||||
@ -236,6 +238,11 @@ found:
|
|||||||
scope = scope->parent;
|
scope = scope->parent;
|
||||||
janet_assert(scope, "invalid scopes");
|
janet_assert(scope, "invalid scopes");
|
||||||
scope->flags |= JANET_SCOPE_ENV;
|
scope->flags |= JANET_SCOPE_ENV;
|
||||||
|
|
||||||
|
/* In the function scope, allocate the slot as an upvalue */
|
||||||
|
janetc_regalloc_touch(&scope->ua, ret.index);
|
||||||
|
|
||||||
|
/* Iterate through child scopes and make sure environment is propagated */
|
||||||
scope = scope->child;
|
scope = scope->child;
|
||||||
|
|
||||||
/* Propagate env up to current scope */
|
/* Propagate env up to current scope */
|
||||||
@ -737,6 +744,21 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
|
|||||||
def->flags |= JANET_FUNCDEF_FLAG_NEEDSENV;
|
def->flags |= JANET_FUNCDEF_FLAG_NEEDSENV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy upvalue bitset */
|
||||||
|
if (scope->ua.count) {
|
||||||
|
/* Number of u32s we need to create a bitmask for all slots */
|
||||||
|
int32_t numchunks = (def->slotcount + 31) >> 5;
|
||||||
|
uint32_t *chunks = malloc(sizeof(uint32_t) * numchunks);
|
||||||
|
if (NULL == chunks) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
memcpy(chunks, scope->ua.chunks, sizeof(uint32_t) * numchunks);
|
||||||
|
/* Register allocator preallocates some registers [240-255, high 16 bits of chunk index 7], we can ignore those. */
|
||||||
|
if (scope->ua.count > 7) chunks[7] &= 0xFFFFU;
|
||||||
|
def->closure_bitset = chunks;
|
||||||
|
def->flags |= JANET_FUNCDEF_FLAG_HASCLOBITSET;
|
||||||
|
}
|
||||||
|
|
||||||
/* Pop the scope */
|
/* Pop the scope */
|
||||||
janetc_popscope(c);
|
janetc_popscope(c);
|
||||||
|
|
||||||
|
@ -127,7 +127,10 @@ struct JanetScope {
|
|||||||
/* Regsiter allocator */
|
/* Regsiter allocator */
|
||||||
JanetcRegisterAllocator ra;
|
JanetcRegisterAllocator ra;
|
||||||
|
|
||||||
/* Referenced closure environents. The values at each index correspond
|
/* Upvalue allocator */
|
||||||
|
JanetcRegisterAllocator ua;
|
||||||
|
|
||||||
|
/* Referenced closure environments. The values at each index correspond
|
||||||
* to which index to get the environment from in the parent. The environment
|
* to which index to get the environment from in the parent. The environment
|
||||||
* that corresponds to the direct parent's stack will always have value 0. */
|
* that corresponds to the direct parent's stack will always have value 0. */
|
||||||
int32_t *envs;
|
int32_t *envs;
|
||||||
|
@ -435,7 +435,7 @@ static Janet janet_core_hash(int32_t argc, Janet *argv) {
|
|||||||
static Janet janet_core_getline(int32_t argc, Janet *argv) {
|
static Janet janet_core_getline(int32_t argc, Janet *argv) {
|
||||||
FILE *in = janet_dynfile("in", stdin);
|
FILE *in = janet_dynfile("in", stdin);
|
||||||
FILE *out = janet_dynfile("out", stdout);
|
FILE *out = janet_dynfile("out", stdout);
|
||||||
janet_arity(argc, 0, 2);
|
janet_arity(argc, 0, 3);
|
||||||
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
|
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
|
||||||
if (argc >= 1) {
|
if (argc >= 1) {
|
||||||
const char *prompt = (const char *) janet_getstring(argv, 0);
|
const char *prompt = (const char *) janet_getstring(argv, 0);
|
||||||
@ -646,7 +646,7 @@ static const JanetReg corelib_cfuns[] = {
|
|||||||
"getline", janet_core_getline,
|
"getline", janet_core_getline,
|
||||||
JDOC("(getline &opt prompt buf env)\n\n"
|
JDOC("(getline &opt prompt buf env)\n\n"
|
||||||
"Reads a line of input into a buffer, including the newline character, using a prompt. "
|
"Reads a line of input into a buffer, including the newline character, using a prompt. "
|
||||||
"An optional environment table can be provided for autocomplete. "
|
"An optional environment table can be provided for auto-complete. "
|
||||||
"Returns the modified buffer. "
|
"Returns the modified buffer. "
|
||||||
"Use this function to implement a simple interface for a terminal program.")
|
"Use this function to implement a simple interface for a terminal program.")
|
||||||
},
|
},
|
||||||
@ -680,7 +680,7 @@ static const JanetReg corelib_cfuns[] = {
|
|||||||
"\t:all:\tthe value of path verbatim\n"
|
"\t:all:\tthe value of path verbatim\n"
|
||||||
"\t:cur:\tthe current file, or (dyn :current-file)\n"
|
"\t:cur:\tthe current file, or (dyn :current-file)\n"
|
||||||
"\t:dir:\tthe directory containing the current file\n"
|
"\t:dir:\tthe directory containing the current file\n"
|
||||||
"\t:name:\tthe filename component of path, with extenion if given\n"
|
"\t:name:\tthe filename component of path, with extension if given\n"
|
||||||
"\t:native:\tthe extension used to load natives, .so or .dll\n"
|
"\t:native:\tthe extension used to load natives, .so or .dll\n"
|
||||||
"\t:sys:\tthe system path, or (syn :syspath)")
|
"\t:sys:\tthe system path, or (syn :syspath)")
|
||||||
},
|
},
|
||||||
@ -697,7 +697,7 @@ static const JanetReg corelib_cfuns[] = {
|
|||||||
{
|
{
|
||||||
"slice", janet_core_slice,
|
"slice", janet_core_slice,
|
||||||
JDOC("(slice x &opt start end)\n\n"
|
JDOC("(slice x &opt start end)\n\n"
|
||||||
"Extract a sub-range of an indexed data strutrue or byte sequence.")
|
"Extract a sub-range of an indexed data structure or byte sequence.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"signal", janet_core_signal,
|
"signal", janet_core_signal,
|
||||||
|
@ -29,4 +29,9 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Needed for realpath on linux */
|
||||||
|
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
|
||||||
|
#define _XOPEN_SOURCE 500
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -218,18 +218,79 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
|||||||
static void janet_env_detach(JanetFuncEnv *env) {
|
static void janet_env_detach(JanetFuncEnv *env) {
|
||||||
/* Check for closure environment */
|
/* Check for closure environment */
|
||||||
if (env) {
|
if (env) {
|
||||||
size_t s = sizeof(Janet) * (size_t) env->length;
|
janet_env_valid(env);
|
||||||
|
int32_t len = env->length;
|
||||||
|
size_t s = sizeof(Janet) * (size_t) len;
|
||||||
Janet *vmem = malloc(s);
|
Janet *vmem = malloc(s);
|
||||||
janet_vm_next_collection += (uint32_t) s;
|
janet_vm_next_collection += (uint32_t) s;
|
||||||
if (NULL == vmem) {
|
if (NULL == vmem) {
|
||||||
JANET_OUT_OF_MEMORY;
|
JANET_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
safe_memcpy(vmem, env->as.fiber->data + env->offset, s);
|
Janet *values = env->as.fiber->data + env->offset;
|
||||||
|
safe_memcpy(vmem, values, s);
|
||||||
|
uint32_t *bitset = janet_stack_frame(values)->func->def->closure_bitset;
|
||||||
|
if (bitset) {
|
||||||
|
/* Clear unneeded references in closure environment */
|
||||||
|
for (int32_t i = 0; i < len; i += 32) {
|
||||||
|
uint32_t mask = ~(bitset[i >> 5]);
|
||||||
|
int32_t maxj = i + 32 > len ? len : i + 32;
|
||||||
|
for (int32_t j = i; j < maxj; j++) {
|
||||||
|
if (mask & 1) vmem[j] = janet_wrap_nil();
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
env->offset = 0;
|
env->offset = 0;
|
||||||
env->as.values = vmem;
|
env->as.values = vmem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validate potentially untrusted func env (unmarshalled envs are difficult to verify) */
|
||||||
|
int janet_env_valid(JanetFuncEnv *env) {
|
||||||
|
if (env->offset < 0) {
|
||||||
|
int32_t real_offset = -(env->offset);
|
||||||
|
JanetFiber *fiber = env->as.fiber;
|
||||||
|
int32_t i = fiber->frame;
|
||||||
|
while (i > 0) {
|
||||||
|
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||||
|
if (real_offset == i &&
|
||||||
|
frame->env == env &&
|
||||||
|
frame->func &&
|
||||||
|
frame->func->def->slotcount == env->length) {
|
||||||
|
env->offset = real_offset;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
i = frame->prevframe;
|
||||||
|
}
|
||||||
|
/* Invalid, set to empty off-stack variant. */
|
||||||
|
env->offset = 0;
|
||||||
|
env->length = 0;
|
||||||
|
env->as.values = NULL;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach a fiber from the env if the target fiber has stopped mutating */
|
||||||
|
void janet_env_maybe_detach(JanetFuncEnv *env) {
|
||||||
|
/* Check for detachable closure envs */
|
||||||
|
janet_env_valid(env);
|
||||||
|
if (env->offset > 0) {
|
||||||
|
JanetFiberStatus s = janet_fiber_status(env->as.fiber);
|
||||||
|
int isFinished = s == JANET_STATUS_DEAD ||
|
||||||
|
s == JANET_STATUS_ERROR ||
|
||||||
|
s == JANET_STATUS_USER0 ||
|
||||||
|
s == JANET_STATUS_USER1 ||
|
||||||
|
s == JANET_STATUS_USER2 ||
|
||||||
|
s == JANET_STATUS_USER3 ||
|
||||||
|
s == JANET_STATUS_USER4;
|
||||||
|
if (isFinished) {
|
||||||
|
janet_env_detach(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a tail frame for a function */
|
/* Create a tail frame for a function */
|
||||||
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
@ -73,5 +73,7 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func);
|
|||||||
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func);
|
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func);
|
||||||
void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun);
|
void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun);
|
||||||
void janet_fiber_popframe(JanetFiber *fiber);
|
void janet_fiber_popframe(JanetFiber *fiber);
|
||||||
|
void janet_env_maybe_detach(JanetFuncEnv *env);
|
||||||
|
int janet_env_valid(JanetFuncEnv *env);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "symcache.h"
|
#include "symcache.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "fiber.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct JanetScratch {
|
struct JanetScratch {
|
||||||
@ -189,7 +190,10 @@ static void janet_mark_funcenv(JanetFuncEnv *env) {
|
|||||||
if (janet_gc_reachable(env))
|
if (janet_gc_reachable(env))
|
||||||
return;
|
return;
|
||||||
janet_gc_mark(env);
|
janet_gc_mark(env);
|
||||||
if (env->offset) {
|
/* If closure env references a dead fiber, we can just copy out the stack frame we need so
|
||||||
|
* we don't need to keep around the whole dead fiber. */
|
||||||
|
janet_env_maybe_detach(env);
|
||||||
|
if (env->offset > 0) {
|
||||||
/* On stack */
|
/* On stack */
|
||||||
janet_mark_fiber(env->as.fiber);
|
janet_mark_fiber(env->as.fiber);
|
||||||
} else {
|
} else {
|
||||||
@ -305,6 +309,7 @@ static void janet_deinit_block(JanetGCObject *mem) {
|
|||||||
free(def->constants);
|
free(def->constants);
|
||||||
free(def->bytecode);
|
free(def->bytecode);
|
||||||
free(def->sourcemap);
|
free(def->sourcemap);
|
||||||
|
free(def->closure_bitset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ static void it_u64_tostring(void *p, JanetBuffer *buffer) {
|
|||||||
janet_buffer_push_cstring(buffer, str);
|
janet_buffer_push_cstring(buffer, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JanetAbstractType it_s64_type = {
|
const JanetAbstractType janet_s64_type = {
|
||||||
"core/s64",
|
"core/s64",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -95,7 +95,7 @@ static const JanetAbstractType it_s64_type = {
|
|||||||
JANET_ATEND_HASH
|
JANET_ATEND_HASH
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JanetAbstractType it_u64_type = {
|
const JanetAbstractType janet_u64_type = {
|
||||||
"core/u64",
|
"core/u64",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -128,8 +128,8 @@ int64_t janet_unwrap_s64(Janet x) {
|
|||||||
}
|
}
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abst = janet_unwrap_abstract(x);
|
void *abst = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abst) == &it_s64_type ||
|
if (janet_abstract_type(abst) == &janet_s64_type ||
|
||||||
(janet_abstract_type(abst) == &it_u64_type))
|
(janet_abstract_type(abst) == &janet_u64_type))
|
||||||
return *(int64_t *)abst;
|
return *(int64_t *)abst;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -157,8 +157,8 @@ uint64_t janet_unwrap_u64(Janet x) {
|
|||||||
}
|
}
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abst = janet_unwrap_abstract(x);
|
void *abst = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abst) == &it_s64_type ||
|
if (janet_abstract_type(abst) == &janet_s64_type ||
|
||||||
(janet_abstract_type(abst) == &it_u64_type))
|
(janet_abstract_type(abst) == &janet_u64_type))
|
||||||
return *(uint64_t *)abst;
|
return *(uint64_t *)abst;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -170,19 +170,19 @@ uint64_t janet_unwrap_u64(Janet x) {
|
|||||||
JanetIntType janet_is_int(Janet x) {
|
JanetIntType janet_is_int(Janet x) {
|
||||||
if (!janet_checktype(x, JANET_ABSTRACT)) return JANET_INT_NONE;
|
if (!janet_checktype(x, JANET_ABSTRACT)) return JANET_INT_NONE;
|
||||||
const JanetAbstractType *at = janet_abstract_type(janet_unwrap_abstract(x));
|
const JanetAbstractType *at = janet_abstract_type(janet_unwrap_abstract(x));
|
||||||
return (at == &it_s64_type) ? JANET_INT_S64 :
|
return (at == &janet_s64_type) ? JANET_INT_S64 :
|
||||||
((at == &it_u64_type) ? JANET_INT_U64 :
|
((at == &janet_u64_type) ? JANET_INT_U64 :
|
||||||
JANET_INT_NONE);
|
JANET_INT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Janet janet_wrap_s64(int64_t x) {
|
Janet janet_wrap_s64(int64_t x) {
|
||||||
int64_t *box = janet_abstract(&it_s64_type, sizeof(int64_t));
|
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||||
*box = (int64_t)x;
|
*box = (int64_t)x;
|
||||||
return janet_wrap_abstract(box);
|
return janet_wrap_abstract(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
Janet janet_wrap_u64(uint64_t x) {
|
Janet janet_wrap_u64(uint64_t x) {
|
||||||
uint64_t *box = janet_abstract(&it_u64_type, sizeof(uint64_t));
|
uint64_t *box = janet_abstract(&janet_u64_type, sizeof(uint64_t));
|
||||||
*box = (uint64_t)x;
|
*box = (uint64_t)x;
|
||||||
return janet_wrap_abstract(box);
|
return janet_wrap_abstract(box);
|
||||||
}
|
}
|
||||||
@ -200,7 +200,7 @@ static Janet cfun_it_u64_new(int32_t argc, Janet *argv) {
|
|||||||
#define OPMETHOD(T, type, name, oper) \
|
#define OPMETHOD(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_arity(argc, 2, -1); \
|
janet_arity(argc, 2, -1); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[0]); \
|
*box = janet_unwrap_##type(argv[0]); \
|
||||||
for (int32_t i = 1; i < argc; i++) \
|
for (int32_t i = 1; i < argc; i++) \
|
||||||
*box oper##= janet_unwrap_##type(argv[i]); \
|
*box oper##= janet_unwrap_##type(argv[i]); \
|
||||||
@ -210,7 +210,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
#define OPMETHODINVERT(T, type, name, oper) \
|
#define OPMETHODINVERT(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_fixarity(argc, 2); \
|
janet_fixarity(argc, 2); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[1]); \
|
*box = janet_unwrap_##type(argv[1]); \
|
||||||
*box oper##= janet_unwrap_##type(argv[0]); \
|
*box oper##= janet_unwrap_##type(argv[0]); \
|
||||||
return janet_wrap_abstract(box); \
|
return janet_wrap_abstract(box); \
|
||||||
@ -219,7 +219,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
#define DIVMETHOD(T, type, name, oper) \
|
#define DIVMETHOD(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_arity(argc, 2, -1); \
|
janet_arity(argc, 2, -1); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[0]); \
|
*box = janet_unwrap_##type(argv[0]); \
|
||||||
for (int32_t i = 1; i < argc; i++) { \
|
for (int32_t i = 1; i < argc; i++) { \
|
||||||
T value = janet_unwrap_##type(argv[i]); \
|
T value = janet_unwrap_##type(argv[i]); \
|
||||||
@ -232,7 +232,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
#define DIVMETHODINVERT(T, type, name, oper) \
|
#define DIVMETHODINVERT(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_fixarity(argc, 2); \
|
janet_fixarity(argc, 2); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[1]); \
|
*box = janet_unwrap_##type(argv[1]); \
|
||||||
T value = janet_unwrap_##type(argv[0]); \
|
T value = janet_unwrap_##type(argv[0]); \
|
||||||
if (value == 0) janet_panic("division by zero"); \
|
if (value == 0) janet_panic("division by zero"); \
|
||||||
@ -243,7 +243,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
#define DIVMETHOD_SIGNED(T, type, name, oper) \
|
#define DIVMETHOD_SIGNED(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_arity(argc, 2, -1); \
|
janet_arity(argc, 2, -1); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[0]); \
|
*box = janet_unwrap_##type(argv[0]); \
|
||||||
for (int32_t i = 1; i < argc; i++) { \
|
for (int32_t i = 1; i < argc; i++) { \
|
||||||
T value = janet_unwrap_##type(argv[i]); \
|
T value = janet_unwrap_##type(argv[i]); \
|
||||||
@ -257,7 +257,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
#define DIVMETHODINVERT_SIGNED(T, type, name, oper) \
|
#define DIVMETHODINVERT_SIGNED(T, type, name, oper) \
|
||||||
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
||||||
janet_fixarity(argc, 2); \
|
janet_fixarity(argc, 2); \
|
||||||
T *box = janet_abstract(&it_##type##_type, sizeof(T)); \
|
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
|
||||||
*box = janet_unwrap_##type(argv[1]); \
|
*box = janet_unwrap_##type(argv[1]); \
|
||||||
T value = janet_unwrap_##type(argv[0]); \
|
T value = janet_unwrap_##type(argv[0]); \
|
||||||
if (value == 0) janet_panic("division by zero"); \
|
if (value == 0) janet_panic("division by zero"); \
|
||||||
@ -276,7 +276,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
|
|||||||
|
|
||||||
static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
|
static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, -1);
|
janet_arity(argc, 2, -1);
|
||||||
int64_t *box = janet_abstract(&it_s64_type, sizeof(int64_t));
|
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||||
*box = janet_unwrap_s64(argv[0]);
|
*box = janet_unwrap_s64(argv[0]);
|
||||||
for (int32_t i = 1; i < argc; i++) {
|
for (int32_t i = 1; i < argc; i++) {
|
||||||
int64_t value = janet_unwrap_s64(argv[i]);
|
int64_t value = janet_unwrap_s64(argv[i]);
|
||||||
@ -292,7 +292,7 @@ static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_it_s64_modi(int32_t argc, Janet *argv) {
|
static Janet cfun_it_s64_modi(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 2);
|
janet_fixarity(argc, 2);
|
||||||
int64_t *box = janet_abstract(&it_s64_type, sizeof(int64_t));
|
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
|
||||||
int64_t op1 = janet_unwrap_s64(argv[0]);
|
int64_t op1 = janet_unwrap_s64(argv[0]);
|
||||||
int64_t op2 = janet_unwrap_s64(argv[1]);
|
int64_t op2 = janet_unwrap_s64(argv[1]);
|
||||||
int64_t x = op1 % op2;
|
int64_t x = op1 % op2;
|
||||||
@ -441,8 +441,8 @@ static const JanetReg it_cfuns[] = {
|
|||||||
/* Module entry point */
|
/* Module entry point */
|
||||||
void janet_lib_inttypes(JanetTable *env) {
|
void janet_lib_inttypes(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, it_cfuns);
|
janet_core_cfuns(env, NULL, it_cfuns);
|
||||||
janet_register_abstract_type(&it_s64_type);
|
janet_register_abstract_type(&janet_s64_type);
|
||||||
janet_register_abstract_type(&it_u64_type);
|
janet_register_abstract_type(&janet_u64_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,16 +33,10 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct IOFile IOFile;
|
|
||||||
struct IOFile {
|
|
||||||
FILE *file;
|
|
||||||
int flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cfun_io_gc(void *p, size_t len);
|
static int cfun_io_gc(void *p, size_t len);
|
||||||
static int io_file_get(void *p, Janet key, Janet *out);
|
static int io_file_get(void *p, Janet key, Janet *out);
|
||||||
|
|
||||||
JanetAbstractType cfun_io_filetype = {
|
const JanetAbstractType janet_file_type = {
|
||||||
"core/file",
|
"core/file",
|
||||||
cfun_io_gc,
|
cfun_io_gc,
|
||||||
NULL,
|
NULL,
|
||||||
@ -90,7 +84,7 @@ static int checkflags(const uint8_t *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Janet makef(FILE *f, int flags) {
|
static Janet makef(FILE *f, int flags) {
|
||||||
IOFile *iof = (IOFile *) janet_abstract(&cfun_io_filetype, sizeof(IOFile));
|
JanetFile *iof = (JanetFile *) janet_abstract(&janet_file_type, sizeof(JanetFile));
|
||||||
iof->file = f;
|
iof->file = f;
|
||||||
iof->flags = flags;
|
iof->flags = flags;
|
||||||
return janet_wrap_abstract(iof);
|
return janet_wrap_abstract(iof);
|
||||||
@ -158,7 +152,7 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read up to n bytes into buffer. */
|
/* Read up to n bytes into buffer. */
|
||||||
static void read_chunk(IOFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
static void read_chunk(JanetFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
||||||
if (!(iof->flags & (JANET_FILE_READ | JANET_FILE_UPDATE)))
|
if (!(iof->flags & (JANET_FILE_READ | JANET_FILE_UPDATE)))
|
||||||
janet_panic("file is not readable");
|
janet_panic("file is not readable");
|
||||||
janet_buffer_extra(buffer, nBytesMax);
|
janet_buffer_extra(buffer, nBytesMax);
|
||||||
@ -172,7 +166,7 @@ static void read_chunk(IOFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
|
|||||||
/* Read a certain number of bytes into memory */
|
/* Read a certain number of bytes into memory */
|
||||||
static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, 3);
|
janet_arity(argc, 2, 3);
|
||||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||||
if (iof->flags & JANET_FILE_CLOSED) janet_panic("file is closed");
|
if (iof->flags & JANET_FILE_CLOSED) janet_panic("file is closed");
|
||||||
JanetBuffer *buffer;
|
JanetBuffer *buffer;
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
@ -212,7 +206,7 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
|
|||||||
/* Write bytes to a file */
|
/* Write bytes to a file */
|
||||||
static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
|
static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, -1);
|
janet_arity(argc, 1, -1);
|
||||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||||
if (iof->flags & JANET_FILE_CLOSED)
|
if (iof->flags & JANET_FILE_CLOSED)
|
||||||
janet_panic("file is closed");
|
janet_panic("file is closed");
|
||||||
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
||||||
@ -235,7 +229,7 @@ static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
|
|||||||
/* Flush the bytes in the file */
|
/* Flush the bytes in the file */
|
||||||
static Janet cfun_io_fflush(int32_t argc, Janet *argv) {
|
static Janet cfun_io_fflush(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||||
if (iof->flags & JANET_FILE_CLOSED)
|
if (iof->flags & JANET_FILE_CLOSED)
|
||||||
janet_panic("file is closed");
|
janet_panic("file is closed");
|
||||||
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
|
||||||
@ -248,7 +242,7 @@ static Janet cfun_io_fflush(int32_t argc, Janet *argv) {
|
|||||||
/* Cleanup a file */
|
/* Cleanup a file */
|
||||||
static int cfun_io_gc(void *p, size_t len) {
|
static int cfun_io_gc(void *p, size_t len) {
|
||||||
(void) len;
|
(void) len;
|
||||||
IOFile *iof = (IOFile *)p;
|
JanetFile *iof = (JanetFile *)p;
|
||||||
if (!(iof->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
|
if (!(iof->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
|
||||||
return fclose(iof->file);
|
return fclose(iof->file);
|
||||||
}
|
}
|
||||||
@ -258,7 +252,7 @@ static int cfun_io_gc(void *p, size_t len) {
|
|||||||
/* Close a file */
|
/* Close a file */
|
||||||
static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
|
static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||||
if (iof->flags & JANET_FILE_CLOSED)
|
if (iof->flags & JANET_FILE_CLOSED)
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
|
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
|
||||||
@ -282,7 +276,7 @@ static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
|
|||||||
/* Seek a file */
|
/* Seek a file */
|
||||||
static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
|
static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, 3);
|
janet_arity(argc, 2, 3);
|
||||||
IOFile *iof = janet_getabstract(argv, 0, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
|
||||||
if (iof->flags & JANET_FILE_CLOSED)
|
if (iof->flags & JANET_FILE_CLOSED)
|
||||||
janet_panic("file is closed");
|
janet_panic("file is closed");
|
||||||
long int offset = 0;
|
long int offset = 0;
|
||||||
@ -326,8 +320,8 @@ FILE *janet_dynfile(const char *name, FILE *def) {
|
|||||||
Janet x = janet_dyn(name);
|
Janet x = janet_dyn(name);
|
||||||
if (!janet_checktype(x, JANET_ABSTRACT)) return def;
|
if (!janet_checktype(x, JANET_ABSTRACT)) return def;
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abstract) != &cfun_io_filetype) return def;
|
if (janet_abstract_type(abstract) != &janet_file_type) return def;
|
||||||
IOFile *iofile = abstract;
|
JanetFile *iofile = abstract;
|
||||||
return iofile->file;
|
return iofile->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,9 +348,9 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
|||||||
break;
|
break;
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abstract) != &cfun_io_filetype)
|
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
IOFile *iofile = abstract;
|
JanetFile *iofile = abstract;
|
||||||
f = iofile->file;
|
f = iofile->file;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -421,9 +415,9 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
|||||||
break;
|
break;
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abstract) != &cfun_io_filetype)
|
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
IOFile *iofile = abstract;
|
JanetFile *iofile = abstract;
|
||||||
f = iofile->file;
|
f = iofile->file;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -470,8 +464,8 @@ static void janet_flusher(const char *name, FILE *dflt_file) {
|
|||||||
break;
|
break;
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abstract) != &cfun_io_filetype) break;
|
if (janet_abstract_type(abstract) != &janet_file_type) break;
|
||||||
IOFile *iofile = abstract;
|
JanetFile *iofile = abstract;
|
||||||
fflush(iofile->file);
|
fflush(iofile->file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -508,12 +502,12 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
|
|||||||
int32_t len = 0;
|
int32_t len = 0;
|
||||||
while (format[len]) len++;
|
while (format[len]) len++;
|
||||||
janet_buffer_init(&buffer, len);
|
janet_buffer_init(&buffer, len);
|
||||||
janet_formatb(&buffer, format, args);
|
janet_formatbv(&buffer, format, args);
|
||||||
if (xtype == JANET_ABSTRACT) {
|
if (xtype == JANET_ABSTRACT) {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abstract) != &cfun_io_filetype)
|
if (janet_abstract_type(abstract) != &janet_file_type)
|
||||||
break;
|
break;
|
||||||
IOFile *iofile = abstract;
|
JanetFile *iofile = abstract;
|
||||||
f = iofile->file;
|
f = iofile->file;
|
||||||
}
|
}
|
||||||
fwrite(buffer.data, buffer.count, 1, f);
|
fwrite(buffer.data, buffer.count, 1, f);
|
||||||
@ -521,7 +515,7 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JANET_BUFFER:
|
case JANET_BUFFER:
|
||||||
janet_formatb(janet_unwrap_buffer(x), format, args);
|
janet_formatbv(janet_unwrap_buffer(x), format, args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@ -660,7 +654,7 @@ static const JanetReg io_cfuns[] = {
|
|||||||
/* C API */
|
/* C API */
|
||||||
|
|
||||||
FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
|
FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
|
||||||
IOFile *iof = janet_getabstract(argv, n, &cfun_io_filetype);
|
JanetFile *iof = janet_getabstract(argv, n, &janet_file_type);
|
||||||
if (NULL != flags) *flags = iof->flags;
|
if (NULL != flags) *flags = iof->flags;
|
||||||
return iof->file;
|
return iof->file;
|
||||||
}
|
}
|
||||||
@ -670,11 +664,11 @@ Janet janet_makefile(FILE *f, int flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JanetAbstract janet_checkfile(Janet j) {
|
JanetAbstract janet_checkfile(Janet j) {
|
||||||
return janet_checkabstract(j, &cfun_io_filetype);
|
return janet_checkabstract(j, &janet_file_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *janet_unwrapfile(Janet j, int *flags) {
|
FILE *janet_unwrapfile(Janet j, int *flags) {
|
||||||
IOFile *iof = janet_unwrap_abstract(j);
|
JanetFile *iof = janet_unwrap_abstract(j);
|
||||||
if (NULL != flags) *flags = iof->flags;
|
if (NULL != flags) *flags = iof->flags;
|
||||||
return iof->file;
|
return iof->file;
|
||||||
}
|
}
|
||||||
|
252
src/core/marsh.c
252
src/core/marsh.c
@ -42,26 +42,26 @@ typedef struct {
|
|||||||
/* Lead bytes in marshaling protocol */
|
/* Lead bytes in marshaling protocol */
|
||||||
enum {
|
enum {
|
||||||
LB_REAL = 200,
|
LB_REAL = 200,
|
||||||
LB_NIL,
|
LB_NIL, /* 201 */
|
||||||
LB_FALSE,
|
LB_FALSE, /* 202 */
|
||||||
LB_TRUE,
|
LB_TRUE, /* 203 */
|
||||||
LB_FIBER,
|
LB_FIBER, /* 204 */
|
||||||
LB_INTEGER,
|
LB_INTEGER, /* 205 */
|
||||||
LB_STRING,
|
LB_STRING, /* 206 */
|
||||||
LB_SYMBOL,
|
LB_SYMBOL, /* 207 */
|
||||||
LB_KEYWORD,
|
LB_KEYWORD, /* 208 */
|
||||||
LB_ARRAY,
|
LB_ARRAY, /* 209 */
|
||||||
LB_TUPLE,
|
LB_TUPLE, /* 210 */
|
||||||
LB_TABLE,
|
LB_TABLE, /* 211 */
|
||||||
LB_TABLE_PROTO,
|
LB_TABLE_PROTO, /* 212 */
|
||||||
LB_STRUCT,
|
LB_STRUCT, /* 213 */
|
||||||
LB_BUFFER,
|
LB_BUFFER, /* 214 */
|
||||||
LB_FUNCTION,
|
LB_FUNCTION, /* 215 */
|
||||||
LB_REGISTRY,
|
LB_REGISTRY, /* 216 */
|
||||||
LB_ABSTRACT,
|
LB_ABSTRACT, /* 217 */
|
||||||
LB_REFERENCE,
|
LB_REFERENCE, /* 218 */
|
||||||
LB_FUNCENV_REF,
|
LB_FUNCENV_REF, /* 219 */
|
||||||
LB_FUNCDEF_REF
|
LB_FUNCDEF_REF /* 220 */
|
||||||
} LeadBytes;
|
} LeadBytes;
|
||||||
|
|
||||||
/* Helper to look inside an entry in an environment */
|
/* Helper to look inside an entry in an environment */
|
||||||
@ -183,10 +183,25 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
janet_env_valid(env);
|
||||||
janet_v_push(st->seen_envs, env);
|
janet_v_push(st->seen_envs, env);
|
||||||
|
if (env->offset > 0 && (JANET_STATUS_ALIVE == janet_fiber_status(env->as.fiber))) {
|
||||||
|
pushint(st, 0);
|
||||||
|
pushint(st, env->length);
|
||||||
|
Janet *values = env->as.fiber->data + env->offset;
|
||||||
|
uint32_t *bitset = janet_stack_frame(values)->func->def->closure_bitset;
|
||||||
|
for (int32_t i = 0; i < env->length; i++) {
|
||||||
|
if (1 & (bitset[i >> 5] >> (i & 0x1F))) {
|
||||||
|
marshal_one(st, values[i], flags + 1);
|
||||||
|
} else {
|
||||||
|
pushbyte(st, LB_NIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
janet_env_maybe_detach(env);
|
||||||
pushint(st, env->offset);
|
pushint(st, env->offset);
|
||||||
pushint(st, env->length);
|
pushint(st, env->length);
|
||||||
if (env->offset) {
|
if (env->offset > 0) {
|
||||||
/* On stack variant */
|
/* On stack variant */
|
||||||
marshal_one(st, janet_wrap_fiber(env->as.fiber), flags + 1);
|
marshal_one(st, janet_wrap_fiber(env->as.fiber), flags + 1);
|
||||||
} else {
|
} else {
|
||||||
@ -195,6 +210,7 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
|||||||
marshal_one(st, env->as.values[i], flags + 1);
|
marshal_one(st, env->as.values[i], flags + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Add function flags to janet functions */
|
/* Add function flags to janet functions */
|
||||||
static void janet_func_addflags(JanetFuncDef *def) {
|
static void janet_func_addflags(JanetFuncDef *def) {
|
||||||
@ -205,6 +221,16 @@ static void janet_func_addflags(JanetFuncDef *def) {
|
|||||||
if (def->sourcemap) def->flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
|
if (def->sourcemap) def->flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Marshal a sequence of u32s */
|
||||||
|
static void janet_marshal_u32s(MarshalState *st, const uint32_t *u32s, int32_t n) {
|
||||||
|
for (int32_t i = 0; i < n; i++) {
|
||||||
|
pushbyte(st, u32s[i] & 0xFF);
|
||||||
|
pushbyte(st, (u32s[i] >> 8) & 0xFF);
|
||||||
|
pushbyte(st, (u32s[i] >> 16) & 0xFF);
|
||||||
|
pushbyte(st, (u32s[i] >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Marshal a function def */
|
/* Marshal a function def */
|
||||||
static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||||
MARSH_STACKCHECK;
|
MARSH_STACKCHECK;
|
||||||
@ -239,12 +265,7 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
|||||||
marshal_one(st, def->constants[i], flags);
|
marshal_one(st, def->constants[i], flags);
|
||||||
|
|
||||||
/* marshal the bytecode */
|
/* marshal the bytecode */
|
||||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
janet_marshal_u32s(st, def->bytecode, def->bytecode_length);
|
||||||
pushbyte(st, def->bytecode[i] & 0xFF);
|
|
||||||
pushbyte(st, (def->bytecode[i] >> 8) & 0xFF);
|
|
||||||
pushbyte(st, (def->bytecode[i] >> 16) & 0xFF);
|
|
||||||
pushbyte(st, (def->bytecode[i] >> 24) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* marshal the environments if needed */
|
/* marshal the environments if needed */
|
||||||
for (int32_t i = 0; i < def->environments_length; i++)
|
for (int32_t i = 0; i < def->environments_length; i++)
|
||||||
@ -264,6 +285,11 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
|||||||
current = map.line;
|
current = map.line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Marshal closure bitset, if needed */
|
||||||
|
if (def->flags & JANET_FUNCDEF_FLAG_HASCLOBITSET) {
|
||||||
|
janet_marshal_u32s(st, def->closure_bitset, ((def->slotcount + 31) >> 5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define JANET_FIBER_FLAG_HASCHILD (1 << 29)
|
#define JANET_FIBER_FLAG_HASCHILD (1 << 29)
|
||||||
@ -609,6 +635,15 @@ static int32_t readint(UnmarshalState *st, const uint8_t **atdata) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Helper to read a natural number (int >= 0). */
|
||||||
|
static int32_t readnat(UnmarshalState *st, const uint8_t **atdata) {
|
||||||
|
int32_t ret = readint(st, atdata);
|
||||||
|
if (ret < 0) {
|
||||||
|
janet_panicf("expected integer >= 0, got %d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper to read a size_t (up to 8 bytes unsigned). */
|
/* Helper to read a size_t (up to 8 bytes unsigned). */
|
||||||
static uint64_t read64(UnmarshalState *st, const uint8_t **atdata) {
|
static uint64_t read64(UnmarshalState *st, const uint8_t **atdata) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
@ -677,36 +712,51 @@ static const uint8_t *unmarshal_one_env(
|
|||||||
JanetFuncEnv *env = janet_gcalloc(JANET_MEMORY_FUNCENV, sizeof(JanetFuncEnv));
|
JanetFuncEnv *env = janet_gcalloc(JANET_MEMORY_FUNCENV, sizeof(JanetFuncEnv));
|
||||||
env->length = 0;
|
env->length = 0;
|
||||||
env->offset = 0;
|
env->offset = 0;
|
||||||
|
env->as.values = NULL;
|
||||||
janet_v_push(st->lookup_envs, env);
|
janet_v_push(st->lookup_envs, env);
|
||||||
int32_t offset = readint(st, &data);
|
int32_t offset = readnat(st, &data);
|
||||||
int32_t length = readint(st, &data);
|
int32_t length = readnat(st, &data);
|
||||||
if (offset) {
|
if (offset > 0) {
|
||||||
Janet fiberv;
|
Janet fiberv;
|
||||||
/* On stack variant */
|
/* On stack variant */
|
||||||
data = unmarshal_one(st, data, &fiberv, flags);
|
data = unmarshal_one(st, data, &fiberv, flags);
|
||||||
janet_asserttype(fiberv, JANET_FIBER);
|
janet_asserttype(fiberv, JANET_FIBER);
|
||||||
env->as.fiber = janet_unwrap_fiber(fiberv);
|
env->as.fiber = janet_unwrap_fiber(fiberv);
|
||||||
/* Unmarshalling fiber may set values */
|
/* Negative offset indicates untrusted input */
|
||||||
if (env->offset != 0 && env->offset != offset)
|
env->offset = -offset;
|
||||||
janet_panic("invalid funcenv offset");
|
|
||||||
if (env->length != 0 && env->length != length)
|
|
||||||
janet_panic("invalid funcenv length");
|
|
||||||
} else {
|
} else {
|
||||||
/* Off stack variant */
|
/* Off stack variant */
|
||||||
|
if (length == 0) {
|
||||||
|
janet_panic("invalid funcenv length");
|
||||||
|
}
|
||||||
env->as.values = malloc(sizeof(Janet) * (size_t) length);
|
env->as.values = malloc(sizeof(Janet) * (size_t) length);
|
||||||
if (!env->as.values) {
|
if (!env->as.values) {
|
||||||
JANET_OUT_OF_MEMORY;
|
JANET_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
env->offset = 0;
|
||||||
for (int32_t i = 0; i < length; i++)
|
for (int32_t i = 0; i < length; i++)
|
||||||
data = unmarshal_one(st, data, env->as.values + i, flags);
|
data = unmarshal_one(st, data, env->as.values + i, flags);
|
||||||
}
|
}
|
||||||
env->offset = offset;
|
|
||||||
env->length = length;
|
env->length = length;
|
||||||
*out = env;
|
*out = env;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unmarshal a series of u32s */
|
||||||
|
static const uint8_t *janet_unmarshal_u32s(UnmarshalState *st, const uint8_t *data, uint32_t *into, int32_t n) {
|
||||||
|
for (int32_t i = 0; i < n; i++) {
|
||||||
|
MARSH_EOS(st, data + 3);
|
||||||
|
into[i] =
|
||||||
|
(uint32_t)(data[0]) |
|
||||||
|
((uint32_t)(data[1]) << 8) |
|
||||||
|
((uint32_t)(data[2]) << 16) |
|
||||||
|
((uint32_t)(data[3]) << 24);
|
||||||
|
data += 4;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
/* Unmarshal a funcdef */
|
/* Unmarshal a funcdef */
|
||||||
static const uint8_t *unmarshal_one_def(
|
static const uint8_t *unmarshal_one_def(
|
||||||
UnmarshalState *st,
|
UnmarshalState *st,
|
||||||
@ -730,6 +780,12 @@ static const uint8_t *unmarshal_one_def(
|
|||||||
def->bytecode_length = 0;
|
def->bytecode_length = 0;
|
||||||
def->name = NULL;
|
def->name = NULL;
|
||||||
def->source = NULL;
|
def->source = NULL;
|
||||||
|
def->closure_bitset = NULL;
|
||||||
|
def->defs = NULL;
|
||||||
|
def->environments = NULL;
|
||||||
|
def->constants = NULL;
|
||||||
|
def->bytecode = NULL;
|
||||||
|
def->sourcemap = NULL;
|
||||||
janet_v_push(st->lookup_defs, def);
|
janet_v_push(st->lookup_defs, def);
|
||||||
|
|
||||||
/* Set default lengths to zero */
|
/* Set default lengths to zero */
|
||||||
@ -740,18 +796,18 @@ static const uint8_t *unmarshal_one_def(
|
|||||||
|
|
||||||
/* Read flags and other fixed values */
|
/* Read flags and other fixed values */
|
||||||
def->flags = readint(st, &data);
|
def->flags = readint(st, &data);
|
||||||
def->slotcount = readint(st, &data);
|
def->slotcount = readnat(st, &data);
|
||||||
def->arity = readint(st, &data);
|
def->arity = readnat(st, &data);
|
||||||
def->min_arity = readint(st, &data);
|
def->min_arity = readnat(st, &data);
|
||||||
def->max_arity = readint(st, &data);
|
def->max_arity = readnat(st, &data);
|
||||||
|
|
||||||
/* Read some lengths */
|
/* Read some lengths */
|
||||||
constants_length = readint(st, &data);
|
constants_length = readnat(st, &data);
|
||||||
bytecode_length = readint(st, &data);
|
bytecode_length = readnat(st, &data);
|
||||||
if (def->flags & JANET_FUNCDEF_FLAG_HASENVS)
|
if (def->flags & JANET_FUNCDEF_FLAG_HASENVS)
|
||||||
environments_length = readint(st, &data);
|
environments_length = readnat(st, &data);
|
||||||
if (def->flags & JANET_FUNCDEF_FLAG_HASDEFS)
|
if (def->flags & JANET_FUNCDEF_FLAG_HASDEFS)
|
||||||
defs_length = readint(st, &data);
|
defs_length = readnat(st, &data);
|
||||||
|
|
||||||
/* Check name and source (optional) */
|
/* Check name and source (optional) */
|
||||||
if (def->flags & JANET_FUNCDEF_FLAG_HASNAME) {
|
if (def->flags & JANET_FUNCDEF_FLAG_HASNAME) {
|
||||||
@ -785,15 +841,7 @@ static const uint8_t *unmarshal_one_def(
|
|||||||
if (!def->bytecode) {
|
if (!def->bytecode) {
|
||||||
JANET_OUT_OF_MEMORY;
|
JANET_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
data = janet_unmarshal_u32s(st, data, def->bytecode, bytecode_length);
|
||||||
MARSH_EOS(st, data + 3);
|
|
||||||
def->bytecode[i] =
|
|
||||||
(uint32_t)(data[0]) |
|
|
||||||
((uint32_t)(data[1]) << 8) |
|
|
||||||
((uint32_t)(data[2]) << 16) |
|
|
||||||
((uint32_t)(data[3]) << 24);
|
|
||||||
data += 4;
|
|
||||||
}
|
|
||||||
def->bytecode_length = bytecode_length;
|
def->bytecode_length = bytecode_length;
|
||||||
|
|
||||||
/* Unmarshal environments */
|
/* Unmarshal environments */
|
||||||
@ -834,12 +882,21 @@ static const uint8_t *unmarshal_one_def(
|
|||||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||||
current += readint(st, &data);
|
current += readint(st, &data);
|
||||||
def->sourcemap[i].line = current;
|
def->sourcemap[i].line = current;
|
||||||
def->sourcemap[i].column = readint(st, &data);
|
def->sourcemap[i].column = readnat(st, &data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
def->sourcemap = NULL;
|
def->sourcemap = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unmarshal closure bitset if needed */
|
||||||
|
if (def->flags & JANET_FUNCDEF_FLAG_HASCLOBITSET) {
|
||||||
|
def->closure_bitset = malloc(sizeof(uint32_t) * def->slotcount);
|
||||||
|
if (NULL == def->closure_bitset) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
data = janet_unmarshal_u32s(st, data, def->closure_bitset, (def->slotcount + 31) >> 5);
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate */
|
/* Validate */
|
||||||
if (janet_verify(def))
|
if (janet_verify(def))
|
||||||
janet_panic("funcdef has invalid bytecode");
|
janet_panic("funcdef has invalid bytecode");
|
||||||
@ -857,7 +914,7 @@ static const uint8_t *unmarshal_one_fiber(
|
|||||||
JanetFiber **out,
|
JanetFiber **out,
|
||||||
int flags) {
|
int flags) {
|
||||||
|
|
||||||
/* Initialize a new fiber */
|
/* Initialize a new fiber with gc friendly defaults */
|
||||||
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
|
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
|
||||||
fiber->flags = 0;
|
fiber->flags = 0;
|
||||||
fiber->frame = 0;
|
fiber->frame = 0;
|
||||||
@ -872,42 +929,41 @@ static const uint8_t *unmarshal_one_fiber(
|
|||||||
/* Push fiber to seen stack */
|
/* Push fiber to seen stack */
|
||||||
janet_v_push(st->lookup, janet_wrap_fiber(fiber));
|
janet_v_push(st->lookup, janet_wrap_fiber(fiber));
|
||||||
|
|
||||||
/* Set frame later so fiber can be GCed at anytime if unmarshalling fails */
|
|
||||||
int32_t frame = 0;
|
|
||||||
int32_t stack = 0;
|
|
||||||
int32_t stacktop = 0;
|
|
||||||
|
|
||||||
/* Read ints */
|
/* Read ints */
|
||||||
fiber->flags = readint(st, &data);
|
int32_t fiber_flags = readint(st, &data);
|
||||||
frame = readint(st, &data);
|
int32_t frame = readnat(st, &data);
|
||||||
fiber->stackstart = readint(st, &data);
|
int32_t fiber_stackstart = readnat(st, &data);
|
||||||
fiber->stacktop = readint(st, &data);
|
int32_t fiber_stacktop = readnat(st, &data);
|
||||||
fiber->maxstack = readint(st, &data);
|
int32_t fiber_maxstack = readnat(st, &data);
|
||||||
|
JanetTable *fiber_env = NULL;
|
||||||
|
|
||||||
/* Check for bad flags and ints */
|
/* Check for bad flags and ints */
|
||||||
if ((int32_t)(frame + JANET_FRAME_SIZE) > fiber->stackstart ||
|
if ((int32_t)(frame + JANET_FRAME_SIZE) > fiber_stackstart ||
|
||||||
fiber->stackstart > fiber->stacktop ||
|
fiber_stackstart > fiber_stacktop ||
|
||||||
fiber->stacktop > fiber->maxstack) {
|
fiber_stacktop > fiber_maxstack) {
|
||||||
janet_panic("fiber has incorrect stack setup");
|
janet_panic("fiber has incorrect stack setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate stack memory */
|
/* Allocate stack memory */
|
||||||
fiber->capacity = fiber->stacktop + 10;
|
fiber->capacity = fiber_stacktop + 10;
|
||||||
fiber->data = malloc(sizeof(Janet) * fiber->capacity);
|
fiber->data = malloc(sizeof(Janet) * fiber->capacity);
|
||||||
if (!fiber->data) {
|
if (!fiber->data) {
|
||||||
JANET_OUT_OF_MEMORY;
|
JANET_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
for (int32_t i = 0; i < fiber->capacity; i++) {
|
||||||
|
fiber->data[i] = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
/* get frames */
|
/* get frames */
|
||||||
stack = frame;
|
int32_t stack = frame;
|
||||||
stacktop = fiber->stackstart - JANET_FRAME_SIZE;
|
int32_t stacktop = fiber_stackstart - JANET_FRAME_SIZE;
|
||||||
while (stack > 0) {
|
while (stack > 0) {
|
||||||
JanetFunction *func = NULL;
|
JanetFunction *func = NULL;
|
||||||
JanetFuncDef *def = NULL;
|
JanetFuncDef *def = NULL;
|
||||||
JanetFuncEnv *env = NULL;
|
JanetFuncEnv *env = NULL;
|
||||||
int32_t frameflags = readint(st, &data);
|
int32_t frameflags = readint(st, &data);
|
||||||
int32_t prevframe = readint(st, &data);
|
int32_t prevframe = readnat(st, &data);
|
||||||
int32_t pcdiff = readint(st, &data);
|
int32_t pcdiff = readnat(st, &data);
|
||||||
|
|
||||||
/* Get frame items */
|
/* Get frame items */
|
||||||
Janet *framestack = fiber->data + stack;
|
Janet *framestack = fiber->data + stack;
|
||||||
@ -923,15 +979,7 @@ static const uint8_t *unmarshal_one_fiber(
|
|||||||
/* Check env */
|
/* Check env */
|
||||||
if (frameflags & JANET_STACKFRAME_HASENV) {
|
if (frameflags & JANET_STACKFRAME_HASENV) {
|
||||||
frameflags &= ~JANET_STACKFRAME_HASENV;
|
frameflags &= ~JANET_STACKFRAME_HASENV;
|
||||||
int32_t offset = stack;
|
|
||||||
int32_t length = stacktop - stack;
|
|
||||||
data = unmarshal_one_env(st, data, &env, flags + 1);
|
data = unmarshal_one_env(st, data, &env, flags + 1);
|
||||||
if (env->offset != 0 && env->offset != offset)
|
|
||||||
janet_panic("funcenv offset does not match fiber frame");
|
|
||||||
if (env->length != 0 && env->length != length)
|
|
||||||
janet_panic("funcenv length does not match fiber frame");
|
|
||||||
env->offset = offset;
|
|
||||||
env->length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error checking */
|
/* Error checking */
|
||||||
@ -939,11 +987,11 @@ static const uint8_t *unmarshal_one_fiber(
|
|||||||
if (expected_framesize != stacktop - stack) {
|
if (expected_framesize != stacktop - stack) {
|
||||||
janet_panic("fiber stackframe size mismatch");
|
janet_panic("fiber stackframe size mismatch");
|
||||||
}
|
}
|
||||||
if (pcdiff < 0 || pcdiff >= def->bytecode_length) {
|
if (pcdiff >= def->bytecode_length) {
|
||||||
janet_panic("fiber stackframe has invalid pc");
|
janet_panic("fiber stackframe has invalid pc");
|
||||||
}
|
}
|
||||||
if ((int32_t)(prevframe + JANET_FRAME_SIZE) > stack) {
|
if ((int32_t)(prevframe + JANET_FRAME_SIZE) > stack) {
|
||||||
janet_panic("fibre stackframe does not align with previous frame");
|
janet_panic("fiber stackframe does not align with previous frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get stack items */
|
/* Get stack items */
|
||||||
@ -966,25 +1014,32 @@ static const uint8_t *unmarshal_one_fiber(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check for fiber env */
|
/* Check for fiber env */
|
||||||
if (fiber->flags & JANET_FIBER_FLAG_HASENV) {
|
if (fiber_flags & JANET_FIBER_FLAG_HASENV) {
|
||||||
Janet envv;
|
Janet envv;
|
||||||
fiber->flags &= ~JANET_FIBER_FLAG_HASENV;
|
fiber_flags &= ~JANET_FIBER_FLAG_HASENV;
|
||||||
data = unmarshal_one(st, data, &envv, flags + 1);
|
data = unmarshal_one(st, data, &envv, flags + 1);
|
||||||
janet_asserttype(envv, JANET_TABLE);
|
janet_asserttype(envv, JANET_TABLE);
|
||||||
fiber->env = janet_unwrap_table(envv);
|
fiber_env = janet_unwrap_table(envv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for child fiber */
|
/* Check for child fiber */
|
||||||
if (fiber->flags & JANET_FIBER_FLAG_HASCHILD) {
|
if (fiber_flags & JANET_FIBER_FLAG_HASCHILD) {
|
||||||
Janet fiberv;
|
Janet fiberv;
|
||||||
fiber->flags &= ~JANET_FIBER_FLAG_HASCHILD;
|
fiber_flags &= ~JANET_FIBER_FLAG_HASCHILD;
|
||||||
data = unmarshal_one(st, data, &fiberv, flags + 1);
|
data = unmarshal_one(st, data, &fiberv, flags + 1);
|
||||||
janet_asserttype(fiberv, JANET_FIBER);
|
janet_asserttype(fiberv, JANET_FIBER);
|
||||||
fiber->child = janet_unwrap_fiber(fiberv);
|
fiber->child = janet_unwrap_fiber(fiberv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return data */
|
/* We have valid fiber, finally construct remaining fields. */
|
||||||
fiber->frame = frame;
|
fiber->frame = frame;
|
||||||
|
fiber->flags = fiber_flags;
|
||||||
|
fiber->stackstart = fiber_stackstart;
|
||||||
|
fiber->stacktop = fiber_stacktop;
|
||||||
|
fiber->maxstack = fiber_maxstack;
|
||||||
|
fiber->env = fiber_env;
|
||||||
|
|
||||||
|
/* Return data */
|
||||||
*out = fiber;
|
*out = fiber;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -1043,7 +1098,7 @@ static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *
|
|||||||
Janet key;
|
Janet key;
|
||||||
data = unmarshal_one(st, data, &key, flags + 1);
|
data = unmarshal_one(st, data, &key, flags + 1);
|
||||||
const JanetAbstractType *at = janet_get_abstract_type(key);
|
const JanetAbstractType *at = janet_get_abstract_type(key);
|
||||||
if (at == NULL) return NULL;
|
if (at == NULL) goto oops;
|
||||||
if (at->unmarshal) {
|
if (at->unmarshal) {
|
||||||
JanetMarshalContext context = {NULL, st, flags, data, at};
|
JanetMarshalContext context = {NULL, st, flags, data, at};
|
||||||
*out = janet_wrap_abstract(at->unmarshal(&context));
|
*out = janet_wrap_abstract(at->unmarshal(&context));
|
||||||
@ -1052,7 +1107,8 @@ static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *
|
|||||||
}
|
}
|
||||||
return context.data;
|
return context.data;
|
||||||
}
|
}
|
||||||
return NULL;
|
oops:
|
||||||
|
janet_panic("invalid abstract type");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *unmarshal_one(
|
static const uint8_t *unmarshal_one(
|
||||||
@ -1064,7 +1120,7 @@ static const uint8_t *unmarshal_one(
|
|||||||
MARSH_STACKCHECK;
|
MARSH_STACKCHECK;
|
||||||
MARSH_EOS(st, data);
|
MARSH_EOS(st, data);
|
||||||
lead = data[0];
|
lead = data[0];
|
||||||
if (lead < 200) {
|
if (lead < LB_REAL) {
|
||||||
*out = janet_wrap_integer(readint(st, &data));
|
*out = janet_wrap_integer(readint(st, &data));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -1100,7 +1156,7 @@ static const uint8_t *unmarshal_one(
|
|||||||
u.bytes[0] = data[8];
|
u.bytes[0] = data[8];
|
||||||
u.bytes[1] = data[7];
|
u.bytes[1] = data[7];
|
||||||
u.bytes[2] = data[6];
|
u.bytes[2] = data[6];
|
||||||
u.bytes[5] = data[5];
|
u.bytes[3] = data[5];
|
||||||
u.bytes[4] = data[4];
|
u.bytes[4] = data[4];
|
||||||
u.bytes[5] = data[3];
|
u.bytes[5] = data[3];
|
||||||
u.bytes[6] = data[2];
|
u.bytes[6] = data[2];
|
||||||
@ -1118,7 +1174,7 @@ static const uint8_t *unmarshal_one(
|
|||||||
case LB_KEYWORD:
|
case LB_KEYWORD:
|
||||||
case LB_REGISTRY: {
|
case LB_REGISTRY: {
|
||||||
data++;
|
data++;
|
||||||
int32_t len = readint(st, &data);
|
int32_t len = readnat(st, &data);
|
||||||
MARSH_EOS(st, data - 1 + len);
|
MARSH_EOS(st, data - 1 + len);
|
||||||
if (lead == LB_STRING) {
|
if (lead == LB_STRING) {
|
||||||
const uint8_t *str = janet_string(data, len);
|
const uint8_t *str = janet_string(data, len);
|
||||||
@ -1178,7 +1234,11 @@ static const uint8_t *unmarshal_one(
|
|||||||
/* Things that open with integers */
|
/* Things that open with integers */
|
||||||
{
|
{
|
||||||
data++;
|
data++;
|
||||||
int32_t len = readint(st, &data);
|
int32_t len = readnat(st, &data);
|
||||||
|
/* DOS check */
|
||||||
|
if (lead != LB_REFERENCE) {
|
||||||
|
MARSH_EOS(st, data - 1 + len);
|
||||||
|
}
|
||||||
if (lead == LB_ARRAY) {
|
if (lead == LB_ARRAY) {
|
||||||
/* Array */
|
/* Array */
|
||||||
JanetArray *array = janet_array(len);
|
JanetArray *array = janet_array(len);
|
||||||
@ -1210,7 +1270,7 @@ static const uint8_t *unmarshal_one(
|
|||||||
*out = janet_wrap_struct(janet_struct_end(struct_));
|
*out = janet_wrap_struct(janet_struct_end(struct_));
|
||||||
janet_v_push(st->lookup, *out);
|
janet_v_push(st->lookup, *out);
|
||||||
} else if (lead == LB_REFERENCE) {
|
} else if (lead == LB_REFERENCE) {
|
||||||
if (len < 0 || len >= janet_v_count(st->lookup))
|
if (len >= janet_v_count(st->lookup))
|
||||||
janet_panicf("invalid reference %d", len);
|
janet_panicf("invalid reference %d", len);
|
||||||
*out = st->lookup[len];
|
*out = st->lookup[len];
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,7 +52,7 @@ static void *janet_rng_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
return rng;
|
return rng;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JanetAbstractType JanetRNG_type = {
|
const JanetAbstractType janet_rng_type = {
|
||||||
"core/rng",
|
"core/rng",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -115,7 +115,7 @@ double janet_rng_double(JanetRNG *rng) {
|
|||||||
|
|
||||||
static Janet cfun_rng_make(int32_t argc, Janet *argv) {
|
static Janet cfun_rng_make(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 0, 1);
|
janet_arity(argc, 0, 1);
|
||||||
JanetRNG *rng = janet_abstract(&JanetRNG_type, sizeof(JanetRNG));
|
JanetRNG *rng = janet_abstract(&janet_rng_type, sizeof(JanetRNG));
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
if (janet_checkint(argv[0])) {
|
if (janet_checkint(argv[0])) {
|
||||||
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
||||||
@ -132,13 +132,13 @@ static Janet cfun_rng_make(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_rng_uniform(int32_t argc, Janet *argv) {
|
static Janet cfun_rng_uniform(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetRNG *rng = janet_getabstract(argv, 0, &JanetRNG_type);
|
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||||
return janet_wrap_number(janet_rng_double(rng));
|
return janet_wrap_number(janet_rng_double(rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_rng_int(int32_t argc, Janet *argv) {
|
static Janet cfun_rng_int(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, 2);
|
janet_arity(argc, 1, 2);
|
||||||
JanetRNG *rng = janet_getabstract(argv, 0, &JanetRNG_type);
|
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
uint32_t word = janet_rng_u32(rng) >> 1;
|
uint32_t word = janet_rng_u32(rng) >> 1;
|
||||||
return janet_wrap_integer(word);
|
return janet_wrap_integer(word);
|
||||||
@ -166,7 +166,7 @@ static void rng_get_4bytes(JanetRNG *rng, uint8_t *buf) {
|
|||||||
|
|
||||||
static Janet cfun_rng_buffer(int32_t argc, Janet *argv) {
|
static Janet cfun_rng_buffer(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, 3);
|
janet_arity(argc, 2, 3);
|
||||||
JanetRNG *rng = janet_getabstract(argv, 0, &JanetRNG_type);
|
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
|
||||||
int32_t n = janet_getnat(argv, 1);
|
int32_t n = janet_getnat(argv, 1);
|
||||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, n);
|
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, n);
|
||||||
|
|
||||||
@ -255,6 +255,10 @@ JANET_DEFINE_MATHOP(fabs, fabs)
|
|||||||
JANET_DEFINE_MATHOP(floor, floor)
|
JANET_DEFINE_MATHOP(floor, floor)
|
||||||
JANET_DEFINE_MATHOP(trunc, trunc)
|
JANET_DEFINE_MATHOP(trunc, trunc)
|
||||||
JANET_DEFINE_MATHOP(round, round)
|
JANET_DEFINE_MATHOP(round, round)
|
||||||
|
JANET_DEFINE_MATHOP(gamma, lgamma)
|
||||||
|
JANET_DEFINE_MATHOP(log1p, log1p)
|
||||||
|
JANET_DEFINE_MATHOP(erf, erf)
|
||||||
|
JANET_DEFINE_MATHOP(erfc, erfc)
|
||||||
|
|
||||||
#define JANET_DEFINE_MATH2OP(name, fop)\
|
#define JANET_DEFINE_MATH2OP(name, fop)\
|
||||||
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
static Janet janet_##name(int32_t argc, Janet *argv) {\
|
||||||
@ -267,6 +271,7 @@ static Janet janet_##name(int32_t argc, Janet *argv) {\
|
|||||||
JANET_DEFINE_MATH2OP(atan2, atan2)
|
JANET_DEFINE_MATH2OP(atan2, atan2)
|
||||||
JANET_DEFINE_MATH2OP(pow, pow)
|
JANET_DEFINE_MATH2OP(pow, pow)
|
||||||
JANET_DEFINE_MATH2OP(hypot, hypot)
|
JANET_DEFINE_MATH2OP(hypot, hypot)
|
||||||
|
JANET_DEFINE_MATH2OP(nextafter, nextafter)
|
||||||
|
|
||||||
static Janet janet_not(int32_t argc, Janet *argv) {
|
static Janet janet_not(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
@ -438,6 +443,26 @@ static const JanetReg math_cfuns[] = {
|
|||||||
JDOC("(math/exp2 x)\n\n"
|
JDOC("(math/exp2 x)\n\n"
|
||||||
"Returns 2 to the power of x.")
|
"Returns 2 to the power of x.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"math/log1p", janet_log1p,
|
||||||
|
JDOC("(math/log1p x)\n\n"
|
||||||
|
"Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"math/gamma", janet_gamma,
|
||||||
|
JDOC("(math/gamma x)\n\n"
|
||||||
|
"Returns gamma(x).")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"math/erfc", janet_erfc,
|
||||||
|
JDOC("(math/erfc x)\n\n"
|
||||||
|
"Returns the complementary error function of x.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"math/erf", janet_erf,
|
||||||
|
JDOC("(math/erf x)\n\n"
|
||||||
|
"Returns the error function of x.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"math/expm1", janet_expm1,
|
"math/expm1", janet_expm1,
|
||||||
JDOC("(math/expm1 x)\n\n"
|
JDOC("(math/expm1 x)\n\n"
|
||||||
@ -453,13 +478,18 @@ static const JanetReg math_cfuns[] = {
|
|||||||
JDOC("(math/round x)\n\n"
|
JDOC("(math/round x)\n\n"
|
||||||
"Returns the integer nearest to x.")
|
"Returns the integer nearest to x.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"math/next", janet_nextafter,
|
||||||
|
JDOC("(math/next y)\n\n"
|
||||||
|
"Returns the next representable floating point value after x in the direction of y.")
|
||||||
|
},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Module entry point */
|
/* Module entry point */
|
||||||
void janet_lib_math(JanetTable *env) {
|
void janet_lib_math(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, math_cfuns);
|
janet_core_cfuns(env, NULL, math_cfuns);
|
||||||
janet_register_abstract_type(&JanetRNG_type);
|
janet_register_abstract_type(&janet_rng_type);
|
||||||
#ifdef JANET_BOOTSTRAP
|
#ifdef JANET_BOOTSTRAP
|
||||||
janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931),
|
janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931),
|
||||||
JDOC("The value pi."));
|
JDOC("The value pi."));
|
||||||
|
457
src/core/os.c
457
src/core/os.c
@ -32,6 +32,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -69,6 +70,13 @@ extern char **environ;
|
|||||||
void arc4random_buf(void *buf, size_t nbytes);
|
void arc4random_buf(void *buf, size_t nbytes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Not POSIX, but all Unixes but Solaris have this function. */
|
||||||
|
#if defined(JANET_POSIX) && !defined(__sun)
|
||||||
|
time_t timegm(struct tm *tm);
|
||||||
|
#elif defined(JANET_WINDOWS)
|
||||||
|
#define timegm _mkgmtime
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Access to some global variables should be synchronized if not in single threaded mode, as
|
/* Access to some global variables should be synchronized if not in single threaded mode, as
|
||||||
* setenv/getenv are not thread safe. */
|
* setenv/getenv are not thread safe. */
|
||||||
#ifdef JANET_THREADS
|
#ifdef JANET_THREADS
|
||||||
@ -401,7 +409,16 @@ static Janet os_execute(int32_t argc, Janet *argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
os_execute_cleanup(envp, child_argv);
|
os_execute_cleanup(envp, child_argv);
|
||||||
return janet_wrap_integer(WEXITSTATUS(status));
|
/* Use POSIX shell semantics for interpreting signals */
|
||||||
|
int ret;
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
ret = WEXITSTATUS(status);
|
||||||
|
} else if (WIFSTOPPED(status)) {
|
||||||
|
ret = WSTOPSIG(status) + 128;
|
||||||
|
} else {
|
||||||
|
ret = WTERMSIG(status) + 128;
|
||||||
|
}
|
||||||
|
return janet_wrap_integer(ret);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,13 +638,11 @@ static Janet os_date(int32_t argc, Janet *argv) {
|
|||||||
struct tm *t_info = NULL;
|
struct tm *t_info = NULL;
|
||||||
if (argc) {
|
if (argc) {
|
||||||
int64_t integer = janet_getinteger64(argv, 0);
|
int64_t integer = janet_getinteger64(argv, 0);
|
||||||
if (integer < 0)
|
|
||||||
janet_panicf("expected non-negative 64 bit signed integer, got %v", argv[0]);
|
|
||||||
t = (time_t) integer;
|
t = (time_t) integer;
|
||||||
} else {
|
} else {
|
||||||
time(&t);
|
time(&t);
|
||||||
}
|
}
|
||||||
if (argc >= 2 && janet_truthy(argv[2])) {
|
if (argc >= 2 && janet_truthy(argv[1])) {
|
||||||
/* local time */
|
/* local time */
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
localtime_s(&t_infos, &t);
|
localtime_s(&t_infos, &t);
|
||||||
@ -658,6 +673,101 @@ static Janet os_date(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_struct(janet_struct_end(st));
|
return janet_wrap_struct(janet_struct_end(st));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int entry_getdst(Janet env_entry) {
|
||||||
|
Janet v;
|
||||||
|
if (janet_checktype(env_entry, JANET_TABLE)) {
|
||||||
|
JanetTable *entry = janet_unwrap_table(env_entry);
|
||||||
|
v = janet_table_get(entry, janet_ckeywordv("dst"));
|
||||||
|
} else if (janet_checktype(env_entry, JANET_STRUCT)) {
|
||||||
|
const JanetKV *entry = janet_unwrap_struct(env_entry);
|
||||||
|
v = janet_struct_get(entry, janet_ckeywordv("dst"));
|
||||||
|
} else {
|
||||||
|
v = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_checktype(v, JANET_NIL)) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return janet_truthy(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
typedef int32_t timeint_t;
|
||||||
|
#else
|
||||||
|
typedef int64_t timeint_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static timeint_t entry_getint(Janet env_entry, char *field) {
|
||||||
|
Janet i;
|
||||||
|
if (janet_checktype(env_entry, JANET_TABLE)) {
|
||||||
|
JanetTable *entry = janet_unwrap_table(env_entry);
|
||||||
|
i = janet_table_get(entry, janet_ckeywordv(field));
|
||||||
|
} else if (janet_checktype(env_entry, JANET_STRUCT)) {
|
||||||
|
const JanetKV *entry = janet_unwrap_struct(env_entry);
|
||||||
|
i = janet_struct_get(entry, janet_ckeywordv(field));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (janet_checktype(i, JANET_NIL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
if (!janet_checkint(i)) {
|
||||||
|
janet_panicf("bad slot #%s, expected 32 bit signed integer, got %v",
|
||||||
|
field, i);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!janet_checkint64(i)) {
|
||||||
|
janet_panicf("bad slot #%s, expected 64 bit signed integer, got %v",
|
||||||
|
field, i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (timeint_t)janet_unwrap_number(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_mktime(int32_t argc, Janet *argv) {
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
time_t t;
|
||||||
|
struct tm t_info;
|
||||||
|
|
||||||
|
/* Use memset instead of = {0} to silence paranoid warning in macos */
|
||||||
|
memset(&t_info, 0, sizeof(t_info));
|
||||||
|
|
||||||
|
if (!janet_checktype(argv[0], JANET_TABLE) &&
|
||||||
|
!janet_checktype(argv[0], JANET_STRUCT))
|
||||||
|
janet_panic_type(argv[0], 0, JANET_TFLAG_DICTIONARY);
|
||||||
|
|
||||||
|
t_info.tm_sec = entry_getint(argv[0], "seconds");
|
||||||
|
t_info.tm_min = entry_getint(argv[0], "minutes");
|
||||||
|
t_info.tm_hour = entry_getint(argv[0], "hours");
|
||||||
|
t_info.tm_mday = entry_getint(argv[0], "month-day") + 1;
|
||||||
|
t_info.tm_mon = entry_getint(argv[0], "month");
|
||||||
|
t_info.tm_year = entry_getint(argv[0], "year") - 1900;
|
||||||
|
t_info.tm_isdst = entry_getdst(argv[0]);
|
||||||
|
|
||||||
|
if (argc >= 2 && janet_truthy(argv[1])) {
|
||||||
|
/* local time */
|
||||||
|
t = mktime(&t_info);
|
||||||
|
} else {
|
||||||
|
/* utc time */
|
||||||
|
#ifdef __sun
|
||||||
|
janet_panic("os/mktime UTC not supported on Solaris");
|
||||||
|
return janet_wrap_nil();
|
||||||
|
#else
|
||||||
|
t = timegm(&t_info);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t == (time_t) -1) {
|
||||||
|
janet_panicf("%s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return janet_wrap_number((double)t);
|
||||||
|
}
|
||||||
|
|
||||||
static Janet os_link(int32_t argc, Janet *argv) {
|
static Janet os_link(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, 3);
|
janet_arity(argc, 2, 3);
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
@ -668,9 +778,25 @@ static Janet os_link(int32_t argc, Janet *argv) {
|
|||||||
#else
|
#else
|
||||||
const char *oldpath = janet_getcstring(argv, 0);
|
const char *oldpath = janet_getcstring(argv, 0);
|
||||||
const char *newpath = janet_getcstring(argv, 1);
|
const char *newpath = janet_getcstring(argv, 1);
|
||||||
int res = ((argc == 3 && janet_getboolean(argv, 2)) ? symlink : link)(oldpath, newpath);
|
int res = ((argc == 3 && janet_truthy(argv[2])) ? symlink : link)(oldpath, newpath);
|
||||||
if (-1 == res) janet_panicf("%s: %s -> %s", strerror(errno), oldpath, newpath);
|
if (-1 == res) janet_panicf("%s: %s -> %s", strerror(errno), oldpath, newpath);
|
||||||
return janet_wrap_integer(res);
|
return janet_wrap_nil();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_symlink(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
janet_panic("os/symlink not supported on Windows");
|
||||||
|
return janet_wrap_nil();
|
||||||
|
#else
|
||||||
|
const char *oldpath = janet_getcstring(argv, 0);
|
||||||
|
const char *newpath = janet_getcstring(argv, 1);
|
||||||
|
int res = symlink(oldpath, newpath);
|
||||||
|
if (-1 == res) janet_panicf("%s: %s -> %s", strerror(errno), oldpath, newpath);
|
||||||
|
return janet_wrap_nil();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +808,9 @@ static Janet os_mkdir(int32_t argc, Janet *argv) {
|
|||||||
#else
|
#else
|
||||||
int res = mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
int res = mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||||
#endif
|
#endif
|
||||||
return janet_wrap_boolean(res != -1);
|
if (res == 0) return janet_wrap_true();
|
||||||
|
if (errno == EEXIST) return janet_wrap_false();
|
||||||
|
janet_panicf("%s: %s", strerror(errno), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet os_rmdir(int32_t argc, Janet *argv) {
|
static Janet os_rmdir(int32_t argc, Janet *argv) {
|
||||||
@ -737,13 +865,42 @@ static Janet os_remove(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet os_readlink(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
static const uint8_t *janet_decode_permissions(unsigned short m) {
|
(void) argc;
|
||||||
uint8_t flags[9] = {0};
|
(void) argv;
|
||||||
flags[0] = flags[3] = flags[6] = (m & S_IREAD) ? 'r' : '-';
|
janet_panic("os/readlink not supported on Windows");
|
||||||
flags[1] = flags[4] = flags[7] = (m & S_IWRITE) ? 'w' : '-';
|
return janet_wrap_nil();
|
||||||
flags[2] = flags[5] = flags[8] = (m & S_IEXEC) ? 'x' : '-';
|
#else
|
||||||
return janet_string(flags, sizeof(flags));
|
static char buffer[PATH_MAX];
|
||||||
|
const char *path = janet_getcstring(argv, 0);
|
||||||
|
ssize_t len = readlink(path, buffer, sizeof buffer);
|
||||||
|
if (len < 0 || (size_t)len >= sizeof buffer)
|
||||||
|
janet_panicf("%s: %s", strerror(errno), path);
|
||||||
|
return janet_stringv((const uint8_t *)buffer, len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
|
||||||
|
typedef struct _stat jstat_t;
|
||||||
|
typedef unsigned short jmode_t;
|
||||||
|
|
||||||
|
static int32_t janet_perm_to_unix(unsigned short m) {
|
||||||
|
int32_t ret = 0;
|
||||||
|
if (m & S_IEXEC) ret |= 0111;
|
||||||
|
if (m & S_IWRITE) ret |= 0222;
|
||||||
|
if (m & S_IREAD) ret |= 0444;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short janet_perm_from_unix(int32_t x) {
|
||||||
|
unsigned short m = 0;
|
||||||
|
if (x & 111) m |= S_IEXEC;
|
||||||
|
if (x & 222) m |= S_IWRITE;
|
||||||
|
if (x & 444) m |= S_IREAD;
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *janet_decode_mode(unsigned short m) {
|
static const uint8_t *janet_decode_mode(unsigned short m) {
|
||||||
@ -753,19 +910,22 @@ static const uint8_t *janet_decode_mode(unsigned short m) {
|
|||||||
else if (m & _S_IFCHR) str = "character";
|
else if (m & _S_IFCHR) str = "character";
|
||||||
return janet_ckeyword(str);
|
return janet_ckeyword(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t janet_decode_permissions(jmode_t mode) {
|
||||||
|
return (int32_t)(mode & (S_IEXEC | S_IWRITE | S_IREAD));
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static const uint8_t *janet_decode_permissions(mode_t m) {
|
|
||||||
uint8_t flags[9] = {0};
|
typedef struct stat jstat_t;
|
||||||
flags[0] = (m & S_IRUSR) ? 'r' : '-';
|
typedef mode_t jmode_t;
|
||||||
flags[1] = (m & S_IWUSR) ? 'w' : '-';
|
|
||||||
flags[2] = (m & S_IXUSR) ? 'x' : '-';
|
static int32_t janet_perm_to_unix(mode_t m) {
|
||||||
flags[3] = (m & S_IRGRP) ? 'r' : '-';
|
return (int32_t) m;
|
||||||
flags[4] = (m & S_IWGRP) ? 'w' : '-';
|
}
|
||||||
flags[5] = (m & S_IXGRP) ? 'x' : '-';
|
|
||||||
flags[6] = (m & S_IROTH) ? 'r' : '-';
|
static mode_t janet_perm_from_unix(int32_t x) {
|
||||||
flags[7] = (m & S_IWOTH) ? 'w' : '-';
|
return (mode_t) x;
|
||||||
flags[8] = (m & S_IXOTH) ? 'x' : '-';
|
|
||||||
return janet_string(flags, sizeof(flags));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *janet_decode_mode(mode_t m) {
|
static const uint8_t *janet_decode_mode(mode_t m) {
|
||||||
@ -779,75 +939,131 @@ static const uint8_t *janet_decode_mode(mode_t m) {
|
|||||||
else if (S_ISCHR(m)) str = "character";
|
else if (S_ISCHR(m)) str = "character";
|
||||||
return janet_ckeyword(str);
|
return janet_ckeyword(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t janet_decode_permissions(jmode_t mode) {
|
||||||
|
return (int32_t)(mode & 0777);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Can we do this? */
|
static int32_t os_parse_permstring(const uint8_t *perm) {
|
||||||
#ifdef JANET_WINDOWS
|
int32_t m = 0;
|
||||||
#define stat _stat
|
if (perm[0] == 'r') m |= 0400;
|
||||||
#endif
|
if (perm[1] == 'w') m |= 0200;
|
||||||
|
if (perm[2] == 'x') m |= 0100;
|
||||||
|
if (perm[3] == 'r') m |= 0040;
|
||||||
|
if (perm[4] == 'w') m |= 0020;
|
||||||
|
if (perm[5] == 'x') m |= 0010;
|
||||||
|
if (perm[6] == 'r') m |= 0004;
|
||||||
|
if (perm[7] == 'w') m |= 0002;
|
||||||
|
if (perm[8] == 'x') m |= 0001;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_make_permstring(int32_t permissions) {
|
||||||
|
uint8_t bytes[9] = {0};
|
||||||
|
bytes[0] = (permissions & 0400) ? 'r' : '-';
|
||||||
|
bytes[1] = (permissions & 0200) ? 'w' : '-';
|
||||||
|
bytes[2] = (permissions & 0100) ? 'x' : '-';
|
||||||
|
bytes[3] = (permissions & 0040) ? 'r' : '-';
|
||||||
|
bytes[4] = (permissions & 0020) ? 'w' : '-';
|
||||||
|
bytes[5] = (permissions & 0010) ? 'x' : '-';
|
||||||
|
bytes[6] = (permissions & 0004) ? 'r' : '-';
|
||||||
|
bytes[7] = (permissions & 0002) ? 'w' : '-';
|
||||||
|
bytes[8] = (permissions & 0001) ? 'x' : '-';
|
||||||
|
return janet_stringv(bytes, sizeof(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t os_get_unix_mode(const Janet *argv, int32_t n) {
|
||||||
|
int32_t unix_mode;
|
||||||
|
if (janet_checkint(argv[n])) {
|
||||||
|
/* Integer mode */
|
||||||
|
int32_t x = janet_unwrap_integer(argv[n]);
|
||||||
|
if (x < 0 || x > 0777) {
|
||||||
|
janet_panicf("bad slot #%d, expected integer in range [0, 8r777], got %v", n, argv[n]);
|
||||||
|
}
|
||||||
|
unix_mode = x;
|
||||||
|
} else {
|
||||||
|
/* Bytes mode */
|
||||||
|
JanetByteView bytes = janet_getbytes(argv, n);
|
||||||
|
if (bytes.len != 9) {
|
||||||
|
janet_panicf("bad slot #%d: expected byte sequence of length 9, got %v", n, argv[n]);
|
||||||
|
}
|
||||||
|
unix_mode = os_parse_permstring(bytes.bytes);
|
||||||
|
}
|
||||||
|
return unix_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jmode_t os_getmode(const Janet *argv, int32_t n) {
|
||||||
|
return janet_perm_from_unix(os_get_unix_mode(argv, n));
|
||||||
|
}
|
||||||
|
|
||||||
/* Getters */
|
/* Getters */
|
||||||
static Janet os_stat_dev(struct stat *st) {
|
static Janet os_stat_dev(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_dev);
|
return janet_wrap_number(st->st_dev);
|
||||||
}
|
}
|
||||||
static Janet os_stat_inode(struct stat *st) {
|
static Janet os_stat_inode(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_ino);
|
return janet_wrap_number(st->st_ino);
|
||||||
}
|
}
|
||||||
static Janet os_stat_mode(struct stat *st) {
|
static Janet os_stat_mode(jstat_t *st) {
|
||||||
return janet_wrap_keyword(janet_decode_mode(st->st_mode));
|
return janet_wrap_keyword(janet_decode_mode(st->st_mode));
|
||||||
}
|
}
|
||||||
static Janet os_stat_permissions(struct stat *st) {
|
static Janet os_stat_int_permissions(jstat_t *st) {
|
||||||
return janet_wrap_string(janet_decode_permissions(st->st_mode));
|
return janet_wrap_integer(janet_perm_to_unix(janet_decode_permissions(st->st_mode)));
|
||||||
}
|
}
|
||||||
static Janet os_stat_uid(struct stat *st) {
|
static Janet os_stat_permissions(jstat_t *st) {
|
||||||
|
return os_make_permstring(janet_perm_to_unix(janet_decode_permissions(st->st_mode)));
|
||||||
|
}
|
||||||
|
static Janet os_stat_uid(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_uid);
|
return janet_wrap_number(st->st_uid);
|
||||||
}
|
}
|
||||||
static Janet os_stat_gid(struct stat *st) {
|
static Janet os_stat_gid(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_gid);
|
return janet_wrap_number(st->st_gid);
|
||||||
}
|
}
|
||||||
static Janet os_stat_nlink(struct stat *st) {
|
static Janet os_stat_nlink(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_nlink);
|
return janet_wrap_number(st->st_nlink);
|
||||||
}
|
}
|
||||||
static Janet os_stat_rdev(struct stat *st) {
|
static Janet os_stat_rdev(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_rdev);
|
return janet_wrap_number(st->st_rdev);
|
||||||
}
|
}
|
||||||
static Janet os_stat_size(struct stat *st) {
|
static Janet os_stat_size(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_size);
|
return janet_wrap_number(st->st_size);
|
||||||
}
|
}
|
||||||
static Janet os_stat_accessed(struct stat *st) {
|
static Janet os_stat_accessed(jstat_t *st) {
|
||||||
return janet_wrap_number((double) st->st_atime);
|
return janet_wrap_number((double) st->st_atime);
|
||||||
}
|
}
|
||||||
static Janet os_stat_modified(struct stat *st) {
|
static Janet os_stat_modified(jstat_t *st) {
|
||||||
return janet_wrap_number((double) st->st_mtime);
|
return janet_wrap_number((double) st->st_mtime);
|
||||||
}
|
}
|
||||||
static Janet os_stat_changed(struct stat *st) {
|
static Janet os_stat_changed(jstat_t *st) {
|
||||||
return janet_wrap_number((double) st->st_ctime);
|
return janet_wrap_number((double) st->st_ctime);
|
||||||
}
|
}
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
static Janet os_stat_blocks(struct stat *st) {
|
static Janet os_stat_blocks(jstat_t *st) {
|
||||||
return janet_wrap_number(0);
|
return janet_wrap_number(0);
|
||||||
}
|
}
|
||||||
static Janet os_stat_blocksize(struct stat *st) {
|
static Janet os_stat_blocksize(jstat_t *st) {
|
||||||
return janet_wrap_number(0);
|
return janet_wrap_number(0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static Janet os_stat_blocks(struct stat *st) {
|
static Janet os_stat_blocks(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_blocks);
|
return janet_wrap_number(st->st_blocks);
|
||||||
}
|
}
|
||||||
static Janet os_stat_blocksize(struct stat *st) {
|
static Janet os_stat_blocksize(jstat_t *st) {
|
||||||
return janet_wrap_number(st->st_blksize);
|
return janet_wrap_number(st->st_blksize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct OsStatGetter {
|
struct OsStatGetter {
|
||||||
const char *name;
|
const char *name;
|
||||||
Janet(*fn)(struct stat *st);
|
Janet(*fn)(jstat_t *st);
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct OsStatGetter os_stat_getters[] = {
|
static const struct OsStatGetter os_stat_getters[] = {
|
||||||
{"dev", os_stat_dev},
|
{"dev", os_stat_dev},
|
||||||
{"inode", os_stat_inode},
|
{"inode", os_stat_inode},
|
||||||
{"mode", os_stat_mode},
|
{"mode", os_stat_mode},
|
||||||
|
{"int-permissions", os_stat_int_permissions},
|
||||||
{"permissions", os_stat_permissions},
|
{"permissions", os_stat_permissions},
|
||||||
{"uid", os_stat_uid},
|
{"uid", os_stat_uid},
|
||||||
{"gid", os_stat_gid},
|
{"gid", os_stat_gid},
|
||||||
@ -862,7 +1078,7 @@ static const struct OsStatGetter os_stat_getters[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Janet os_stat(int32_t argc, Janet *argv) {
|
static Janet os_stat_or_lstat(int do_lstat, int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, 2);
|
janet_arity(argc, 1, 2);
|
||||||
const char *path = janet_getcstring(argv, 0);
|
const char *path = janet_getcstring(argv, 0);
|
||||||
JanetTable *tab = NULL;
|
JanetTable *tab = NULL;
|
||||||
@ -880,8 +1096,18 @@ static Janet os_stat(int32_t argc, Janet *argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Build result */
|
/* Build result */
|
||||||
struct stat st;
|
jstat_t st;
|
||||||
int res = stat(path, &st);
|
#ifdef JANET_WINDOWS
|
||||||
|
(void) do_lstat;
|
||||||
|
int res = _stat(path, &st);
|
||||||
|
#else
|
||||||
|
int res;
|
||||||
|
if (do_lstat) {
|
||||||
|
res = lstat(path, &st);
|
||||||
|
} else {
|
||||||
|
res = stat(path, &st);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (-1 == res) {
|
if (-1 == res) {
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
@ -903,6 +1129,37 @@ static Janet os_stat(int32_t argc, Janet *argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet os_stat(int32_t argc, Janet *argv) {
|
||||||
|
return os_stat_or_lstat(0, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_lstat(int32_t argc, Janet *argv) {
|
||||||
|
return os_stat_or_lstat(1, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_chmod(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
const char *path = janet_getcstring(argv, 0);
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
int res = _chmod(path, os_getmode(argv, 1));
|
||||||
|
#else
|
||||||
|
int res = chmod(path, os_getmode(argv, 1));
|
||||||
|
#endif
|
||||||
|
if (-1 == res) janet_panicf("%s: %s", strerror(errno), path);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_umask(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
int mask = (int) os_getmode(argv, 0);
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
int res = _umask(mask);
|
||||||
|
#else
|
||||||
|
int res = umask(mask);
|
||||||
|
#endif
|
||||||
|
return janet_wrap_integer(janet_perm_to_unix(res));
|
||||||
|
}
|
||||||
|
|
||||||
static Janet os_dir(int32_t argc, Janet *argv) {
|
static Janet os_dir(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, 2);
|
janet_arity(argc, 1, 2);
|
||||||
const char *dir = janet_getcstring(argv, 0);
|
const char *dir = janet_getcstring(argv, 0);
|
||||||
@ -949,6 +1206,31 @@ static Janet os_rename(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet os_realpath(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
(void) argv;
|
||||||
|
janet_panic("os/realpath not supported on Windows");
|
||||||
|
#else
|
||||||
|
const char *src = janet_getcstring(argv, 0);
|
||||||
|
char *dest = realpath(src, NULL);
|
||||||
|
if (NULL == dest) janet_panicf("%s: %s", strerror(errno), src);
|
||||||
|
Janet ret = janet_cstringv(dest);
|
||||||
|
free(dest);
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_permission_string(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
return os_make_permstring(os_get_unix_mode(argv, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_permission_int(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
return janet_wrap_integer(os_get_unix_mode(argv, 0));
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* JANET_REDUCED_OS */
|
#endif /* JANET_REDUCED_OS */
|
||||||
|
|
||||||
static const JanetReg os_cfuns[] = {
|
static const JanetReg os_cfuns[] = {
|
||||||
@ -1007,7 +1289,8 @@ static const JanetReg os_cfuns[] = {
|
|||||||
" only that information from stat. If the file or directory does not exist, returns nil. The keys are\n\n"
|
" only that information from stat. If the file or directory does not exist, returns nil. The keys are\n\n"
|
||||||
"\t:dev - the device that the file is on\n"
|
"\t:dev - the device that the file is on\n"
|
||||||
"\t:mode - the type of file, one of :file, :directory, :block, :character, :fifo, :socket, :link, or :other\n"
|
"\t:mode - the type of file, one of :file, :directory, :block, :character, :fifo, :socket, :link, or :other\n"
|
||||||
"\t:permissions - A unix permission string like \"rwx--x--x\"\n"
|
"\t:int-permissions - A Unix permission integer like 8r744\n"
|
||||||
|
"\t:permissions - A Unix permission string like \"rwxr--r--\"\n"
|
||||||
"\t:uid - File uid\n"
|
"\t:uid - File uid\n"
|
||||||
"\t:gid - File gid\n"
|
"\t:gid - File gid\n"
|
||||||
"\t:nlink - number of links to file\n"
|
"\t:nlink - number of links to file\n"
|
||||||
@ -1019,6 +1302,19 @@ static const JanetReg os_cfuns[] = {
|
|||||||
"\t:changed - timestamp when file last chnaged (permissions changed)\n"
|
"\t:changed - timestamp when file last chnaged (permissions changed)\n"
|
||||||
"\t:modified - timestamp when file last modified (content changed)\n")
|
"\t:modified - timestamp when file last modified (content changed)\n")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/lstat", os_lstat,
|
||||||
|
JDOC("(os/lstat path &opt tab|key)\n\n"
|
||||||
|
"Like os/stat, but don't follow symlinks.\n")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/chmod", os_chmod,
|
||||||
|
JDOC("(os/chmod path mode)\n\n"
|
||||||
|
"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.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"os/touch", os_touch,
|
"os/touch", os_touch,
|
||||||
JDOC("(os/touch path &opt actime modtime)\n\n"
|
JDOC("(os/touch path &opt actime modtime)\n\n"
|
||||||
@ -1028,13 +1324,19 @@ static const JanetReg os_cfuns[] = {
|
|||||||
{
|
{
|
||||||
"os/cd", os_cd,
|
"os/cd", os_cd,
|
||||||
JDOC("(os/cd path)\n\n"
|
JDOC("(os/cd path)\n\n"
|
||||||
"Change current directory to path. Returns true on success, false on failure.")
|
"Change current directory to path. Returns nil on success, errors on failure.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/umask", os_umask,
|
||||||
|
JDOC("(os/umask mask)\n\n"
|
||||||
|
"Set a new umask, returns the old umask.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os/mkdir", os_mkdir,
|
"os/mkdir", os_mkdir,
|
||||||
JDOC("(os/mkdir path)\n\n"
|
JDOC("(os/mkdir path)\n\n"
|
||||||
"Create a new directory. The path will be relative to the current directory if relative, otherwise "
|
"Create a new directory. The path will be relative to the current directory if relative, otherwise "
|
||||||
"it will be an absolute path.")
|
"it will be an absolute path. Returns true if the directory was created, false if the directory already exists, and "
|
||||||
|
"errors otherwise.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os/rmdir", os_rmdir,
|
"os/rmdir", os_rmdir,
|
||||||
@ -1049,8 +1351,20 @@ static const JanetReg os_cfuns[] = {
|
|||||||
{
|
{
|
||||||
"os/link", os_link,
|
"os/link", os_link,
|
||||||
JDOC("(os/link oldpath newpath &opt symlink)\n\n"
|
JDOC("(os/link oldpath newpath &opt symlink)\n\n"
|
||||||
"Create a symlink from oldpath to newpath. The 3 optional paramater "
|
"Create a link at newpath that points to oldpath and returns nil. "
|
||||||
"enables a hard link over a soft link. Does not work on Windows.")
|
"Iff symlink is truthy, creates a symlink. "
|
||||||
|
"Iff symlink is falsey or not provided, "
|
||||||
|
"creates a hard link. Does not work on Windows.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/symlink", os_symlink,
|
||||||
|
JDOC("(os/symlink oldpath newpath)\n\n"
|
||||||
|
"Create a symlink from oldpath to newpath, returning nil. Same as (os/link oldpath newpath true).")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/readlink", os_readlink,
|
||||||
|
JDOC("(os/readlink path)\n\n"
|
||||||
|
"Read the contents of a symbolic link. Does not work on Windows.\n")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os/execute", os_execute,
|
"os/execute", os_execute,
|
||||||
@ -1080,6 +1394,16 @@ static const JanetReg os_cfuns[] = {
|
|||||||
"Get the current time expressed as the number of seconds since "
|
"Get the current time expressed as the number of seconds since "
|
||||||
"January 1, 1970, the Unix epoch. Returns a real number.")
|
"January 1, 1970, the Unix epoch. Returns a real number.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/mktime", os_mktime,
|
||||||
|
JDOC("(os/mktime date-struct &opt local)\n\n"
|
||||||
|
"Get the broken down date-struct time expressed as the number "
|
||||||
|
" 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 computed for the local timezone.\n\n"
|
||||||
|
"Inverse function to os/date.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"os/clock", os_clock,
|
"os/clock", os_clock,
|
||||||
JDOC("(os/clock)\n\n"
|
JDOC("(os/clock)\n\n"
|
||||||
@ -1100,14 +1424,14 @@ static const JanetReg os_cfuns[] = {
|
|||||||
{
|
{
|
||||||
"os/cryptorand", os_cryptorand,
|
"os/cryptorand", os_cryptorand,
|
||||||
JDOC("(os/cryptorand n &opt buf)\n\n"
|
JDOC("(os/cryptorand n &opt buf)\n\n"
|
||||||
"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.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os/date", os_date,
|
"os/date", os_date,
|
||||||
JDOC("(os/date &opt time local)\n\n"
|
JDOC("(os/date &opt time local)\n\n"
|
||||||
"Returns the given time as a date struct, or the current time if no time is given. "
|
"Returns the given time as a date struct, or the current time if no time is given. "
|
||||||
"Returns a struct with following key values. Note that all numbers are 0-indexed. "
|
"Returns a struct with following key values. Note that all numbers are 0-indexed. "
|
||||||
"Date is given in UTC unless local is truthy, in which case the date is formated for "
|
"Date is given in UTC unless local is truthy, in which case the date is formatted for "
|
||||||
"the local timezone.\n\n"
|
"the local timezone.\n\n"
|
||||||
"\t:seconds - number of seconds [0-61]\n"
|
"\t:seconds - number of seconds [0-61]\n"
|
||||||
"\t:minutes - number of minutes [0-59]\n"
|
"\t:minutes - number of minutes [0-59]\n"
|
||||||
@ -1124,6 +1448,25 @@ static const JanetReg os_cfuns[] = {
|
|||||||
JDOC("(os/rename oldname newname)\n\n"
|
JDOC("(os/rename oldname newname)\n\n"
|
||||||
"Rename a file on disk to a new path. Returns nil.")
|
"Rename a file on disk to a new path. Returns nil.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/realpath", os_realpath,
|
||||||
|
JDOC("(os/realpath path)\n\n"
|
||||||
|
"Get the absolute path for a given path, following ../, ./, and symlinks. "
|
||||||
|
"Returns an absolute path as a string. Will raise an error on Windows.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/perm-string", os_permission_string,
|
||||||
|
JDOC("(os/perm-string int)\n\n"
|
||||||
|
"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 "
|
||||||
|
"include the file/directory/symlink character as rendered by `ls`.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/perm-int", os_permission_int,
|
||||||
|
JDOC("(os/perm-int bytes)\n\n"
|
||||||
|
"Parse a 9 character permission string and return an integer that can be used by chmod.")
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
149
src/core/parse.c
149
src/core/parse.c
@ -26,6 +26,9 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define JANET_PARSER_DEAD 0x1
|
||||||
|
#define JANET_PARSER_GENERATED_ERROR 0x2
|
||||||
|
|
||||||
/* Check if a character is whitespace */
|
/* Check if a character is whitespace */
|
||||||
static int is_whitespace(uint8_t c) {
|
static int is_whitespace(uint8_t c) {
|
||||||
return c == ' '
|
return c == ' '
|
||||||
@ -201,6 +204,8 @@ static int checkescape(uint8_t c) {
|
|||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
case 'x':
|
case 'x':
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
return 1;
|
return 1;
|
||||||
case 'n':
|
case 'n':
|
||||||
return '\n';
|
return '\n';
|
||||||
@ -228,6 +233,24 @@ static int checkescape(uint8_t c) {
|
|||||||
/* Forward declare */
|
/* Forward declare */
|
||||||
static int stringchar(JanetParser *p, JanetParseState *state, uint8_t c);
|
static int stringchar(JanetParser *p, JanetParseState *state, uint8_t c);
|
||||||
|
|
||||||
|
static void write_codepoint(JanetParser *p, int32_t codepoint) {
|
||||||
|
if (codepoint <= 0x7F) {
|
||||||
|
push_buf(p, (uint8_t) codepoint);
|
||||||
|
} else if (codepoint <= 0x7FF) {
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 6) & 0x1F) | 0xC0);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 0) & 0x3F) | 0x80);
|
||||||
|
} else if (codepoint <= 0xFFFF) {
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 12) & 0x0F) | 0xE0);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 6) & 0x3F) | 0x80);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 0) & 0x3F) | 0x80);
|
||||||
|
} else {
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 18) & 0x07) | 0xF0);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 12) & 0x3F) | 0x80);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 6) & 0x3F) | 0x80);
|
||||||
|
push_buf(p, (uint8_t)((codepoint >> 0) & 0x3F) | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int escapeh(JanetParser *p, JanetParseState *state, uint8_t c) {
|
static int escapeh(JanetParser *p, JanetParseState *state, uint8_t c) {
|
||||||
int digit = to_hex(c);
|
int digit = to_hex(c);
|
||||||
if (digit < 0) {
|
if (digit < 0) {
|
||||||
@ -237,7 +260,27 @@ static int escapeh(JanetParser *p, JanetParseState *state, uint8_t c) {
|
|||||||
state->argn = (state->argn << 4) + digit;
|
state->argn = (state->argn << 4) + digit;
|
||||||
state->counter--;
|
state->counter--;
|
||||||
if (!state->counter) {
|
if (!state->counter) {
|
||||||
push_buf(p, (state->argn & 0xFF));
|
push_buf(p, (uint8_t)(state->argn & 0xFF));
|
||||||
|
state->argn = 0;
|
||||||
|
state->consumer = stringchar;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int escapeu(JanetParser *p, JanetParseState *state, uint8_t c) {
|
||||||
|
int digit = to_hex(c);
|
||||||
|
if (digit < 0) {
|
||||||
|
p->error = "invalid hex digit in unicode escape";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
state->argn = (state->argn << 4) + digit;
|
||||||
|
state->counter--;
|
||||||
|
if (!state->counter) {
|
||||||
|
if (state->argn > 0x10FFFF) {
|
||||||
|
p->error = "invalid unicode codepoint";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
write_codepoint(p, state->argn);
|
||||||
state->argn = 0;
|
state->argn = 0;
|
||||||
state->consumer = stringchar;
|
state->consumer = stringchar;
|
||||||
}
|
}
|
||||||
@ -254,6 +297,10 @@ static int escape1(JanetParser *p, JanetParseState *state, uint8_t c) {
|
|||||||
state->counter = 2;
|
state->counter = 2;
|
||||||
state->argn = 0;
|
state->argn = 0;
|
||||||
state->consumer = escapeh;
|
state->consumer = escapeh;
|
||||||
|
} else if (c == 'u' || c == 'U') {
|
||||||
|
state->counter = c == 'u' ? 4 : 6;
|
||||||
|
state->argn = 0;
|
||||||
|
state->consumer = escapeu;
|
||||||
} else {
|
} else {
|
||||||
push_buf(p, (uint8_t) e);
|
push_buf(p, (uint8_t) e);
|
||||||
state->consumer = stringchar;
|
state->consumer = stringchar;
|
||||||
@ -393,21 +440,23 @@ static Janet close_array(JanetParser *p, JanetParseState *state) {
|
|||||||
|
|
||||||
static Janet close_struct(JanetParser *p, JanetParseState *state) {
|
static Janet close_struct(JanetParser *p, JanetParseState *state) {
|
||||||
JanetKV *st = janet_struct_begin(state->argn >> 1);
|
JanetKV *st = janet_struct_begin(state->argn >> 1);
|
||||||
for (int32_t i = state->argn; i > 0; i -= 2) {
|
for (size_t i = p->argcount - state->argn; i < p->argcount; i += 2) {
|
||||||
Janet value = p->args[--p->argcount];
|
Janet key = p->args[i];
|
||||||
Janet key = p->args[--p->argcount];
|
Janet value = p->args[i + 1];
|
||||||
janet_struct_put(st, key, value);
|
janet_struct_put(st, key, value);
|
||||||
}
|
}
|
||||||
|
p->argcount -= state->argn;
|
||||||
return janet_wrap_struct(janet_struct_end(st));
|
return janet_wrap_struct(janet_struct_end(st));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet close_table(JanetParser *p, JanetParseState *state) {
|
static Janet close_table(JanetParser *p, JanetParseState *state) {
|
||||||
JanetTable *table = janet_table(state->argn >> 1);
|
JanetTable *table = janet_table(state->argn >> 1);
|
||||||
for (int32_t i = state->argn; i > 0; i -= 2) {
|
for (size_t i = p->argcount - state->argn; i < p->argcount; i += 2) {
|
||||||
Janet value = p->args[--p->argcount];
|
Janet key = p->args[i];
|
||||||
Janet key = p->args[--p->argcount];
|
Janet value = p->args[i + 1];
|
||||||
janet_table_put(table, key, value);
|
janet_table_put(table, key, value);
|
||||||
}
|
}
|
||||||
|
p->argcount -= state->argn;
|
||||||
return janet_wrap_table(table);
|
return janet_wrap_table(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,11 +640,30 @@ void janet_parser_eof(JanetParser *parser) {
|
|||||||
size_t oldline = parser->line;
|
size_t oldline = parser->line;
|
||||||
janet_parser_consume(parser, '\n');
|
janet_parser_consume(parser, '\n');
|
||||||
if (parser->statecount > 1) {
|
if (parser->statecount > 1) {
|
||||||
parser->error = "unexpected end of source";
|
JanetParseState *s = parser->states + (parser->statecount - 1);
|
||||||
|
JanetBuffer *buffer = janet_buffer(40);
|
||||||
|
janet_buffer_push_cstring(buffer, "unexpected end of source, ");
|
||||||
|
if (s->flags & PFLAG_PARENS) {
|
||||||
|
janet_buffer_push_u8(buffer, '(');
|
||||||
|
} else if (s->flags & PFLAG_SQRBRACKETS) {
|
||||||
|
janet_buffer_push_u8(buffer, '[');
|
||||||
|
} else if (s->flags & PFLAG_CURLYBRACKETS) {
|
||||||
|
janet_buffer_push_u8(buffer, '{');
|
||||||
|
} else if (s->flags & PFLAG_STRING) {
|
||||||
|
janet_buffer_push_u8(buffer, '"');
|
||||||
|
} else if (s->flags & PFLAG_LONGSTRING) {
|
||||||
|
int32_t i;
|
||||||
|
for (i = 0; i < s->argn; i++) {
|
||||||
|
janet_buffer_push_u8(buffer, '`');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
janet_formatb(buffer, " opened at line %d, column %d", s->line, s->column);
|
||||||
|
parser->error = (const char *) janet_string(buffer->data, buffer->count);
|
||||||
|
parser->flag |= JANET_PARSER_GENERATED_ERROR;
|
||||||
}
|
}
|
||||||
parser->line = oldline;
|
parser->line = oldline;
|
||||||
parser->column = oldcolumn;
|
parser->column = oldcolumn;
|
||||||
parser->flag = 1;
|
parser->flag |= JANET_PARSER_DEAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum JanetParserStatus janet_parser_status(JanetParser *parser) {
|
enum JanetParserStatus janet_parser_status(JanetParser *parser) {
|
||||||
@ -617,6 +685,7 @@ const char *janet_parser_error(JanetParser *parser) {
|
|||||||
if (status == JANET_PARSE_ERROR) {
|
if (status == JANET_PARSE_ERROR) {
|
||||||
const char *e = parser->error;
|
const char *e = parser->error;
|
||||||
parser->error = NULL;
|
parser->error = NULL;
|
||||||
|
parser->flag &= ~JANET_PARSER_GENERATED_ERROR;
|
||||||
janet_parser_flush(parser);
|
janet_parser_flush(parser);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -720,6 +789,9 @@ static int parsermark(void *p, size_t size) {
|
|||||||
for (i = 0; i < parser->argcount; i++) {
|
for (i = 0; i < parser->argcount; i++) {
|
||||||
janet_mark(parser->args[i]);
|
janet_mark(parser->args[i]);
|
||||||
}
|
}
|
||||||
|
if (parser->flag & JANET_PARSER_GENERATED_ERROR) {
|
||||||
|
janet_mark(janet_wrap_string(parser->error));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -732,7 +804,7 @@ static int parsergc(void *p, size_t size) {
|
|||||||
|
|
||||||
static int parserget(void *p, Janet key, Janet *out);
|
static int parserget(void *p, Janet key, Janet *out);
|
||||||
|
|
||||||
static JanetAbstractType janet_parse_parsertype = {
|
const JanetAbstractType janet_parser_type = {
|
||||||
"core/parser",
|
"core/parser",
|
||||||
parsergc,
|
parsergc,
|
||||||
parsermark,
|
parsermark,
|
||||||
@ -744,14 +816,14 @@ static JanetAbstractType janet_parse_parsertype = {
|
|||||||
static Janet cfun_parse_parser(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_parser(int32_t argc, Janet *argv) {
|
||||||
(void) argv;
|
(void) argv;
|
||||||
janet_fixarity(argc, 0);
|
janet_fixarity(argc, 0);
|
||||||
JanetParser *p = janet_abstract(&janet_parse_parsertype, sizeof(JanetParser));
|
JanetParser *p = janet_abstract(&janet_parser_type, sizeof(JanetParser));
|
||||||
janet_parser_init(p);
|
janet_parser_init(p);
|
||||||
return janet_wrap_abstract(p);
|
return janet_wrap_abstract(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, 3);
|
janet_arity(argc, 2, 3);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
JanetByteView view = janet_getbytes(argv, 1);
|
JanetByteView view = janet_getbytes(argv, 1);
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
int32_t offset = janet_getinteger(argv, 2);
|
int32_t offset = janet_getinteger(argv, 2);
|
||||||
@ -776,14 +848,14 @@ static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_parse_eof(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_eof(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
janet_parser_eof(p);
|
janet_parser_eof(p);
|
||||||
return argv[0];
|
return argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 2);
|
janet_fixarity(argc, 2);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
JanetParseState *s = p->states + p->statecount - 1;
|
JanetParseState *s = p->states + p->statecount - 1;
|
||||||
if (s->consumer == tokenchar) {
|
if (s->consumer == tokenchar) {
|
||||||
janet_parser_consume(p, ' ');
|
janet_parser_consume(p, ' ');
|
||||||
@ -817,13 +889,13 @@ static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_parse_has_more(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_has_more(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
return janet_wrap_boolean(janet_parser_has_more(p));
|
return janet_wrap_boolean(janet_parser_has_more(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_byte(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_byte(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 2);
|
janet_fixarity(argc, 2);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
int32_t i = janet_getinteger(argv, 1);
|
int32_t i = janet_getinteger(argv, 1);
|
||||||
janet_parser_consume(p, 0xFF & i);
|
janet_parser_consume(p, 0xFF & i);
|
||||||
return argv[0];
|
return argv[0];
|
||||||
@ -831,7 +903,7 @@ static Janet cfun_parse_byte(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_parse_status(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_status(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
const char *stat = NULL;
|
const char *stat = NULL;
|
||||||
switch (janet_parser_status(p)) {
|
switch (janet_parser_status(p)) {
|
||||||
case JANET_PARSE_PENDING:
|
case JANET_PARSE_PENDING:
|
||||||
@ -852,28 +924,32 @@ static Janet cfun_parse_status(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_parse_error(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_error(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
const char *err = janet_parser_error(p);
|
const char *err = janet_parser_error(p);
|
||||||
if (err) return janet_cstringv(err);
|
if (err) {
|
||||||
|
return (p->flag & JANET_PARSER_GENERATED_ERROR)
|
||||||
|
? janet_wrap_string(err)
|
||||||
|
: janet_cstringv(err);
|
||||||
|
}
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_produce(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_produce(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
return janet_parser_produce(p);
|
return janet_parser_produce(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_flush(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_flush(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
janet_parser_flush(p);
|
janet_parser_flush(p);
|
||||||
return argv[0];
|
return argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_parse_where(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_where(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
Janet *tup = janet_tuple_begin(2);
|
Janet *tup = janet_tuple_begin(2);
|
||||||
tup[0] = janet_wrap_integer(p->line);
|
tup[0] = janet_wrap_integer(p->line);
|
||||||
tup[1] = janet_wrap_integer(p->column);
|
tup[1] = janet_wrap_integer(p->column);
|
||||||
@ -953,31 +1029,30 @@ struct ParserStateGetter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Janet parser_state_delimiters(const JanetParser *_p) {
|
static Janet parser_state_delimiters(const JanetParser *_p) {
|
||||||
JanetParser *clone = janet_abstract(&janet_parse_parsertype, sizeof(JanetParser));
|
JanetParser *p = (JanetParser *)_p;
|
||||||
janet_parser_clone(_p, clone);
|
|
||||||
size_t i;
|
size_t i;
|
||||||
const uint8_t *str;
|
const uint8_t *str;
|
||||||
size_t oldcount;
|
size_t oldcount;
|
||||||
oldcount = clone->bufcount;
|
oldcount = p->bufcount;
|
||||||
for (i = 0; i < clone->statecount; i++) {
|
for (i = 0; i < p->statecount; i++) {
|
||||||
JanetParseState *s = clone->states + i;
|
JanetParseState *s = p->states + i;
|
||||||
if (s->flags & PFLAG_PARENS) {
|
if (s->flags & PFLAG_PARENS) {
|
||||||
push_buf(clone, '(');
|
push_buf(p, '(');
|
||||||
} else if (s->flags & PFLAG_SQRBRACKETS) {
|
} else if (s->flags & PFLAG_SQRBRACKETS) {
|
||||||
push_buf(clone, '[');
|
push_buf(p, '[');
|
||||||
} else if (s->flags & PFLAG_CURLYBRACKETS) {
|
} else if (s->flags & PFLAG_CURLYBRACKETS) {
|
||||||
push_buf(clone, '{');
|
push_buf(p, '{');
|
||||||
} else if (s->flags & PFLAG_STRING) {
|
} else if (s->flags & PFLAG_STRING) {
|
||||||
push_buf(clone, '"');
|
push_buf(p, '"');
|
||||||
} else if (s->flags & PFLAG_LONGSTRING) {
|
} else if (s->flags & PFLAG_LONGSTRING) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
for (i = 0; i < s->argn; i++) {
|
for (i = 0; i < s->argn; i++) {
|
||||||
push_buf(clone, '`');
|
push_buf(p, '`');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str = janet_string(clone->buf + oldcount, (int32_t)(clone->bufcount - oldcount));
|
str = janet_string(p->buf + oldcount, (int32_t)(p->bufcount - oldcount));
|
||||||
clone->bufcount = oldcount;
|
p->bufcount = oldcount;
|
||||||
return janet_wrap_string(str);
|
return janet_wrap_string(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,7 +1079,7 @@ static const struct ParserStateGetter parser_state_getters[] = {
|
|||||||
static Janet cfun_parse_state(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_state(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, 2);
|
janet_arity(argc, 1, 2);
|
||||||
const uint8_t *key = NULL;
|
const uint8_t *key = NULL;
|
||||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
key = janet_getkeyword(argv, 1);
|
key = janet_getkeyword(argv, 1);
|
||||||
}
|
}
|
||||||
@ -1031,8 +1106,8 @@ static Janet cfun_parse_state(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_parse_clone(int32_t argc, Janet *argv) {
|
static Janet cfun_parse_clone(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetParser *src = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
JanetParser *src = janet_getabstract(argv, 0, &janet_parser_type);
|
||||||
JanetParser *dest = janet_abstract(&janet_parse_parsertype, sizeof(JanetParser));
|
JanetParser *dest = janet_abstract(&janet_parser_type, sizeof(JanetParser));
|
||||||
janet_parser_clone(src, dest);
|
janet_parser_clone(src, dest);
|
||||||
return janet_wrap_abstract(dest);
|
return janet_wrap_abstract(dest);
|
||||||
}
|
}
|
||||||
|
@ -35,34 +35,6 @@
|
|||||||
* Runtime
|
* Runtime
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* opcodes for peg vm */
|
|
||||||
typedef enum {
|
|
||||||
RULE_LITERAL, /* [len, bytes...] */
|
|
||||||
RULE_NCHAR, /* [n] */
|
|
||||||
RULE_NOTNCHAR, /* [n] */
|
|
||||||
RULE_RANGE, /* [lo | hi << 16 (1 word)] */
|
|
||||||
RULE_SET, /* [bitmap (8 words)] */
|
|
||||||
RULE_LOOK, /* [offset, rule] */
|
|
||||||
RULE_CHOICE, /* [len, rules...] */
|
|
||||||
RULE_SEQUENCE, /* [len, rules...] */
|
|
||||||
RULE_IF, /* [rule_a, rule_b (b if a)] */
|
|
||||||
RULE_IFNOT, /* [rule_a, rule_b (b if not a)] */
|
|
||||||
RULE_NOT, /* [rule] */
|
|
||||||
RULE_BETWEEN, /* [lo, hi, rule] */
|
|
||||||
RULE_GETTAG, /* [searchtag, tag] */
|
|
||||||
RULE_CAPTURE, /* [rule, tag] */
|
|
||||||
RULE_POSITION, /* [tag] */
|
|
||||||
RULE_ARGUMENT, /* [argument-index, tag] */
|
|
||||||
RULE_CONSTANT, /* [constant, tag] */
|
|
||||||
RULE_ACCUMULATE, /* [rule, tag] */
|
|
||||||
RULE_GROUP, /* [rule, tag] */
|
|
||||||
RULE_REPLACE, /* [rule, constant, tag] */
|
|
||||||
RULE_MATCHTIME, /* [rule, constant, tag] */
|
|
||||||
RULE_ERROR, /* [rule] */
|
|
||||||
RULE_DROP, /* [rule] */
|
|
||||||
RULE_BACKMATCH, /* [tag] */
|
|
||||||
} Opcode;
|
|
||||||
|
|
||||||
/* Hold captured patterns and match state */
|
/* Hold captured patterns and match state */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t *text_start;
|
const uint8_t *text_start;
|
||||||
@ -1016,16 +988,9 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
|
|||||||
* Post-Compilation
|
* Post-Compilation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t *bytecode;
|
|
||||||
Janet *constants;
|
|
||||||
size_t bytecode_len;
|
|
||||||
uint32_t num_constants;
|
|
||||||
} Peg;
|
|
||||||
|
|
||||||
static int peg_mark(void *p, size_t size) {
|
static int peg_mark(void *p, size_t size) {
|
||||||
(void) size;
|
(void) size;
|
||||||
Peg *peg = (Peg *)p;
|
JanetPeg *peg = (JanetPeg *)p;
|
||||||
if (NULL != peg->constants)
|
if (NULL != peg->constants)
|
||||||
for (uint32_t i = 0; i < peg->num_constants; i++)
|
for (uint32_t i = 0; i < peg->num_constants; i++)
|
||||||
janet_mark(peg->constants[i]);
|
janet_mark(peg->constants[i]);
|
||||||
@ -1033,7 +998,7 @@ static int peg_mark(void *p, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void peg_marshal(void *p, JanetMarshalContext *ctx) {
|
static void peg_marshal(void *p, JanetMarshalContext *ctx) {
|
||||||
Peg *peg = (Peg *)p;
|
JanetPeg *peg = (JanetPeg *)p;
|
||||||
janet_marshal_size(ctx, peg->bytecode_len);
|
janet_marshal_size(ctx, peg->bytecode_len);
|
||||||
janet_marshal_int(ctx, (int32_t)peg->num_constants);
|
janet_marshal_int(ctx, (int32_t)peg->num_constants);
|
||||||
janet_marshal_abstract(ctx, p);
|
janet_marshal_abstract(ctx, p);
|
||||||
@ -1055,7 +1020,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
uint32_t num_constants = (uint32_t) janet_unmarshal_int(ctx);
|
uint32_t num_constants = (uint32_t) janet_unmarshal_int(ctx);
|
||||||
|
|
||||||
/* Calculate offsets. Should match those in make_peg */
|
/* Calculate offsets. Should match those in make_peg */
|
||||||
size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t));
|
size_t bytecode_start = size_padded(sizeof(JanetPeg), sizeof(uint32_t));
|
||||||
size_t bytecode_size = bytecode_len * sizeof(uint32_t);
|
size_t bytecode_size = bytecode_len * sizeof(uint32_t);
|
||||||
size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
|
size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
|
||||||
size_t total_size = constants_start + sizeof(Janet) * (size_t) num_constants;
|
size_t total_size = constants_start + sizeof(Janet) * (size_t) num_constants;
|
||||||
@ -1065,7 +1030,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
|
|
||||||
/* Allocate PEG */
|
/* Allocate PEG */
|
||||||
char *mem = janet_unmarshal_abstract(ctx, total_size);
|
char *mem = janet_unmarshal_abstract(ctx, total_size);
|
||||||
Peg *peg = (Peg *)mem;
|
JanetPeg *peg = (JanetPeg *)mem;
|
||||||
uint32_t *bytecode = (uint32_t *)(mem + bytecode_start);
|
uint32_t *bytecode = (uint32_t *)(mem + bytecode_start);
|
||||||
Janet *constants = (Janet *)(mem + constants_start);
|
Janet *constants = (Janet *)(mem + constants_start);
|
||||||
peg->bytecode = NULL;
|
peg->bytecode = NULL;
|
||||||
@ -1208,7 +1173,7 @@ bad:
|
|||||||
|
|
||||||
static int cfun_peg_getter(JanetAbstract a, Janet key, Janet *out);
|
static int cfun_peg_getter(JanetAbstract a, Janet key, Janet *out);
|
||||||
|
|
||||||
static const JanetAbstractType peg_type = {
|
const JanetAbstractType janet_peg_type = {
|
||||||
"core/peg",
|
"core/peg",
|
||||||
NULL,
|
NULL,
|
||||||
peg_mark,
|
peg_mark,
|
||||||
@ -1219,15 +1184,15 @@ static const JanetAbstractType peg_type = {
|
|||||||
JANET_ATEND_UNMARSHAL
|
JANET_ATEND_UNMARSHAL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Convert Builder to Peg (Janet Abstract Value) */
|
/* Convert Builder to JanetPeg (Janet Abstract Value) */
|
||||||
static Peg *make_peg(Builder *b) {
|
static JanetPeg *make_peg(Builder *b) {
|
||||||
size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t));
|
size_t bytecode_start = size_padded(sizeof(JanetPeg), sizeof(uint32_t));
|
||||||
size_t bytecode_size = janet_v_count(b->bytecode) * sizeof(uint32_t);
|
size_t bytecode_size = janet_v_count(b->bytecode) * sizeof(uint32_t);
|
||||||
size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
|
size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
|
||||||
size_t constants_size = janet_v_count(b->constants) * sizeof(Janet);
|
size_t constants_size = janet_v_count(b->constants) * sizeof(Janet);
|
||||||
size_t total_size = constants_start + constants_size;
|
size_t total_size = constants_start + constants_size;
|
||||||
char *mem = janet_abstract(&peg_type, total_size);
|
char *mem = janet_abstract(&janet_peg_type, total_size);
|
||||||
Peg *peg = (Peg *)mem;
|
JanetPeg *peg = (JanetPeg *)mem;
|
||||||
peg->bytecode = (uint32_t *)(mem + bytecode_start);
|
peg->bytecode = (uint32_t *)(mem + bytecode_start);
|
||||||
peg->constants = (Janet *)(mem + constants_start);
|
peg->constants = (Janet *)(mem + constants_start);
|
||||||
peg->num_constants = janet_v_count(b->constants);
|
peg->num_constants = janet_v_count(b->constants);
|
||||||
@ -1238,7 +1203,7 @@ static Peg *make_peg(Builder *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compiler entry point */
|
/* Compiler entry point */
|
||||||
static Peg *compile_peg(Janet x) {
|
static JanetPeg *compile_peg(Janet x) {
|
||||||
Builder builder;
|
Builder builder;
|
||||||
builder.grammar = janet_table(0);
|
builder.grammar = janet_table(0);
|
||||||
builder.default_grammar = janet_get_core_table("default-peg-grammar");
|
builder.default_grammar = janet_get_core_table("default-peg-grammar");
|
||||||
@ -1249,7 +1214,7 @@ static Peg *compile_peg(Janet x) {
|
|||||||
builder.form = x;
|
builder.form = x;
|
||||||
builder.depth = JANET_RECURSION_GUARD;
|
builder.depth = JANET_RECURSION_GUARD;
|
||||||
peg_compile1(&builder, x);
|
peg_compile1(&builder, x);
|
||||||
Peg *peg = make_peg(&builder);
|
JanetPeg *peg = make_peg(&builder);
|
||||||
builder_cleanup(&builder);
|
builder_cleanup(&builder);
|
||||||
return peg;
|
return peg;
|
||||||
}
|
}
|
||||||
@ -1260,15 +1225,15 @@ static Peg *compile_peg(Janet x) {
|
|||||||
|
|
||||||
static Janet cfun_peg_compile(int32_t argc, Janet *argv) {
|
static Janet cfun_peg_compile(int32_t argc, Janet *argv) {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
Peg *peg = compile_peg(argv[0]);
|
JanetPeg *peg = compile_peg(argv[0]);
|
||||||
return janet_wrap_abstract(peg);
|
return janet_wrap_abstract(peg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_peg_match(int32_t argc, Janet *argv) {
|
static Janet cfun_peg_match(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 2, -1);
|
janet_arity(argc, 2, -1);
|
||||||
Peg *peg;
|
JanetPeg *peg;
|
||||||
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
||||||
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &peg_type) {
|
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
|
||||||
peg = janet_unwrap_abstract(argv[0]);
|
peg = janet_unwrap_abstract(argv[0]);
|
||||||
} else {
|
} else {
|
||||||
peg = compile_peg(argv[0]);
|
peg = compile_peg(argv[0]);
|
||||||
@ -1327,7 +1292,7 @@ static const JanetReg peg_cfuns[] = {
|
|||||||
/* Load the peg module */
|
/* Load the peg module */
|
||||||
void janet_lib_peg(JanetTable *env) {
|
void janet_lib_peg(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, peg_cfuns);
|
janet_core_cfuns(env, NULL, peg_cfuns);
|
||||||
janet_register_abstract_type(&peg_type);
|
janet_register_abstract_type(&janet_peg_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ifdef JANET_PEG */
|
#endif /* ifdef JANET_PEG */
|
||||||
|
@ -156,7 +156,7 @@ static void janet_escape_string_impl(JanetBuffer *buffer, const uint8_t *str, in
|
|||||||
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\\\", 2);
|
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\\\", 2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (c < 32 || c > 127) {
|
if (c < 32 || c > 126) {
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
buf[0] = '\\';
|
buf[0] = '\\';
|
||||||
buf[1] = 'x';
|
buf[1] = 'x';
|
||||||
@ -459,8 +459,8 @@ static const char *janet_pretty_colors[] = {
|
|||||||
|
|
||||||
#define JANET_PRETTY_DICT_ONELINE 4
|
#define JANET_PRETTY_DICT_ONELINE 4
|
||||||
#define JANET_PRETTY_IND_ONELINE 10
|
#define JANET_PRETTY_IND_ONELINE 10
|
||||||
#define JANET_PRETTY_DICT_LIMIT 16
|
#define JANET_PRETTY_DICT_LIMIT 30
|
||||||
#define JANET_PRETTY_ARRAY_LIMIT 16
|
#define JANET_PRETTY_ARRAY_LIMIT 160
|
||||||
|
|
||||||
/* Helper for pretty printing */
|
/* Helper for pretty printing */
|
||||||
static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
||||||
@ -591,6 +591,11 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
|||||||
if (is_dict_value && len >= JANET_PRETTY_DICT_ONELINE) print_newline(S, 0);
|
if (is_dict_value && len >= JANET_PRETTY_DICT_ONELINE) print_newline(S, 0);
|
||||||
for (i = 0; i < cap; i++) {
|
for (i = 0; i < cap; i++) {
|
||||||
if (!janet_checktype(kvs[i].key, JANET_NIL)) {
|
if (!janet_checktype(kvs[i].key, JANET_NIL)) {
|
||||||
|
if (counter == JANET_PRETTY_DICT_LIMIT) {
|
||||||
|
print_newline(S, 0);
|
||||||
|
janet_buffer_push_cstring(S->buffer, "...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (first_kv_pair) {
|
if (first_kv_pair) {
|
||||||
first_kv_pair = 0;
|
first_kv_pair = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -600,11 +605,6 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
|||||||
janet_buffer_push_u8(S->buffer, ' ');
|
janet_buffer_push_u8(S->buffer, ' ');
|
||||||
janet_pretty_one(S, kvs[i].value, 1);
|
janet_pretty_one(S, kvs[i].value, 1);
|
||||||
counter++;
|
counter++;
|
||||||
if (counter == 10) {
|
|
||||||
print_newline(S, 0);
|
|
||||||
janet_buffer_push_cstring(S->buffer, "...");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,7 +728,7 @@ static const char *scanformat(
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void janet_formatb(JanetBuffer *b, const char *format, va_list args) {
|
void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
|
||||||
const char *format_end = format + strlen(format);
|
const char *format_end = format + strlen(format);
|
||||||
const char *c = format;
|
const char *c = format;
|
||||||
int32_t startlen = b->count;
|
int32_t startlen = b->count;
|
||||||
@ -853,7 +853,7 @@ const uint8_t *janet_formatc(const char *format, ...) {
|
|||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
/* Run format */
|
/* Run format */
|
||||||
janet_formatb(&buffer, format, args);
|
janet_formatbv(&buffer, format, args);
|
||||||
|
|
||||||
/* Iterate length */
|
/* Iterate length */
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@ -863,6 +863,14 @@ const uint8_t *janet_formatc(const char *format, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JanetBuffer *janet_formatb(JanetBuffer *buffer, const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
janet_formatbv(buffer, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Shared implementation between string/format and
|
/* Shared implementation between string/format and
|
||||||
* buffer/format */
|
* buffer/format */
|
||||||
void janet_buffer_format(
|
void janet_buffer_format(
|
||||||
|
@ -54,6 +54,10 @@ extern JANET_THREAD_LOCAL Janet *janet_vm_return_reg;
|
|||||||
* along with otherwise bare c function pointers. */
|
* along with otherwise bare c function pointers. */
|
||||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
extern JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||||
|
|
||||||
|
/* Registry for abstract abstract types that can be marshalled.
|
||||||
|
* We need this to look up the constructors when unmarshalling. */
|
||||||
|
extern JANET_THREAD_LOCAL JanetTable *janet_vm_abstract_registry;
|
||||||
|
|
||||||
/* Immutable value cache */
|
/* Immutable value cache */
|
||||||
extern JANET_THREAD_LOCAL const uint8_t **janet_vm_cache;
|
extern JANET_THREAD_LOCAL const uint8_t **janet_vm_cache;
|
||||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_capacity;
|
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_capacity;
|
||||||
|
@ -123,7 +123,8 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
|||||||
dist = otherdist;
|
dist = otherdist;
|
||||||
hash = otherhash;
|
hash = otherhash;
|
||||||
} else if (status == 0) {
|
} else if (status == 0) {
|
||||||
/* A key was added to the struct more than once */
|
/* A key was added to the struct more than once - replace old value */
|
||||||
|
kv->value = value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,7 +409,7 @@ int janet_thread_receive(Janet *msg_out, double timeout) {
|
|||||||
|
|
||||||
static int janet_thread_getter(void *p, Janet key, Janet *out);
|
static int janet_thread_getter(void *p, Janet key, Janet *out);
|
||||||
|
|
||||||
static JanetAbstractType Thread_AT = {
|
const JanetAbstractType janet_thread_type = {
|
||||||
"core/thread",
|
"core/thread",
|
||||||
thread_gc,
|
thread_gc,
|
||||||
thread_mark,
|
thread_mark,
|
||||||
@ -418,7 +418,7 @@ static JanetAbstractType Thread_AT = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static JanetThread *janet_make_thread(JanetMailbox *mailbox, JanetTable *encode) {
|
static JanetThread *janet_make_thread(JanetMailbox *mailbox, JanetTable *encode) {
|
||||||
JanetThread *thread = janet_abstract(&Thread_AT, sizeof(JanetThread));
|
JanetThread *thread = janet_abstract(&janet_thread_type, sizeof(JanetThread));
|
||||||
janet_mailbox_ref(mailbox, 1);
|
janet_mailbox_ref(mailbox, 1);
|
||||||
thread->mailbox = mailbox;
|
thread->mailbox = mailbox;
|
||||||
thread->encode = encode;
|
thread->encode = encode;
|
||||||
@ -426,7 +426,7 @@ static JanetThread *janet_make_thread(JanetMailbox *mailbox, JanetTable *encode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JanetThread *janet_getthread(const Janet *argv, int32_t n) {
|
JanetThread *janet_getthread(const Janet *argv, int32_t n) {
|
||||||
return (JanetThread *) janet_getabstract(argv, n, &Thread_AT);
|
return (JanetThread *) janet_getabstract(argv, n, &janet_thread_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Runs in new thread */
|
/* Runs in new thread */
|
||||||
@ -668,7 +668,7 @@ static const JanetReg threadlib_cfuns[] = {
|
|||||||
/* Module entry point */
|
/* Module entry point */
|
||||||
void janet_lib_thread(JanetTable *env) {
|
void janet_lib_thread(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, threadlib_cfuns);
|
janet_core_cfuns(env, NULL, threadlib_cfuns);
|
||||||
janet_register_abstract_type(&Thread_AT);
|
janet_register_abstract_type(&janet_thread_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -111,7 +111,7 @@ static void *ta_buffer_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JanetAbstractType ta_buffer_type = {
|
const JanetAbstractType janet_ta_buffer_type = {
|
||||||
"ta/buffer",
|
"ta/buffer",
|
||||||
ta_buffer_gc,
|
ta_buffer_gc,
|
||||||
NULL,
|
NULL,
|
||||||
@ -154,7 +154,7 @@ static void *ta_view_unmarshal(JanetMarshalContext *ctx) {
|
|||||||
offset = janet_unmarshal_size(ctx);
|
offset = janet_unmarshal_size(ctx);
|
||||||
buffer = janet_unmarshal_janet(ctx);
|
buffer = janet_unmarshal_janet(ctx);
|
||||||
if (!janet_checktype(buffer, JANET_ABSTRACT) ||
|
if (!janet_checktype(buffer, JANET_ABSTRACT) ||
|
||||||
(janet_abstract_type(janet_unwrap_abstract(buffer)) != &ta_buffer_type)) {
|
(janet_abstract_type(janet_unwrap_abstract(buffer)) != &janet_ta_buffer_type)) {
|
||||||
janet_panicf("expected typed array buffer");
|
janet_panicf("expected typed array buffer");
|
||||||
}
|
}
|
||||||
view->buffer = (JanetTArrayBuffer *)janet_unwrap_abstract(buffer);
|
view->buffer = (JanetTArrayBuffer *)janet_unwrap_abstract(buffer);
|
||||||
@ -275,7 +275,7 @@ static void ta_setter(void *p, Janet key, Janet value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JanetAbstractType ta_view_type = {
|
const JanetAbstractType janet_ta_view_type = {
|
||||||
"ta/view",
|
"ta/view",
|
||||||
NULL,
|
NULL,
|
||||||
ta_mark,
|
ta_mark,
|
||||||
@ -287,7 +287,7 @@ static const JanetAbstractType ta_view_type = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
JanetTArrayBuffer *janet_tarray_buffer(size_t size) {
|
JanetTArrayBuffer *janet_tarray_buffer(size_t size) {
|
||||||
JanetTArrayBuffer *buf = janet_abstract(&ta_buffer_type, sizeof(JanetTArrayBuffer));
|
JanetTArrayBuffer *buf = janet_abstract(&janet_ta_buffer_type, sizeof(JanetTArrayBuffer));
|
||||||
ta_buffer_init(buf, size);
|
ta_buffer_init(buf, size);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -299,13 +299,13 @@ JanetTArrayView *janet_tarray_view(
|
|||||||
size_t offset,
|
size_t offset,
|
||||||
JanetTArrayBuffer *buffer) {
|
JanetTArrayBuffer *buffer) {
|
||||||
|
|
||||||
JanetTArrayView *view = janet_abstract(&ta_view_type, sizeof(JanetTArrayView));
|
JanetTArrayView *view = janet_abstract(&janet_ta_view_type, sizeof(JanetTArrayView));
|
||||||
|
|
||||||
if ((stride < 1) || (size < 1)) janet_panic("stride and size should be > 0");
|
if ((stride < 1) || (size < 1)) janet_panic("stride and size should be > 0");
|
||||||
size_t buf_size = offset + ta_type_sizes[type] * ((size - 1) * stride + 1);
|
size_t buf_size = offset + ta_type_sizes[type] * ((size - 1) * stride + 1);
|
||||||
|
|
||||||
if (NULL == buffer) {
|
if (NULL == buffer) {
|
||||||
buffer = janet_abstract(&ta_buffer_type, sizeof(JanetTArrayBuffer));
|
buffer = janet_abstract(&janet_ta_buffer_type, sizeof(JanetTArrayBuffer));
|
||||||
ta_buffer_init(buffer, buf_size);
|
ta_buffer_init(buffer, buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,15 +325,15 @@ JanetTArrayView *janet_tarray_view(
|
|||||||
}
|
}
|
||||||
|
|
||||||
JanetTArrayBuffer *janet_gettarray_buffer(const Janet *argv, int32_t n) {
|
JanetTArrayBuffer *janet_gettarray_buffer(const Janet *argv, int32_t n) {
|
||||||
return janet_getabstract(argv, n, &ta_buffer_type);
|
return janet_getabstract(argv, n, &janet_ta_buffer_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
JanetTArrayView *janet_gettarray_any(const Janet *argv, int32_t n) {
|
JanetTArrayView *janet_gettarray_any(const Janet *argv, int32_t n) {
|
||||||
return janet_getabstract(argv, n, &ta_view_type);
|
return janet_getabstract(argv, n, &janet_ta_view_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
JanetTArrayView *janet_gettarray_view(const Janet *argv, int32_t n, JanetTArrayType type) {
|
JanetTArrayView *janet_gettarray_view(const Janet *argv, int32_t n, JanetTArrayType type) {
|
||||||
JanetTArrayView *view = janet_getabstract(argv, n, &ta_view_type);
|
JanetTArrayView *view = janet_getabstract(argv, n, &janet_ta_view_type);
|
||||||
if (view->type != type) {
|
if (view->type != type) {
|
||||||
janet_panicf("bad slot #%d, expected typed array of type %s, got %v",
|
janet_panicf("bad slot #%d, expected typed array of type %s, got %v",
|
||||||
n, ta_type_names[type], argv[n]);
|
n, ta_type_names[type], argv[n]);
|
||||||
@ -359,7 +359,7 @@ static Janet cfun_typed_array_new(int32_t argc, Janet *argv) {
|
|||||||
4, argv[4]);
|
4, argv[4]);
|
||||||
}
|
}
|
||||||
void *p = janet_unwrap_abstract(argv[4]);
|
void *p = janet_unwrap_abstract(argv[4]);
|
||||||
if (janet_abstract_type(p) == &ta_view_type) {
|
if (janet_abstract_type(p) == &janet_ta_view_type) {
|
||||||
JanetTArrayView *view = (JanetTArrayView *)p;
|
JanetTArrayView *view = (JanetTArrayView *)p;
|
||||||
offset = (view->buffer->data - view->as.u8) + offset * ta_type_sizes[view->type];
|
offset = (view->buffer->data - view->as.u8) + offset * ta_type_sizes[view->type];
|
||||||
stride *= view->stride;
|
stride *= view->stride;
|
||||||
@ -375,7 +375,7 @@ static Janet cfun_typed_array_new(int32_t argc, Janet *argv) {
|
|||||||
static JanetTArrayView *ta_is_view(Janet x) {
|
static JanetTArrayView *ta_is_view(Janet x) {
|
||||||
if (!janet_checktype(x, JANET_ABSTRACT)) return NULL;
|
if (!janet_checktype(x, JANET_ABSTRACT)) return NULL;
|
||||||
void *abst = janet_unwrap_abstract(x);
|
void *abst = janet_unwrap_abstract(x);
|
||||||
if (janet_abstract_type(abst) != &ta_view_type) return NULL;
|
if (janet_abstract_type(abst) != &janet_ta_view_type) return NULL;
|
||||||
return (JanetTArrayView *)abst;
|
return (JanetTArrayView *)abst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ static Janet cfun_typed_array_size(int32_t argc, Janet *argv) {
|
|||||||
if ((view = ta_is_view(argv[0]))) {
|
if ((view = ta_is_view(argv[0]))) {
|
||||||
return janet_wrap_number((double) view->size);
|
return janet_wrap_number((double) view->size);
|
||||||
}
|
}
|
||||||
JanetTArrayBuffer *buf = (JanetTArrayBuffer *)janet_getabstract(argv, 0, &ta_buffer_type);
|
JanetTArrayBuffer *buf = (JanetTArrayBuffer *)janet_getabstract(argv, 0, &janet_ta_buffer_type);
|
||||||
return janet_wrap_number((double) buf->size);
|
return janet_wrap_number((double) buf->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +433,7 @@ static Janet cfun_typed_array_properties(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_typed_array_slice(int32_t argc, Janet *argv) {
|
static Janet cfun_typed_array_slice(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
JanetTArrayView *src = janet_getabstract(argv, 0, &ta_view_type);
|
JanetTArrayView *src = janet_getabstract(argv, 0, &janet_ta_view_type);
|
||||||
JanetRange range;
|
JanetRange range;
|
||||||
int32_t length = (int32_t)src->size;
|
int32_t length = (int32_t)src->size;
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
@ -461,9 +461,9 @@ static Janet cfun_typed_array_slice(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_typed_array_copy_bytes(int32_t argc, Janet *argv) {
|
static Janet cfun_typed_array_copy_bytes(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 4, 5);
|
janet_arity(argc, 4, 5);
|
||||||
JanetTArrayView *src = janet_getabstract(argv, 0, &ta_view_type);
|
JanetTArrayView *src = janet_getabstract(argv, 0, &janet_ta_view_type);
|
||||||
size_t index_src = janet_getsize(argv, 1);
|
size_t index_src = janet_getsize(argv, 1);
|
||||||
JanetTArrayView *dst = janet_getabstract(argv, 2, &ta_view_type);
|
JanetTArrayView *dst = janet_getabstract(argv, 2, &janet_ta_view_type);
|
||||||
size_t index_dst = janet_getsize(argv, 3);
|
size_t index_dst = janet_getsize(argv, 3);
|
||||||
size_t count = (argc == 5) ? janet_getsize(argv, 4) : 1;
|
size_t count = (argc == 5) ? janet_getsize(argv, 4) : 1;
|
||||||
size_t src_atom_size = ta_type_sizes[src->type];
|
size_t src_atom_size = ta_type_sizes[src->type];
|
||||||
@ -488,9 +488,9 @@ static Janet cfun_typed_array_copy_bytes(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
static Janet cfun_typed_array_swap_bytes(int32_t argc, Janet *argv) {
|
static Janet cfun_typed_array_swap_bytes(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 4, 5);
|
janet_arity(argc, 4, 5);
|
||||||
JanetTArrayView *src = janet_getabstract(argv, 0, &ta_view_type);
|
JanetTArrayView *src = janet_getabstract(argv, 0, &janet_ta_view_type);
|
||||||
size_t index_src = janet_getsize(argv, 1);
|
size_t index_src = janet_getsize(argv, 1);
|
||||||
JanetTArrayView *dst = janet_getabstract(argv, 2, &ta_view_type);
|
JanetTArrayView *dst = janet_getabstract(argv, 2, &janet_ta_view_type);
|
||||||
size_t index_dst = janet_getsize(argv, 3);
|
size_t index_dst = janet_getsize(argv, 3);
|
||||||
size_t count = (argc == 5) ? janet_getsize(argv, 4) : 1;
|
size_t count = (argc == 5) ? janet_getsize(argv, 4) : 1;
|
||||||
size_t src_atom_size = ta_type_sizes[src->type];
|
size_t src_atom_size = ta_type_sizes[src->type];
|
||||||
@ -574,8 +574,8 @@ static JanetMethod tarray_view_methods[] = {
|
|||||||
/* Module entry point */
|
/* Module entry point */
|
||||||
void janet_lib_typed_array(JanetTable *env) {
|
void janet_lib_typed_array(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, ta_cfuns);
|
janet_core_cfuns(env, NULL, ta_cfuns);
|
||||||
janet_register_abstract_type(&ta_buffer_type);
|
janet_register_abstract_type(&janet_ta_buffer_type);
|
||||||
janet_register_abstract_type(&ta_view_type);
|
janet_register_abstract_type(&janet_ta_view_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -380,7 +380,7 @@ void janet_var(JanetTable *env, const char *name, Janet val, const char *doc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load many cfunctions at once */
|
/* Load many cfunctions at once */
|
||||||
void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
static void _janet_cfuns_prefix(JanetTable *env, const char *regprefix, const JanetReg *cfuns, int defprefix) {
|
||||||
uint8_t *longname_buffer = NULL;
|
uint8_t *longname_buffer = NULL;
|
||||||
size_t prefixlen = 0;
|
size_t prefixlen = 0;
|
||||||
size_t bufsize = 0;
|
size_t bufsize = 0;
|
||||||
@ -414,47 +414,46 @@ void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns)
|
|||||||
name = janet_csymbolv(cfuns->name);
|
name = janet_csymbolv(cfuns->name);
|
||||||
}
|
}
|
||||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||||
|
if (defprefix) {
|
||||||
|
JanetTable *subt = janet_table(2);
|
||||||
|
janet_table_put(subt, janet_ckeywordv("value"), fun);
|
||||||
|
if (cfuns->documentation)
|
||||||
|
janet_table_put(subt, janet_ckeywordv("doc"), janet_cstringv(cfuns->documentation));
|
||||||
|
janet_table_put(env, name, janet_wrap_table(subt));
|
||||||
|
} else {
|
||||||
janet_def(env, cfuns->name, fun, cfuns->documentation);
|
janet_def(env, cfuns->name, fun, cfuns->documentation);
|
||||||
|
}
|
||||||
janet_table_put(janet_vm_registry, fun, name);
|
janet_table_put(janet_vm_registry, fun, name);
|
||||||
cfuns++;
|
cfuns++;
|
||||||
}
|
}
|
||||||
free(longname_buffer);
|
free(longname_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void janet_cfuns_prefix(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
||||||
|
_janet_cfuns_prefix(env, regprefix, cfuns, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
||||||
|
_janet_cfuns_prefix(env, regprefix, cfuns, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Abstract type introspection */
|
/* Abstract type introspection */
|
||||||
|
|
||||||
static const JanetAbstractType type_wrap = {
|
|
||||||
"core/type-info",
|
|
||||||
JANET_ATEND_NAME
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const JanetAbstractType *at;
|
|
||||||
} JanetAbstractTypeWrap;
|
|
||||||
|
|
||||||
void janet_register_abstract_type(const JanetAbstractType *at) {
|
void janet_register_abstract_type(const JanetAbstractType *at) {
|
||||||
JanetAbstractTypeWrap *abstract = (JanetAbstractTypeWrap *)
|
|
||||||
janet_abstract(&type_wrap, sizeof(JanetAbstractTypeWrap));
|
|
||||||
abstract->at = at;
|
|
||||||
Janet sym = janet_csymbolv(at->name);
|
Janet sym = janet_csymbolv(at->name);
|
||||||
if (!(janet_checktype(janet_table_get(janet_vm_registry, sym), JANET_NIL))) {
|
if (!(janet_checktype(janet_table_get(janet_vm_abstract_registry, sym), JANET_NIL))) {
|
||||||
janet_panicf("cannot register abstract type %s, "
|
janet_panicf("cannot register abstract type %s, "
|
||||||
"a type with the same name exists", at->name);
|
"a type with the same name exists", at->name);
|
||||||
}
|
}
|
||||||
janet_table_put(janet_vm_registry, sym, janet_wrap_abstract(abstract));
|
janet_table_put(janet_vm_abstract_registry, sym, janet_wrap_pointer((void *) at));
|
||||||
}
|
}
|
||||||
|
|
||||||
const JanetAbstractType *janet_get_abstract_type(Janet key) {
|
const JanetAbstractType *janet_get_abstract_type(Janet key) {
|
||||||
Janet twrap = janet_table_get(janet_vm_registry, key);
|
Janet wrapped = janet_table_get(janet_vm_abstract_registry, key);
|
||||||
if (janet_checktype(twrap, JANET_NIL)) {
|
if (janet_checktype(wrapped, JANET_NIL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!janet_checktype(twrap, JANET_ABSTRACT) ||
|
return (JanetAbstractType *)(janet_unwrap_pointer(wrapped));
|
||||||
(janet_abstract_type(janet_unwrap_abstract(twrap)) != &type_wrap)) {
|
|
||||||
janet_panic("expected abstract type");
|
|
||||||
}
|
|
||||||
JanetAbstractTypeWrap *w = (JanetAbstractTypeWrap *)janet_unwrap_abstract(twrap);
|
|
||||||
return w->at;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef JANET_BOOTSTRAP
|
#ifndef JANET_BOOTSTRAP
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
/* VM state */
|
/* VM state */
|
||||||
JANET_THREAD_LOCAL JanetTable *janet_vm_core_env;
|
JANET_THREAD_LOCAL JanetTable *janet_vm_core_env;
|
||||||
JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||||
|
JANET_THREAD_LOCAL JanetTable *janet_vm_abstract_registry;
|
||||||
JANET_THREAD_LOCAL int janet_vm_stackn = 0;
|
JANET_THREAD_LOCAL int janet_vm_stackn = 0;
|
||||||
JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber = NULL;
|
JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber = NULL;
|
||||||
JANET_THREAD_LOCAL JanetFiber *janet_vm_root_fiber = NULL;
|
JANET_THREAD_LOCAL JanetFiber *janet_vm_root_fiber = NULL;
|
||||||
@ -89,8 +90,8 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
|||||||
func = janet_stack_frame(stack)->func; \
|
func = janet_stack_frame(stack)->func; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define vm_return(sig, val) do { \
|
#define vm_return(sig, val) do { \
|
||||||
vm_commit(); \
|
|
||||||
janet_vm_return_reg[0] = (val); \
|
janet_vm_return_reg[0] = (val); \
|
||||||
|
vm_commit(); \
|
||||||
return (sig); \
|
return (sig); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -107,13 +108,13 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
|||||||
#define vm_assert_type(X, T) do { \
|
#define vm_assert_type(X, T) do { \
|
||||||
if (!(janet_checktype((X), (T)))) { \
|
if (!(janet_checktype((X), (T)))) { \
|
||||||
vm_commit(); \
|
vm_commit(); \
|
||||||
janet_panicf("expected %T, got %t", (1 << (T)), (X)); \
|
janet_panicf("expected %T, got %v", (1 << (T)), (X)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define vm_assert_types(X, TS) do { \
|
#define vm_assert_types(X, TS) do { \
|
||||||
if (!(janet_checktypes((X), (TS)))) { \
|
if (!(janet_checktypes((X), (TS)))) { \
|
||||||
vm_commit(); \
|
vm_commit(); \
|
||||||
janet_panicf("expected %T, got %t", (TS), (X)); \
|
janet_panicf("expected %T, got %v", (TS), (X)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -290,6 +291,10 @@ static Janet janet_binop_call(const char *lmethod, const char *rmethod, Janet lh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out);
|
||||||
|
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out);
|
||||||
|
|
||||||
/* Interpreter main loop */
|
/* Interpreter main loop */
|
||||||
static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||||
|
|
||||||
@ -824,7 +829,8 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
vm_assert(func->def->environments_length > eindex, "invalid upvalue environment");
|
vm_assert(func->def->environments_length > eindex, "invalid upvalue environment");
|
||||||
env = func->envs[eindex];
|
env = func->envs[eindex];
|
||||||
vm_assert(env->length > vindex, "invalid upvalue index");
|
vm_assert(env->length > vindex, "invalid upvalue index");
|
||||||
if (env->offset) {
|
vm_assert(janet_env_valid(env), "invalid upvalue environment");
|
||||||
|
if (env->offset > 0) {
|
||||||
/* On stack */
|
/* On stack */
|
||||||
stack[A] = env->as.fiber->data[env->offset + vindex];
|
stack[A] = env->as.fiber->data[env->offset + vindex];
|
||||||
} else {
|
} else {
|
||||||
@ -841,7 +847,8 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
vm_assert(func->def->environments_length > eindex, "invalid upvalue environment");
|
vm_assert(func->def->environments_length > eindex, "invalid upvalue environment");
|
||||||
env = func->envs[eindex];
|
env = func->envs[eindex];
|
||||||
vm_assert(env->length > vindex, "invalid upvalue index");
|
vm_assert(env->length > vindex, "invalid upvalue index");
|
||||||
if (env->offset) {
|
vm_assert(janet_env_valid(env), "invalid upvalue environment");
|
||||||
|
if (env->offset > 0) {
|
||||||
env->as.fiber->data[env->offset + vindex] = stack[A];
|
env->as.fiber->data[env->offset + vindex] = stack[A];
|
||||||
} else {
|
} else {
|
||||||
env->as.values[vindex] = stack[A];
|
env->as.values[vindex] = stack[A];
|
||||||
@ -904,7 +911,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
if (janet_indexed_view(stack[D], &vals, &len)) {
|
if (janet_indexed_view(stack[D], &vals, &len)) {
|
||||||
janet_fiber_pushn(fiber, vals, len);
|
janet_fiber_pushn(fiber, vals, len);
|
||||||
} else {
|
} else {
|
||||||
janet_panicf("expected %T, got %t", JANET_TFLAG_INDEXED, stack[D]);
|
janet_panicf("expected %T, got %v", JANET_TFLAG_INDEXED, stack[D]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack = fiber->data + fiber->frame;
|
stack = fiber->data + fiber->frame;
|
||||||
@ -997,8 +1004,12 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
Janet retreg;
|
Janet retreg;
|
||||||
vm_assert_type(stack[B], JANET_FIBER);
|
vm_assert_type(stack[B], JANET_FIBER);
|
||||||
JanetFiber *child = janet_unwrap_fiber(stack[B]);
|
JanetFiber *child = janet_unwrap_fiber(stack[B]);
|
||||||
|
if (janet_check_can_resume(child, &retreg)) {
|
||||||
|
vm_commit();
|
||||||
|
janet_panicv(retreg);
|
||||||
|
}
|
||||||
fiber->child = child;
|
fiber->child = child;
|
||||||
JanetSignal sig = janet_continue(child, stack[C], &retreg);
|
JanetSignal sig = janet_continue_no_check(child, stack[C], &retreg);
|
||||||
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
||||||
vm_return(sig, retreg);
|
vm_return(sig, retreg);
|
||||||
}
|
}
|
||||||
@ -1241,10 +1252,7 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
|||||||
return *janet_vm_return_reg;
|
return *janet_vm_return_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter the main vm loop */
|
static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
|
||||||
JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|
||||||
jmp_buf buf;
|
|
||||||
|
|
||||||
/* Check conditions */
|
/* Check conditions */
|
||||||
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||||
if (janet_vm_stackn >= JANET_RECURSION_GUARD) {
|
if (janet_vm_stackn >= JANET_RECURSION_GUARD) {
|
||||||
@ -1261,6 +1269,13 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
*out = janet_wrap_string(str);
|
*out = janet_wrap_string(str);
|
||||||
return JANET_SIGNAL_ERROR;
|
return JANET_SIGNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
return JANET_SIGNAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out) {
|
||||||
|
jmp_buf buf;
|
||||||
|
|
||||||
|
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||||
|
|
||||||
/* Continue child fiber if it exists */
|
/* Continue child fiber if it exists */
|
||||||
if (fiber->child) {
|
if (fiber->child) {
|
||||||
@ -1334,6 +1349,14 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
return signal;
|
return signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enter the main vm loop */
|
||||||
|
JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
||||||
|
/* Check conditions */
|
||||||
|
JanetSignal tmp_signal = janet_check_can_resume(fiber, out);
|
||||||
|
if (tmp_signal) return tmp_signal;
|
||||||
|
return janet_continue_no_check(fiber, in, out);
|
||||||
|
}
|
||||||
|
|
||||||
JanetSignal janet_pcall(
|
JanetSignal janet_pcall(
|
||||||
JanetFunction *fun,
|
JanetFunction *fun,
|
||||||
int32_t argc,
|
int32_t argc,
|
||||||
@ -1387,7 +1410,9 @@ int janet_init(void) {
|
|||||||
janet_scratch_cap = 0;
|
janet_scratch_cap = 0;
|
||||||
/* Initialize registry */
|
/* Initialize registry */
|
||||||
janet_vm_registry = janet_table(0);
|
janet_vm_registry = janet_table(0);
|
||||||
|
janet_vm_abstract_registry = janet_table(0);
|
||||||
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
||||||
|
janet_gcroot(janet_wrap_table(janet_vm_abstract_registry));
|
||||||
/* Core env */
|
/* Core env */
|
||||||
janet_vm_core_env = NULL;
|
janet_vm_core_env = NULL;
|
||||||
/* Seed RNG */
|
/* Seed RNG */
|
||||||
@ -1412,6 +1437,7 @@ void janet_deinit(void) {
|
|||||||
janet_vm_root_count = 0;
|
janet_vm_root_count = 0;
|
||||||
janet_vm_root_capacity = 0;
|
janet_vm_root_capacity = 0;
|
||||||
janet_vm_registry = NULL;
|
janet_vm_registry = NULL;
|
||||||
|
janet_vm_abstract_registry = NULL;
|
||||||
janet_vm_core_env = NULL;
|
janet_vm_core_env = NULL;
|
||||||
janet_vm_fiber = NULL;
|
janet_vm_fiber = NULL;
|
||||||
janet_vm_root_fiber = NULL;
|
janet_vm_root_fiber = NULL;
|
||||||
|
@ -97,7 +97,14 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check big endian */
|
/* Check big endian */
|
||||||
#if defined(__MIPSEB__) /* MIPS 32-bit */ \
|
#if defined(__LITTLE_ENDIAN__) || \
|
||||||
|
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||||
|
/* If we know the target is LE, always use that - e.g. ppc64 little endian
|
||||||
|
* defines the __LITTLE_ENDIAN__ macro in the ABI spec, so we can rely
|
||||||
|
* on that and if that's not defined, fall back to big endian assumption
|
||||||
|
*/
|
||||||
|
#define JANET_LITTLE_ENDIAN 1
|
||||||
|
#elif defined(__MIPSEB__) /* MIPS 32-bit */ \
|
||||||
|| defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \
|
|| defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \
|
||||||
|| defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \
|
|| defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \
|
||||||
|| defined(_M_PPC) || defined(__PPC) \
|
|| defined(_M_PPC) || defined(__PPC) \
|
||||||
@ -661,7 +668,7 @@ struct Janet {
|
|||||||
#define janet_type(x) ((x).type)
|
#define janet_type(x) ((x).type)
|
||||||
#define janet_checktype(x, t) ((x).type == (t))
|
#define janet_checktype(x, t) ((x).type == (t))
|
||||||
#define janet_truthy(x) \
|
#define janet_truthy(x) \
|
||||||
((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.integer & 0x1)))
|
((x).type != JANET_NIL && ((x).type != JANET_BOOLEAN || ((x).as.u64 & 0x1)))
|
||||||
|
|
||||||
#define janet_unwrap_struct(x) ((const JanetKV *)(x).as.pointer)
|
#define janet_unwrap_struct(x) ((const JanetKV *)(x).as.pointer)
|
||||||
#define janet_unwrap_tuple(x) ((const Janet *)(x).as.pointer)
|
#define janet_unwrap_tuple(x) ((const Janet *)(x).as.pointer)
|
||||||
@ -731,8 +738,9 @@ struct JanetStackFrame {
|
|||||||
int32_t flags;
|
int32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Number of Janets a frame takes up in the stack */
|
/* Number of Janets a frame takes up in the stack
|
||||||
#define JANET_FRAME_SIZE ((sizeof(JanetStackFrame) + sizeof(Janet) - 1) / sizeof(Janet))
|
* Should be constant across architectures */
|
||||||
|
#define JANET_FRAME_SIZE 4
|
||||||
|
|
||||||
/* A dynamic array type. */
|
/* A dynamic array type. */
|
||||||
struct JanetArray {
|
struct JanetArray {
|
||||||
@ -810,6 +818,7 @@ struct JanetAbstractHead {
|
|||||||
#define JANET_FUNCDEF_FLAG_HASENVS 0x400000
|
#define JANET_FUNCDEF_FLAG_HASENVS 0x400000
|
||||||
#define JANET_FUNCDEF_FLAG_HASSOURCEMAP 0x800000
|
#define JANET_FUNCDEF_FLAG_HASSOURCEMAP 0x800000
|
||||||
#define JANET_FUNCDEF_FLAG_STRUCTARG 0x1000000
|
#define JANET_FUNCDEF_FLAG_STRUCTARG 0x1000000
|
||||||
|
#define JANET_FUNCDEF_FLAG_HASCLOBITSET 0x2000000
|
||||||
#define JANET_FUNCDEF_FLAG_TAG 0xFFFF
|
#define JANET_FUNCDEF_FLAG_TAG 0xFFFF
|
||||||
|
|
||||||
/* Source mapping structure for a bytecode instruction */
|
/* Source mapping structure for a bytecode instruction */
|
||||||
@ -825,6 +834,7 @@ struct JanetFuncDef {
|
|||||||
Janet *constants;
|
Janet *constants;
|
||||||
JanetFuncDef **defs;
|
JanetFuncDef **defs;
|
||||||
uint32_t *bytecode;
|
uint32_t *bytecode;
|
||||||
|
uint32_t *closure_bitset; /* Bit set indicating which slots can be referenced by closures. */
|
||||||
|
|
||||||
/* Various debug information */
|
/* Various debug information */
|
||||||
JanetSourceMapping *sourcemap;
|
JanetSourceMapping *sourcemap;
|
||||||
@ -892,8 +902,9 @@ struct JanetParser {
|
|||||||
int flag;
|
int flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A context for marshaling and unmarshaling abstract types */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *m_state; /* void* to not expose MarshalState ?*/
|
void *m_state;
|
||||||
void *u_state;
|
void *u_state;
|
||||||
int flags;
|
int flags;
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
@ -970,6 +981,12 @@ struct JanetRNG {
|
|||||||
uint32_t counter;
|
uint32_t counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct JanetFile JanetFile;
|
||||||
|
struct JanetFile {
|
||||||
|
FILE *file;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
/* Thread types */
|
/* Thread types */
|
||||||
#ifdef JANET_THREADS
|
#ifdef JANET_THREADS
|
||||||
typedef struct JanetThread JanetThread;
|
typedef struct JanetThread JanetThread;
|
||||||
@ -1105,6 +1122,7 @@ JANET_API void janet_loop(void);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Parsing */
|
/* Parsing */
|
||||||
|
extern JANET_API const JanetAbstractType janet_parser_type;
|
||||||
JANET_API void janet_parser_init(JanetParser *parser);
|
JANET_API void janet_parser_init(JanetParser *parser);
|
||||||
JANET_API void janet_parser_deinit(JanetParser *parser);
|
JANET_API void janet_parser_deinit(JanetParser *parser);
|
||||||
JANET_API void janet_parser_consume(JanetParser *parser, uint8_t c);
|
JANET_API void janet_parser_consume(JanetParser *parser, uint8_t c);
|
||||||
@ -1166,6 +1184,7 @@ JANET_API void janet_debug_find(
|
|||||||
JanetString source, int32_t line, int32_t column);
|
JanetString source, int32_t line, int32_t column);
|
||||||
|
|
||||||
/* RNG */
|
/* RNG */
|
||||||
|
extern JANET_API const JanetAbstractType janet_rng_type;
|
||||||
JANET_API JanetRNG *janet_default_rng(void);
|
JANET_API JanetRNG *janet_default_rng(void);
|
||||||
JANET_API void janet_rng_seed(JanetRNG *rng, uint32_t seed);
|
JANET_API void janet_rng_seed(JanetRNG *rng, uint32_t seed);
|
||||||
JANET_API void janet_rng_longseed(JanetRNG *rng, const uint8_t *bytes, int32_t len);
|
JANET_API void janet_rng_longseed(JanetRNG *rng, const uint8_t *bytes, int32_t len);
|
||||||
@ -1229,7 +1248,8 @@ JANET_API void janet_description_b(JanetBuffer *buffer, Janet x);
|
|||||||
#define janet_cstringv(cstr) janet_wrap_string(janet_cstring(cstr))
|
#define janet_cstringv(cstr) janet_wrap_string(janet_cstring(cstr))
|
||||||
#define janet_stringv(str, len) janet_wrap_string(janet_string((str), (len)))
|
#define janet_stringv(str, len) janet_wrap_string(janet_string((str), (len)))
|
||||||
JANET_API JanetString janet_formatc(const char *format, ...);
|
JANET_API JanetString janet_formatc(const char *format, ...);
|
||||||
JANET_API void janet_formatb(JanetBuffer *bufp, const char *format, va_list args);
|
JANET_API JanetBuffer *janet_formatb(JanetBuffer *bufp, const char *format, ...);
|
||||||
|
JANET_API void janet_formatbv(JanetBuffer *bufp, const char *format, va_list args);
|
||||||
|
|
||||||
/* Symbol functions */
|
/* Symbol functions */
|
||||||
JANET_API JanetSymbol janet_symbol(const uint8_t *str, int32_t len);
|
JANET_API JanetSymbol janet_symbol(const uint8_t *str, int32_t len);
|
||||||
@ -1479,6 +1499,8 @@ JANET_API JanetArray *janet_optarray(const Janet *argv, int32_t argc, int32_t n,
|
|||||||
JANET_API Janet janet_dyn(const char *name);
|
JANET_API Janet janet_dyn(const char *name);
|
||||||
JANET_API void janet_setdyn(const char *name, Janet value);
|
JANET_API void janet_setdyn(const char *name, Janet value);
|
||||||
|
|
||||||
|
extern JANET_API const JanetAbstractType janet_file_type;
|
||||||
|
|
||||||
#define JANET_FILE_WRITE 1
|
#define JANET_FILE_WRITE 1
|
||||||
#define JANET_FILE_READ 2
|
#define JANET_FILE_READ 2
|
||||||
#define JANET_FILE_APPEND 4
|
#define JANET_FILE_APPEND 4
|
||||||
@ -1516,8 +1538,52 @@ JANET_API JanetAbstract janet_unmarshal_abstract(JanetMarshalContext *ctx, size_
|
|||||||
JANET_API void janet_register_abstract_type(const JanetAbstractType *at);
|
JANET_API void janet_register_abstract_type(const JanetAbstractType *at);
|
||||||
JANET_API const JanetAbstractType *janet_get_abstract_type(Janet key);
|
JANET_API const JanetAbstractType *janet_get_abstract_type(Janet key);
|
||||||
|
|
||||||
|
#ifdef JANET_PEG
|
||||||
|
|
||||||
|
extern JANET_API const JanetAbstractType janet_peg_type;
|
||||||
|
|
||||||
|
/* opcodes for peg vm */
|
||||||
|
typedef enum {
|
||||||
|
RULE_LITERAL, /* [len, bytes...] */
|
||||||
|
RULE_NCHAR, /* [n] */
|
||||||
|
RULE_NOTNCHAR, /* [n] */
|
||||||
|
RULE_RANGE, /* [lo | hi << 16 (1 word)] */
|
||||||
|
RULE_SET, /* [bitmap (8 words)] */
|
||||||
|
RULE_LOOK, /* [offset, rule] */
|
||||||
|
RULE_CHOICE, /* [len, rules...] */
|
||||||
|
RULE_SEQUENCE, /* [len, rules...] */
|
||||||
|
RULE_IF, /* [rule_a, rule_b (b if a)] */
|
||||||
|
RULE_IFNOT, /* [rule_a, rule_b (b if not a)] */
|
||||||
|
RULE_NOT, /* [rule] */
|
||||||
|
RULE_BETWEEN, /* [lo, hi, rule] */
|
||||||
|
RULE_GETTAG, /* [searchtag, tag] */
|
||||||
|
RULE_CAPTURE, /* [rule, tag] */
|
||||||
|
RULE_POSITION, /* [tag] */
|
||||||
|
RULE_ARGUMENT, /* [argument-index, tag] */
|
||||||
|
RULE_CONSTANT, /* [constant, tag] */
|
||||||
|
RULE_ACCUMULATE, /* [rule, tag] */
|
||||||
|
RULE_GROUP, /* [rule, tag] */
|
||||||
|
RULE_REPLACE, /* [rule, constant, tag] */
|
||||||
|
RULE_MATCHTIME, /* [rule, constant, tag] */
|
||||||
|
RULE_ERROR, /* [rule] */
|
||||||
|
RULE_DROP, /* [rule] */
|
||||||
|
RULE_BACKMATCH, /* [tag] */
|
||||||
|
} JanetPegOpcode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t *bytecode;
|
||||||
|
Janet *constants;
|
||||||
|
size_t bytecode_len;
|
||||||
|
uint32_t num_constants;
|
||||||
|
} JanetPeg;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JANET_TYPED_ARRAY
|
#ifdef JANET_TYPED_ARRAY
|
||||||
|
|
||||||
|
extern JANET_API const JanetAbstractType janet_ta_view_type;
|
||||||
|
extern JANET_API const JanetAbstractType janet_ta_buffer_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JANET_TARRAY_TYPE_U8,
|
JANET_TARRAY_TYPE_U8,
|
||||||
JANET_TARRAY_TYPE_S8,
|
JANET_TARRAY_TYPE_S8,
|
||||||
@ -1568,6 +1634,9 @@ JanetTArrayView *janet_gettarray_any(const Janet *argv, int32_t n);
|
|||||||
|
|
||||||
#ifdef JANET_INT_TYPES
|
#ifdef JANET_INT_TYPES
|
||||||
|
|
||||||
|
extern JANET_API const JanetAbstractType janet_s64_type;
|
||||||
|
extern JANET_API const JanetAbstractType janet_u64_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JANET_INT_NONE,
|
JANET_INT_NONE,
|
||||||
JANET_INT_S64,
|
JANET_INT_S64,
|
||||||
@ -1584,6 +1653,15 @@ JANET_API int janet_scan_uint64(const uint8_t *str, int32_t len, uint64_t *out);
|
|||||||
|
|
||||||
#endif
|
#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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/***** END SECTION MAIN *****/
|
/***** END SECTION MAIN *****/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -515,6 +515,147 @@ static void check_specials(JanetByteView src) {
|
|||||||
check_cmatch(src, "while");
|
check_cmatch(src, "while");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void resolve_format(JanetTable *entry) {
|
||||||
|
int is_macro = janet_truthy(janet_table_get(entry, janet_ckeywordv("macro")));
|
||||||
|
Janet refv = janet_table_get(entry, janet_ckeywordv("ref"));
|
||||||
|
int is_ref = janet_checktype(refv, JANET_ARRAY);
|
||||||
|
Janet value = janet_wrap_nil();
|
||||||
|
if (is_ref) {
|
||||||
|
JanetArray *a = janet_unwrap_array(refv);
|
||||||
|
if (a->count) value = a->data[0];
|
||||||
|
} else {
|
||||||
|
value = janet_table_get(entry, janet_ckeywordv("value"));
|
||||||
|
}
|
||||||
|
if (is_macro) {
|
||||||
|
fprintf(stderr, " macro\n");
|
||||||
|
gbl_lines_below++;
|
||||||
|
} else if (is_ref) {
|
||||||
|
janet_eprintf(" var (%t)\n", value);
|
||||||
|
gbl_lines_below++;
|
||||||
|
} else {
|
||||||
|
janet_eprintf(" %t\n", value);
|
||||||
|
gbl_lines_below++;
|
||||||
|
}
|
||||||
|
Janet sm = janet_table_get(entry, janet_ckeywordv("source-map"));
|
||||||
|
Janet path = janet_get(sm, janet_wrap_integer(0));
|
||||||
|
Janet line = janet_get(sm, janet_wrap_integer(1));
|
||||||
|
Janet col = janet_get(sm, janet_wrap_integer(2));
|
||||||
|
if (janet_checktype(path, JANET_STRING) && janet_truthy(line) && janet_truthy(col)) {
|
||||||
|
janet_eprintf(" %S on line %v, column %v\n", janet_unwrap_string(path), line, col);
|
||||||
|
gbl_lines_below++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doc_format(JanetString doc, int32_t width) {
|
||||||
|
int32_t maxcol = width - 8;
|
||||||
|
uint8_t wordbuf[256] = {0};
|
||||||
|
int32_t wordp = 0;
|
||||||
|
int32_t current = 0;
|
||||||
|
if (maxcol > 200) maxcol = 200;
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
for (int32_t i = 0; i < janet_string_length(doc); i++) {
|
||||||
|
uint8_t b = doc[i];
|
||||||
|
switch (b) {
|
||||||
|
default: {
|
||||||
|
if (maxcol <= current + wordp + 1) {
|
||||||
|
if (!current) {
|
||||||
|
fwrite(wordbuf, wordp, 1, stderr);
|
||||||
|
wordp = 0;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
gbl_lines_below++;
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
wordbuf[wordp++] = b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '\t': {
|
||||||
|
if (maxcol <= current + wordp + 2) {
|
||||||
|
if (!current) {
|
||||||
|
fwrite(wordbuf, wordp, 1, stderr);
|
||||||
|
wordp = 0;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
gbl_lines_below++;
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
wordbuf[wordp++] = ' ';
|
||||||
|
wordbuf[wordp++] = ' ';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '\n':
|
||||||
|
case ' ': {
|
||||||
|
if (wordp) {
|
||||||
|
int32_t oldcur = current;
|
||||||
|
int spacer = maxcol > current + wordp + 1;
|
||||||
|
if (spacer) current++;
|
||||||
|
else current = 0;
|
||||||
|
current += wordp;
|
||||||
|
if (oldcur) fprintf(stderr, spacer ? " " : "\n ");
|
||||||
|
if (oldcur && !spacer) gbl_lines_below++;
|
||||||
|
fwrite(wordbuf, wordp, 1, stderr);
|
||||||
|
wordp = 0;
|
||||||
|
}
|
||||||
|
if (b == '\n') {
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
gbl_lines_below++;
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wordp) {
|
||||||
|
int32_t oldcur = current;
|
||||||
|
int spacer = maxcol > current + wordp + 1;
|
||||||
|
if (spacer) current++;
|
||||||
|
else current = 0;
|
||||||
|
current += wordp + 1;
|
||||||
|
if (oldcur) fprintf(stderr, spacer ? " " : "\n ");
|
||||||
|
if (oldcur && !spacer) gbl_lines_below++;
|
||||||
|
fwrite(wordbuf, wordp, 1, stderr);
|
||||||
|
wordp = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_matches(JanetByteView prefix) {
|
||||||
|
JanetTable *env = gbl_complete_env;
|
||||||
|
gbl_match_count = 0;
|
||||||
|
while (NULL != env) {
|
||||||
|
JanetKV *kvend = env->data + env->capacity;
|
||||||
|
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
||||||
|
if (!janet_checktype(kv->key, JANET_SYMBOL)) continue;
|
||||||
|
const uint8_t *sym = janet_unwrap_symbol(kv->key);
|
||||||
|
check_match(prefix, sym, janet_string_length(sym));
|
||||||
|
}
|
||||||
|
env = env->proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kshowdoc(void) {
|
||||||
|
if (!gbl_complete_env) return;
|
||||||
|
while (is_symbol_char_gen(gbl_buf[gbl_pos])) gbl_pos++;
|
||||||
|
JanetByteView prefix = get_symprefix();
|
||||||
|
Janet symbol = janet_symbolv(prefix.bytes, prefix.len);
|
||||||
|
Janet entry = janet_table_get(gbl_complete_env, symbol);
|
||||||
|
if (!janet_checktype(entry, JANET_TABLE)) return;
|
||||||
|
Janet doc = janet_table_get(janet_unwrap_table(entry), janet_ckeywordv("doc"));
|
||||||
|
if (!janet_checktype(doc, JANET_STRING)) return;
|
||||||
|
JanetString docs = janet_unwrap_string(doc);
|
||||||
|
int num_cols = getcols();
|
||||||
|
clearlines();
|
||||||
|
fprintf(stderr, "\n\n\n");
|
||||||
|
gbl_lines_below += 3;
|
||||||
|
resolve_format(janet_unwrap_table(entry));
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
gbl_lines_below += 1;
|
||||||
|
doc_format(docs, num_cols);
|
||||||
|
fprintf(stderr, "\n\n");
|
||||||
|
gbl_lines_below += 2;
|
||||||
|
/* Go up to original line (zsh-like autocompletion) */
|
||||||
|
fprintf(stderr, "\x1B[%dA", gbl_lines_below);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
static void kshowcomp(void) {
|
static void kshowcomp(void) {
|
||||||
JanetTable *env = gbl_complete_env;
|
JanetTable *env = gbl_complete_env;
|
||||||
if (env == NULL) {
|
if (env == NULL) {
|
||||||
@ -530,17 +671,7 @@ static void kshowcomp(void) {
|
|||||||
JanetByteView prefix = get_symprefix();
|
JanetByteView prefix = get_symprefix();
|
||||||
if (prefix.len == 0) return;
|
if (prefix.len == 0) return;
|
||||||
|
|
||||||
/* Find all matches */
|
find_matches(prefix);
|
||||||
gbl_match_count = 0;
|
|
||||||
while (NULL != env) {
|
|
||||||
JanetKV *kvend = env->data + env->capacity;
|
|
||||||
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
|
||||||
if (!janet_checktype(kv->key, JANET_SYMBOL)) continue;
|
|
||||||
const uint8_t *sym = janet_unwrap_symbol(kv->key);
|
|
||||||
check_match(prefix, sym, janet_string_length(sym));
|
|
||||||
}
|
|
||||||
env = env->proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_specials(prefix);
|
check_specials(prefix);
|
||||||
|
|
||||||
@ -633,6 +764,10 @@ static int line() {
|
|||||||
case 6: /* ctrl-f */
|
case 6: /* ctrl-f */
|
||||||
kright();
|
kright();
|
||||||
break;
|
break;
|
||||||
|
case 7: /* ctrl-g */
|
||||||
|
kshowdoc();
|
||||||
|
refresh();
|
||||||
|
break;
|
||||||
case 127: /* backspace */
|
case 127: /* backspace */
|
||||||
case 8: /* ctrl-h */
|
case 8: /* ctrl-h */
|
||||||
kbackspace(1);
|
kbackspace(1);
|
||||||
|
22
test/fuzzers/fuzz_dostring.c
Normal file
22
test/fuzzers/fuzz_dostring.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
char *new_str = (char *)malloc(size + 1);
|
||||||
|
if (new_str == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(new_str, data, size);
|
||||||
|
new_str[size] = '\0';
|
||||||
|
|
||||||
|
/* janet logic */
|
||||||
|
janet_init();
|
||||||
|
JanetTable *env = janet_core_env(NULL);
|
||||||
|
janet_dostring(env, new_str, "main", NULL);
|
||||||
|
janet_deinit();
|
||||||
|
|
||||||
|
free(new_str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
(defn assert
|
(defn assert
|
||||||
"Override's the default assert with some nice error handling."
|
"Override's the default assert with some nice error handling."
|
||||||
[x e]
|
[x &opt e]
|
||||||
|
(default e "assert error")
|
||||||
(++ num-tests-run)
|
(++ num-tests-run)
|
||||||
(when x (++ num-tests-passed))
|
(when x (++ num-tests-passed))
|
||||||
(if x
|
(if x
|
||||||
|
@ -206,6 +206,10 @@
|
|||||||
(def 🐮 :cow)
|
(def 🐮 :cow)
|
||||||
(assert (= (string "🐼" 🦊 🐮) "🐼foxcow") "emojis 🙉 :)")
|
(assert (= (string "🐼" 🦊 🐮) "🐼foxcow") "emojis 🙉 :)")
|
||||||
(assert (not= 🦊 "🦊") "utf8 strings are not symbols and vice versa")
|
(assert (not= 🦊 "🦊") "utf8 strings are not symbols and vice versa")
|
||||||
|
(assert (= "\U01F637" "😷") "unicode escape 1")
|
||||||
|
(assert (= "\u2623" "\U002623" "☣") "unicode escape 2")
|
||||||
|
(assert (= "\u24c2" "\U0024c2" "Ⓜ") "unicode escape 3")
|
||||||
|
(assert (= "\u0061" "a") "unicode escape 4")
|
||||||
|
|
||||||
# Symbols with @ character
|
# Symbols with @ character
|
||||||
|
|
||||||
@ -250,6 +254,11 @@
|
|||||||
(assert (apply <= (merge @[1 3 5] @[2 4 6 6 6 9])) "merge sort merge 3")
|
(assert (apply <= (merge @[1 3 5] @[2 4 6 6 6 9])) "merge sort merge 3")
|
||||||
(assert (apply <= (merge '(1 3 5) @[2 4 6 6 6 9])) "merge sort merge 4")
|
(assert (apply <= (merge '(1 3 5) @[2 4 6 6 6 9])) "merge sort merge 4")
|
||||||
|
|
||||||
|
(assert (deep= @[1 2 3 4 5] (sort @[5 3 4 1 2])) "sort 1")
|
||||||
|
(assert (deep= @[{:a 1} {:a 4} {:a 7}] (sort-by |($ :a) @[{:a 4} {:a 7} {:a 1}])) "sort 2")
|
||||||
|
(assert (deep= @[1 2 3 4 5] (sorted [5 3 4 1 2])) "sort 3")
|
||||||
|
(assert (deep= @[{:a 1} {:a 4} {:a 7}] (sorted-by |($ :a) [{:a 4} {:a 7} {:a 1}])) "sort 4")
|
||||||
|
|
||||||
# Gensym tests
|
# Gensym tests
|
||||||
|
|
||||||
(assert (not= (gensym) (gensym)) "two gensyms not equal")
|
(assert (not= (gensym) (gensym)) "two gensyms not equal")
|
||||||
@ -319,5 +328,11 @@
|
|||||||
(assert (= true ;(map truthy? [0 "" true @{} {} [] '()])) "truthy values")
|
(assert (= true ;(map truthy? [0 "" true @{} {} [] '()])) "truthy values")
|
||||||
(assert (= false ;(map truthy? [nil false])) "non-truthy values")
|
(assert (= false ;(map truthy? [nil false])) "non-truthy values")
|
||||||
|
|
||||||
|
# Struct and Table duplicate elements
|
||||||
|
(assert (= {:a 3 :b 2} {:a 1 :b 2 :a 3}) "struct literal duplicate keys")
|
||||||
|
(assert (= {:a 3 :b 2} (struct :a 1 :b 2 :a 3)) "struct constructor duplicate keys")
|
||||||
|
(assert (deep= @{:a 3 :b 2} @{:a 1 :b 2 :a 3}) "table literal duplicate keys")
|
||||||
|
(assert (deep= @{:a 3 :b 2} (table :a 1 :b 2 :a 3)) "table constructor duplicate keys")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
@ -259,4 +259,26 @@
|
|||||||
(assert (array= (array/slice @[1 2 3] 0 2) @[1 2]) "array/slice 1")
|
(assert (array= (array/slice @[1 2 3] 0 2) @[1 2]) "array/slice 1")
|
||||||
(assert (array= (array/slice @[0 7 3 9 1 4] 2 -2) @[3 9 1]) "array/slice 2")
|
(assert (array= (array/slice @[0 7 3 9 1 4] 2 -2) @[3 9 1]) "array/slice 2")
|
||||||
|
|
||||||
|
# Even and odd
|
||||||
|
|
||||||
|
(assert (odd? 9) "odd? 1")
|
||||||
|
(assert (odd? -9) "odd? 2")
|
||||||
|
(assert (not (odd? 10)) "odd? 3")
|
||||||
|
(assert (not (odd? 0)) "odd? 4")
|
||||||
|
(assert (not (odd? -10)) "odd? 5")
|
||||||
|
(assert (not (odd? 1.1)) "odd? 6")
|
||||||
|
(assert (not (odd? -0.1)) "odd? 7")
|
||||||
|
(assert (not (odd? -1.1)) "odd? 8")
|
||||||
|
(assert (not (odd? -1.6)) "odd? 9")
|
||||||
|
|
||||||
|
(assert (even? 10) "even? 1")
|
||||||
|
(assert (even? -10) "even? 2")
|
||||||
|
(assert (even? 0) "even? 3")
|
||||||
|
(assert (not (even? 9)) "even? 4")
|
||||||
|
(assert (not (even? -9)) "even? 5")
|
||||||
|
(assert (not (even? 0.1)) "even? 6")
|
||||||
|
(assert (not (even? -0.1)) "even? 7")
|
||||||
|
(assert (not (even? -10.1)) "even? 8")
|
||||||
|
(assert (not (even? -10.6)) "even? 9")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
@ -226,6 +226,23 @@
|
|||||||
:week-day 3}
|
:week-day 3}
|
||||||
(os/date 1388608200)) "os/date")
|
(os/date 1388608200)) "os/date")
|
||||||
|
|
||||||
|
# OS mktime test
|
||||||
|
|
||||||
|
(assert (= 1388608200 (os/mktime {:year-day 0
|
||||||
|
:minutes 30
|
||||||
|
:month 0
|
||||||
|
:dst false
|
||||||
|
:seconds 0
|
||||||
|
:year 2014
|
||||||
|
:month-day 0
|
||||||
|
:hours 20
|
||||||
|
:week-day 3})) "os/mktime")
|
||||||
|
|
||||||
|
(def now (os/time))
|
||||||
|
(assert (= (os/mktime (os/date now)) now) "UTC os/mktime")
|
||||||
|
(assert (= (os/mktime (os/date now true) true) now) "local os/mktime")
|
||||||
|
(assert (= (os/mktime {:year 1970}) 0) "os/mktime default values")
|
||||||
|
|
||||||
# Appending buffer to self
|
# Appending buffer to self
|
||||||
|
|
||||||
(with-dyns [:out @""]
|
(with-dyns [:out @""]
|
||||||
|
@ -126,4 +126,119 @@
|
|||||||
(assert (= false (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} false :no)) "match wildcard 6")
|
(assert (= false (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} false :no)) "match wildcard 6")
|
||||||
(assert (= nil (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} nil :no)) "match wildcard 7")
|
(assert (= nil (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} nil :no)) "match wildcard 7")
|
||||||
|
|
||||||
|
# Regression #301
|
||||||
|
(def b (buffer/new-filled 128 0x78))
|
||||||
|
(assert (= 38 (length (buffer/blit @"" b -1 90))) "buffer/blit 1")
|
||||||
|
|
||||||
|
(def a @"abcdefghijklm")
|
||||||
|
(assert (deep= @"abcde" (buffer/blit @"" a -1 0 5)) "buffer/blit 2")
|
||||||
|
(assert (deep= @"bcde" (buffer/blit @"" a -1 1 5)) "buffer/blit 3")
|
||||||
|
(assert (deep= @"cde" (buffer/blit @"" a -1 2 5)) "buffer/blit 4")
|
||||||
|
(assert (deep= @"de" (buffer/blit @"" a -1 3 5)) "buffer/blit 5")
|
||||||
|
|
||||||
|
# chr
|
||||||
|
(assert (= (chr "a") 97) "chr 1")
|
||||||
|
|
||||||
|
# Detaching closure over non resumable fiber.
|
||||||
|
(do
|
||||||
|
(defn f1
|
||||||
|
[a]
|
||||||
|
(defn f1 [] (++ (a 0)))
|
||||||
|
(defn f2 [] (++ (a 0)))
|
||||||
|
(error [f1 f2]))
|
||||||
|
(def [_ [f1 f2]] (protect (f1 @[0])))
|
||||||
|
# At time of writing, mark phase can detach closure envs.
|
||||||
|
(gccollect)
|
||||||
|
(assert (= 1 (f1)) "detach-non-resumable-closure 1")
|
||||||
|
(assert (= 2 (f2)) "detach-non-resumable-closure 2"))
|
||||||
|
|
||||||
|
# Marshal closure over non resumable fiber.
|
||||||
|
(do
|
||||||
|
(defn f1
|
||||||
|
[a]
|
||||||
|
(defn f1 [] (++ (a 0)))
|
||||||
|
(defn f2 [] (++ (a 0)))
|
||||||
|
(error [f1 f2]))
|
||||||
|
(def [_ tup] (protect (f1 @[0])))
|
||||||
|
(def [f1 f2] (unmarshal (marshal tup make-image-dict) load-image-dict))
|
||||||
|
(assert (= 1 (f1)) "marshal-non-resumable-closure 1")
|
||||||
|
(assert (= 2 (f2)) "marshal-non-resumable-closure 2"))
|
||||||
|
|
||||||
|
# Marshal closure over currently alive fiber.
|
||||||
|
(do
|
||||||
|
(defn f1
|
||||||
|
[a]
|
||||||
|
(defn f1 [] (++ (a 0)))
|
||||||
|
(defn f2 [] (++ (a 0)))
|
||||||
|
(marshal [f1 f2] make-image-dict))
|
||||||
|
(def [f1 f2] (unmarshal (f1 @[0]) load-image-dict))
|
||||||
|
(assert (= 1 (f1)) "marshal-live-closure 1")
|
||||||
|
(assert (= 2 (f2)) "marshal-live-closure 2"))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(var a 1)
|
||||||
|
(defn b [x] (+ a x))
|
||||||
|
(def c (unmarshal (marshal b)))
|
||||||
|
(assert (= 2 (c 1)) "marshal-on-stack-closure 1"))
|
||||||
|
|
||||||
|
# Reduce2
|
||||||
|
|
||||||
|
(assert (= (reduce + 0 (range 1 10)) (reduce2 + (range 10))) "reduce2 1")
|
||||||
|
(assert (= (reduce * 1 (range 2 10)) (reduce2 * (range 1 10))) "reduce2 2")
|
||||||
|
(assert (= nil (reduce2 * [])) "reduce2 3")
|
||||||
|
|
||||||
|
# Accumulate
|
||||||
|
|
||||||
|
(assert (deep= (accumulate + 0 (range 5)) @[0 1 3 6 10]) "accumulate 1")
|
||||||
|
(assert (deep= (accumulate2 + (range 5)) @[0 1 3 6 10]) "accumulate2 1")
|
||||||
|
(assert (deep= @[] (accumulate2 + [])) "accumulate2 2")
|
||||||
|
(assert (deep= @[] (accumulate 0 + [])) "accumulate 2")
|
||||||
|
|
||||||
|
# Perm strings
|
||||||
|
|
||||||
|
(assert (= (os/perm-int "rwxrwxrwx") 8r777) "perm 1")
|
||||||
|
(assert (= (os/perm-int "rwxr-xr-x") 8r755) "perm 2")
|
||||||
|
(assert (= (os/perm-int "rw-r--r--") 8r644) "perm 3")
|
||||||
|
|
||||||
|
(assert (= (band (os/perm-int "rwxrwxrwx") 8r077) 8r077) "perm 4")
|
||||||
|
(assert (= (band (os/perm-int "rwxr-xr-x") 8r077) 8r055) "perm 5")
|
||||||
|
(assert (= (band (os/perm-int "rw-r--r--") 8r077) 8r044) "perm 6")
|
||||||
|
|
||||||
|
(assert (= (os/perm-string 8r777) "rwxrwxrwx") "perm 7")
|
||||||
|
(assert (= (os/perm-string 8r755) "rwxr-xr-x") "perm 8")
|
||||||
|
(assert (= (os/perm-string 8r644) "rw-r--r--") "perm 9")
|
||||||
|
|
||||||
|
# Issue #336 cases - don't segfault
|
||||||
|
|
||||||
|
(assert-error "unmarshal errors 1" (unmarshal @"\xd6\xb9\xb9"))
|
||||||
|
(assert-error "unmarshal errors 2" (unmarshal @"\xd7bc"))
|
||||||
|
(assert-error "unmarshal errors 3" (unmarshal "\xd3\x01\xd9\x01\x62\xcf\x03\x78\x79\x7a" load-image-dict))
|
||||||
|
(assert-error "unmarshal errors 4"
|
||||||
|
(unmarshal
|
||||||
|
@"\xD7\xCD\0e/p\x98\0\0\x03\x01\x01\x01\x02\0\0\x04\0\xCEe/p../tools
|
||||||
|
\0\0\0/afl\0\0\x01\0erate\xDE\xDE\xDE\xDE\xDE\xDE\xDE\xDE\xDE\xDE
|
||||||
|
\xA8\xDE\xDE\xDE\xDE\xDE\xDE\0\0\0\xDE\xDE_unmarshal_testcase3.ja
|
||||||
|
neldb\0\0\0\xD8\x05printG\x01\0\xDE\xDE\xDE'\x03\0marshal_tes/\x02
|
||||||
|
\0\0\0\0\0*\xFE\x01\04\x02\0\0'\x03\0\r\0\r\0\r\0\r" load-image-dict))
|
||||||
|
|
||||||
|
# No segfault, valgrind clean.
|
||||||
|
|
||||||
|
(def x @"\xCC\xCD.nd\x80\0\r\x1C\xCDg!\0\x07\xCC\xCD\r\x1Ce\x10\0\r;\xCDb\x04\xFF9\xFF\x80\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04uu\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\0\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04}\x04\x04\x04\x04\x04\x04\x04\x04#\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\0\x01\0\0\x03\x04\x04\x04\xE2\x03\x04\x04\x04\x04\x04\x04\x04\x04\x04\x14\x1A\x04\x04\x04\x04\x04\x18\x04\x04!\x04\xE2\x03\x04\x04\x04\x04\x04\x04$\x04\x04\x04\x04\x04\x04\x04\x04\x04\x80\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04A\0\0\0\x03\0\0!\xBF\xFF")
|
||||||
|
(unmarshal x load-image-dict)
|
||||||
|
(gccollect)
|
||||||
|
(marshal x make-image-dict)
|
||||||
|
|
||||||
|
(def b @"\xCC\xCD\0\x03\0\x08\x04\rm\xCD\x7F\xFF\xFF\xFF\x02\0\x02\xD7\xCD\0\x98\0\0\x05\x01\x01\x01\x01\x08\xCE\x01f\xCE../tools/afl/generate_unmarshal_testcases.janet\xCE\x012,\x01\0\0&\x03\0\06\x02\x03\x03)\x03\x01\0*\x04\0\00\x03\x04\0>\x03\0\0\x03\x03\0\0*\x05\0\x11\0\x11\0\x05\0\x05\0\x05\0\x05\0\x05\xC9\xDA\x04\xC9\xC9\xC9")
|
||||||
|
(unmarshal b load-image-dict)
|
||||||
|
(gccollect)
|
||||||
|
|
||||||
|
(def v (unmarshal
|
||||||
|
@"\xD7\xCD0\xD4000000\0\x03\x01\xCE\00\0\x01\0\0000\x03\0\0\0000000000\xCC0\0000"
|
||||||
|
load-image-dict))
|
||||||
|
(gccollect)
|
||||||
|
|
||||||
|
# in vs get regression
|
||||||
|
(assert (nil? (first @"")) "in vs get 1")
|
||||||
|
(assert (nil? (last @"")) "in vs get 1")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
@ -3,12 +3,26 @@
|
|||||||
To use these, you need to install afl (of course), and xterm. A tiling window manager helps manage
|
To use these, you need to install afl (of course), and xterm. A tiling window manager helps manage
|
||||||
many concurrent fuzzer instances.
|
many concurrent fuzzer instances.
|
||||||
|
|
||||||
|
Note, afl sometimes requires system configuration, if you find AFL quitting prematurely, try manually
|
||||||
|
launching it and addressing any error messages.
|
||||||
|
|
||||||
## Fuzz the parser
|
## Fuzz the parser
|
||||||
```
|
```
|
||||||
$ sh ./tools/afl/prepare_to_fuzz.sh
|
$ sh ./tools/afl/prepare_to_fuzz.sh
|
||||||
export NFUZZ=1
|
$ export NFUZZ=1
|
||||||
$ sh ./tools/afl/fuzz.sh parser
|
$ sh ./tools/afl/fuzz.sh parser
|
||||||
Ctrl+C when done to close all fuzzer terminals.
|
Ctrl+C when done to close all fuzzer terminals.
|
||||||
$ sh ./tools/afl/aggregate_cases.sh parser
|
$ sh ./tools/afl/aggregate_cases.sh parser
|
||||||
$ ls ./fuzz_out/parser_aggregated/
|
$ ls ./fuzz_out/parser_aggregated/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Fuzz the unmarshaller
|
||||||
|
```
|
||||||
|
$ janet ./tools/afl/generate_unmarshal_testcases.janet
|
||||||
|
$ sh ./tools/afl/prepare_to_fuzz.sh
|
||||||
|
$ export NFUZZ=1
|
||||||
|
$ sh ./tools/afl/fuzz.sh unmarshal
|
||||||
|
Ctrl+C when done to close all fuzzer terminals.
|
||||||
|
$ sh ./tools/afl/aggregate_cases.sh unmarshal
|
||||||
|
$ ls ./fuzz_out/unmarshal_aggregated/
|
||||||
|
```
|
||||||
|
49
tools/afl/generate_unmarshal_testcases.janet
Normal file
49
tools/afl/generate_unmarshal_testcases.janet
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
(os/mkdir "./tools/afl/unmarshal_testcases/")
|
||||||
|
|
||||||
|
(defn spit-case [n v]
|
||||||
|
(spit
|
||||||
|
(string "./tools/afl/unmarshal_testcases/" (string n))
|
||||||
|
(marshal v make-image-dict)))
|
||||||
|
|
||||||
|
(def cases [
|
||||||
|
nil
|
||||||
|
|
||||||
|
"abc"
|
||||||
|
|
||||||
|
:def
|
||||||
|
|
||||||
|
'hij
|
||||||
|
|
||||||
|
123
|
||||||
|
|
||||||
|
(int/s64 123)
|
||||||
|
|
||||||
|
"7"
|
||||||
|
|
||||||
|
[1 2 3]
|
||||||
|
|
||||||
|
@[1 2 3]
|
||||||
|
|
||||||
|
{:a 123}
|
||||||
|
|
||||||
|
@{:b 'xyz}
|
||||||
|
|
||||||
|
(peg/compile
|
||||||
|
'{:a (* "a" :b "a")
|
||||||
|
:b (* "b" (+ :a 0) "b")
|
||||||
|
:main (* "(" :b ")")})
|
||||||
|
|
||||||
|
(fn f [a] (fn [] {:ab a}))
|
||||||
|
|
||||||
|
(fn f [a] (print "hello world!"))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(defn f [a] (yield) @[1 "2"])
|
||||||
|
(def fb (fiber/new f))
|
||||||
|
(resume fb)
|
||||||
|
fb)
|
||||||
|
])
|
||||||
|
|
||||||
|
(eachk i cases
|
||||||
|
(spit-case i (in cases i)))
|
6
tools/afl/unmarshal_runner.janet
Normal file
6
tools/afl/unmarshal_runner.janet
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Unmarshal garbage.
|
||||||
|
(def v (unmarshal (slurp ((dyn :args) 1)) load-image-dict))
|
||||||
|
# Trigger leaks or use after free.
|
||||||
|
(gccollect)
|
||||||
|
# Attempt to use generated value.
|
||||||
|
(marshal v make-image-dict)
|
@ -308,7 +308,7 @@
|
|||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>match</key>
|
<key>match</key>
|
||||||
<string>(\\[nevr0zft"\\']|\\x[0-9a-fA-F][0-9a-fA-f])</string>
|
<string>(\\[nevr0zft"\\']|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{6})</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>constant.character.escape.janet</string>
|
<string>constant.character.escape.janet</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user