mirror of
https://github.com/janet-lang/janet
synced 2025-11-12 21:43:03 +00:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40ae2e812f | ||
|
|
06f613e40b | ||
|
|
61c8c1e8d2 | ||
|
|
ee924ee310 | ||
|
|
fad0ce3ced | ||
|
|
d396180939 | ||
|
|
0d089abe67 | ||
|
|
ed5c1dfc3c | ||
|
|
6b949a7375 | ||
|
|
3028e2908f | ||
|
|
578803b01f | ||
|
|
46738825c0 | ||
|
|
56357699cb | ||
|
|
fe8e718183 | ||
|
|
1eb34989d4 | ||
|
|
2f3b4c8bfb | ||
|
|
6412768000 | ||
|
|
82688b9a44 | ||
|
|
651e12cfe4 | ||
|
|
4118d581af | ||
|
|
62608bec03 | ||
|
|
71cffc973d | ||
|
|
a8e49d084b | ||
|
|
db631097b1 | ||
|
|
0d31674166 | ||
|
|
cb5af974a4 | ||
|
|
f2f421a0a2 | ||
|
|
413c46e2ee | ||
|
|
3b412d51f0 | ||
|
|
4931e2aee2 | ||
|
|
ffadf673cf | ||
|
|
5b5a7e5a24 | ||
|
|
ab53208f47 | ||
|
|
7c407705e8 | ||
|
|
60378ff941 | ||
|
|
30a0c77d19 | ||
|
|
07ec89276b | ||
|
|
a37dc1af9d | ||
|
|
03458df140 | ||
|
|
164eb9659e | ||
|
|
99cfbaa63b | ||
|
|
8d8a6534e3 | ||
|
|
938c5013c9 | ||
|
|
ea9d5ec793 | ||
|
|
ec65f038a8 | ||
|
|
199ec36d40 | ||
|
|
1326ded048 | ||
|
|
8347439644 | ||
|
|
cddc2a8280 | ||
|
|
97a8938407 | ||
|
|
939d1dcae9 | ||
|
|
9d5cc5c11f | ||
|
|
d998f24d26 | ||
|
|
d543f8857b | ||
|
|
c48a942d22 | ||
|
|
e1602618c3 | ||
|
|
36be240623 | ||
|
|
04e499c97f | ||
|
|
f586a8a9dc | ||
|
|
5112ed77d6 | ||
|
|
bf29a54272 | ||
|
|
6d9286a202 | ||
|
|
92fdd07ca3 | ||
|
|
1c937ad960 | ||
|
|
f9891a5c04 | ||
|
|
e8ad311d84 | ||
|
|
545c09e202 | ||
|
|
4dc281a05f | ||
|
|
3a0af8caad | ||
|
|
8ff2fecb26 | ||
|
|
1855c6aed5 | ||
|
|
d4c6643311 | ||
|
|
e8c738002b | ||
|
|
309c3aaeb8 | ||
|
|
1f8bcadb3b | ||
|
|
6f4af5fef8 | ||
|
|
868cdb9f8b | ||
|
|
2f76a429ef | ||
|
|
a69799aa42 | ||
|
|
139bef2142 | ||
|
|
8ba142bcf4 | ||
|
|
c49e4966f6 | ||
|
|
516fa4e49d | ||
|
|
6bf9f89429 | ||
|
|
4e263b8c39 |
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -33,3 +33,23 @@ jobs:
|
||||
build/janet.h
|
||||
build/c/janet.c
|
||||
build/c/shell.c
|
||||
|
||||
release-windows:
|
||||
name: Build release binaries for windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Build the project
|
||||
shell: cmd
|
||||
run: build_win all
|
||||
- name: Draft the release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
./dist/*.zip
|
||||
./*.zip
|
||||
./*.msi
|
||||
|
||||
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,6 +1,25 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.20.0 - 2022-1-27
|
||||
- Add `:missing-symbol` hook to `compile` that will act as a catch-all macro for undefined symbols.
|
||||
- Add `:redef` dynamic binding that will allow users to redefine top-level bindings with late binding. This
|
||||
is intended for development use.
|
||||
- Fix a bug with reading from a stream returned by `os/open` on Windows and Linux.
|
||||
- Add `:ppc64` as a detectable OS type.
|
||||
- Add `& more` support for destructuring in the match macro.
|
||||
- Add `& more` support for destructuring in all binding forms (`def`).
|
||||
|
||||
## 1.19.2 - 2021-12-06
|
||||
- Fix bug with missing status lines in some stack traces.
|
||||
- Update hash function to have better statistical properties.
|
||||
|
||||
## 1.19.1 - 2021-12-04
|
||||
- Add an optional `prefix` parameter to `debug/stacktrace` to allow printing prettier error messages.
|
||||
- Remove appveyor for CI pipeline
|
||||
- Fixed a bug that prevented sending threaded abstracts over threaded channels.
|
||||
- Fix bug in the `map` function with arity at least 3.
|
||||
|
||||
## 1.19.0 - 2021-11-27
|
||||
- Add `math/log-gamma` to replace `math/gamma`, and change `math/gamma` to be the expected gamma function.
|
||||
- Fix leaking file-descriptors in os/spawn and os/execute.
|
||||
|
||||
2
Makefile
2
Makefile
@@ -165,7 +165,7 @@ build/c/janet.c: build/janet_boot src/boot/boot.janet
|
||||
##### Amalgamation #####
|
||||
########################
|
||||
|
||||
SONAME=libjanet.so.1.19
|
||||
SONAME=libjanet.so.1.20
|
||||
|
||||
build/c/shell.c: src/mainclient/shell.c
|
||||
cp $< $@
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[](https://gitter.im/janet-language/community)
|
||||
|
||||
[](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/freebsd.yml?)
|
||||
[](https://builds.sr.ht/~bakpakin/janet/commits/openbsd.yml?)
|
||||
[](https://github.com/janet-lang/janet/actions/workflows/test.yml)
|
||||
|
||||
51
appveyor.yml
51
appveyor.yml
@@ -1,51 +0,0 @@
|
||||
version: build-{build}
|
||||
clone_folder: c:\projects\janet
|
||||
image:
|
||||
- Visual Studio 2019
|
||||
configuration:
|
||||
- Release
|
||||
platform:
|
||||
- x64
|
||||
- x86
|
||||
environment:
|
||||
matrix:
|
||||
- arch: Win64
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
# skip unsupported combinations
|
||||
init:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
|
||||
|
||||
install:
|
||||
- set JANET_BUILD=%appveyor_repo_commit:~0,7%
|
||||
- build_win all
|
||||
- set janet_outname=%appveyor_repo_tag_name%
|
||||
- if "%janet_outname%"=="" set /P janet_outname=<build\version.txt
|
||||
build: off
|
||||
|
||||
artifacts:
|
||||
- name: janet.c
|
||||
path: dist\janet.c
|
||||
type: File
|
||||
- name: janet.h
|
||||
path: dist\janet.h
|
||||
type: File
|
||||
- name: shell.c
|
||||
path: dist\shell.c
|
||||
type: File
|
||||
- name: "janet-$(janet_outname)-windows-%platform%"
|
||||
path: dist
|
||||
type: Zip
|
||||
- path: "janet-$(janet_outname)-windows-%platform%-installer.msi"
|
||||
type: File
|
||||
|
||||
deploy:
|
||||
description: 'The Janet Programming Language.'
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: lwEXy09qhj2jSH9s1C/KvCkAUqJSma8phFR+0kbsfUc3rVxpNK5uD3z9Md0SjYRx
|
||||
artifact: /(janet|shell).*/
|
||||
draft: true
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
@@ -1,6 +1,6 @@
|
||||
(defn dowork [name n]
|
||||
(print name " starting work...")
|
||||
(os/execute [(dyn :executable) "-e" (string "(os/sleep " n ")")])
|
||||
(os/execute [(dyn :executable) "-e" (string "(os/sleep " n ")")] :p)
|
||||
(print name " finished work!"))
|
||||
|
||||
# Will be done in parallel
|
||||
|
||||
@@ -76,9 +76,16 @@ void num_array_put(void *p, Janet key, Janet value) {
|
||||
}
|
||||
}
|
||||
|
||||
static Janet num_array_length(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
|
||||
return janet_wrap_number(array->size);
|
||||
}
|
||||
|
||||
static const JanetMethod methods[] = {
|
||||
{"scale", num_array_scale},
|
||||
{"sum", num_array_sum},
|
||||
{"length", num_array_length},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -109,6 +116,11 @@ static const JanetReg cfuns[] = {
|
||||
"(numarray/scale numarray factor)\n\n"
|
||||
"scale numarray by factor"
|
||||
},
|
||||
{
|
||||
"sum", num_array_sum,
|
||||
"(numarray/sum numarray)\n\n"
|
||||
"sums numarray"
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(import build/numarray)
|
||||
(import /build/numarray)
|
||||
|
||||
(def a (numarray/new 30))
|
||||
(print (get a 20))
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
project('janet', 'c',
|
||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.19.0')
|
||||
version : '1.20.0')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
|
||||
@@ -532,16 +532,19 @@
|
||||
|
||||
(defmacro loop
|
||||
```
|
||||
A general purpose loop macro. This macro is similar to the Common Lisp
|
||||
loop macro, although intentionally much smaller in scope.
|
||||
The head of the loop should be a tuple that contains a sequence of
|
||||
either bindings or conditionals. A binding is a sequence of three values
|
||||
that define something to loop over. They are formatted like:
|
||||
A general purpose loop macro. This macro is similar to the Common Lisp loop
|
||||
macro, although intentionally much smaller in scope. The head of the loop
|
||||
should be a tuple that contains a sequence of either bindings or
|
||||
conditionals. A binding is a sequence of three values that define something
|
||||
to loop over. Bindings are written in the format:
|
||||
|
||||
binding :verb object/expression
|
||||
|
||||
Where `binding` is a binding as passed to def, `:verb` is one of a set of
|
||||
keywords, and `object` is any expression. The available verbs are:
|
||||
where `binding` is a binding as passed to def, `:verb` is one of a set of
|
||||
keywords, and `object` is any expression. Each subsequent binding creates a
|
||||
nested loop within the loop created by the previous binding.
|
||||
|
||||
The available verbs are:
|
||||
|
||||
* `:iterate` - repeatedly evaluate and bind to the expression while it is
|
||||
truthy.
|
||||
@@ -565,14 +568,19 @@
|
||||
where `:modifier` is one of a set of keywords, and `argument` is keyword-dependent.
|
||||
`:modifier` can be one of:
|
||||
|
||||
* `:while expression` - breaks from the loop if `expression` is falsey.
|
||||
* `:until expression` - breaks from the loop if `expression` is truthy.
|
||||
* `:let bindings` - defines bindings inside the loop as passed to the `let` macro.
|
||||
* `:before form` - evaluates a form for a side effect before the next inner loop.
|
||||
* `:after form` - same as `:before`, but the side effect happens after the next inner loop.
|
||||
* `:while expression` - breaks from the current loop if `expression` is
|
||||
falsey.
|
||||
* `:until expression` - breaks from the current loop if `expression` is
|
||||
truthy.
|
||||
* `:let bindings` - defines bindings inside the current loop as passed to the
|
||||
`let` macro.
|
||||
* `:before form` - evaluates a form for a side effect before the next inner
|
||||
loop.
|
||||
* `:after form` - same as `:before`, but the side effect happens after the
|
||||
next inner loop.
|
||||
* `:repeat n` - repeats the next inner loop `n` times.
|
||||
lets try putting a loop item on multiple lines.
|
||||
* `:when condition` - only evaluates the loop body when condition is true.
|
||||
* `:when condition` - only evaluates the current loop body when `condition`
|
||||
is true.
|
||||
|
||||
The `loop` macro always evaluates to nil.
|
||||
```
|
||||
@@ -908,7 +916,7 @@
|
||||
(while true
|
||||
(if (= nil (set k1 (next i1 k1))) (break))
|
||||
(if (= nil (set k2 (next i2 k2))) (break))
|
||||
(if (= nil (set k3 (next i2 k3))) (break))
|
||||
(if (= nil (set k3 (next i3 k3))) (break))
|
||||
(array/push res (f (in i1 k1) (in i2 k2) (in i3 k3)))))
|
||||
4 (do
|
||||
(var k1 nil)
|
||||
@@ -918,8 +926,8 @@
|
||||
(while true
|
||||
(if (= nil (set k1 (next i1 k1))) (break))
|
||||
(if (= nil (set k2 (next i2 k2))) (break))
|
||||
(if (= nil (set k3 (next i2 k3))) (break))
|
||||
(if (= nil (set k4 (next i2 k4))) (break))
|
||||
(if (= nil (set k3 (next i3 k3))) (break))
|
||||
(if (= nil (set k4 (next i4 k4))) (break))
|
||||
(array/push res (f (in i1 k1) (in i2 k2) (in i3 k3) (in i4 k4)))))
|
||||
(do
|
||||
(def iterkeys (array/new-filled ninds))
|
||||
@@ -1668,8 +1676,9 @@
|
||||
* symbol -- a pattern that is a symbol will match anything, binding `x`'s
|
||||
value to that symbol.
|
||||
|
||||
* array -- an array will match only if all of its elements match the
|
||||
corresponding elements in `x`.
|
||||
* array or bracket tuple -- an array or bracket tuple will match only if
|
||||
all of its elements match the corresponding elements in `x`.
|
||||
Use `& rest` at the end of an array or bracketed tuple to bind all remaining values to `rest`.
|
||||
|
||||
* table or struct -- a table or struct will match if all values match with
|
||||
the corresponding values in `x`.
|
||||
@@ -1743,10 +1752,26 @@
|
||||
(break)
|
||||
|
||||
# match data structure template
|
||||
(or isarr (= t :struct) (= t :table))
|
||||
(or (= t :struct) (= t :table))
|
||||
(eachp [i sub-pattern] pattern
|
||||
(visit-pattern-1 b2g s i sub-pattern))
|
||||
|
||||
isarr
|
||||
(do
|
||||
(when isarr (get-length-sym s))
|
||||
(get-length-sym s)
|
||||
(eachp [i sub-pattern] pattern
|
||||
(when (= sub-pattern '&)
|
||||
(when (<= (length pattern) (inc i))
|
||||
(errorf "expected symbol following & in pattern"))
|
||||
|
||||
(when (< (+ i 2) (length pattern))
|
||||
(errorf "expected a single symbol follow '& in pattern, found %q" (slice pattern (inc i))))
|
||||
|
||||
(when (not= (type (pattern (inc i))) :symbol)
|
||||
(errorf "expected symbol following & in pattern, found %q" (pattern (inc i))))
|
||||
|
||||
(put b2g (pattern (inc i)) @[[slice s i]])
|
||||
(break))
|
||||
(visit-pattern-1 b2g s i sub-pattern)))
|
||||
|
||||
# match global unification
|
||||
@@ -1766,14 +1791,24 @@
|
||||
(def isarr (or (= t :array) (and (= t :tuple) (= (tuple/type pattern) :brackets))))
|
||||
(when isarr
|
||||
(array/push anda (get-length-sym s))
|
||||
(array/push anda [<= (length pattern) (get-length-sym s)]))
|
||||
(def pattern-len
|
||||
(if-let [ rest-idx (find-index (fn [x] (= x '&)) pattern) ]
|
||||
rest-idx
|
||||
(length pattern)))
|
||||
(array/push anda [<= pattern-len (get-length-sym s)]))
|
||||
(cond
|
||||
|
||||
# match data structure template
|
||||
(or isarr (= t :struct) (= t :table))
|
||||
(or (= t :struct) (= t :table))
|
||||
(eachp [i sub-pattern] pattern
|
||||
(when (not isarr)
|
||||
(array/push anda [not= nil (get-sym s i)]))
|
||||
(array/push anda [not= nil (get-sym s i)])
|
||||
(visit-pattern-2 anda gun preds s i sub-pattern))
|
||||
|
||||
isarr
|
||||
(eachp [i sub-pattern] pattern
|
||||
# stop recursing to sub-patterns if the rest sigil is found
|
||||
(when (= sub-pattern '&)
|
||||
(break))
|
||||
(visit-pattern-2 anda gun preds s i sub-pattern))
|
||||
|
||||
# match local binding
|
||||
@@ -1944,8 +1979,8 @@
|
||||
(def h (in t 0))
|
||||
(def s (in specs h))
|
||||
(def entry (or (dyn h) {}))
|
||||
(def m (entry :value))
|
||||
(def m? (entry :macro))
|
||||
(def m (do (def r (get entry :ref)) (if r (in r 0) (get entry :value))))
|
||||
(def m? (in entry :macro))
|
||||
(cond
|
||||
s (s t)
|
||||
m? (do (setdyn :macro-form t) (m ;(tuple/slice t 1)))
|
||||
@@ -2178,19 +2213,20 @@
|
||||
the file, prints nothing."
|
||||
[where line col]
|
||||
(if-not line (break))
|
||||
(unless (string? where) (break))
|
||||
(when-with [f (file/open where :r)]
|
||||
(def source-code (file/read f :all))
|
||||
(var index 0)
|
||||
(repeat (dec line)
|
||||
(if-not index (break))
|
||||
(set index (inc (string/find "\n" source-code index))))
|
||||
(set index (string/find "\n" source-code index))
|
||||
(if index (++ index)))
|
||||
(when index
|
||||
(def line-end (string/find "\n" source-code index))
|
||||
(eprint " " (string/slice source-code index line-end))
|
||||
(when col
|
||||
(+= index col)
|
||||
(eprint (string/repeat " " (inc col)) "^"))
|
||||
(eflush))))
|
||||
(eprint (string/repeat " " (inc col)) "^")))))
|
||||
|
||||
(defn warn-compile
|
||||
"Default handler for a compile warning"
|
||||
@@ -2223,7 +2259,7 @@
|
||||
col
|
||||
": compile error: ")
|
||||
(if macrof
|
||||
(debug/stacktrace macrof msg)
|
||||
(debug/stacktrace macrof msg "")
|
||||
(eprint msg))
|
||||
(when ec
|
||||
(print-line-col where line col)
|
||||
@@ -2255,7 +2291,7 @@
|
||||
* `:chunks` - callback to read into a buffer - default is getline
|
||||
* `:on-parse-error` - callback when parsing fails - default is bad-parse
|
||||
* `:env` - the environment to compile against - default is the current env
|
||||
* `:source` - string path of source for better errors - default is "<anonymous>"
|
||||
* `:source` - source path for better errors (use keywords for non-paths) - default is :<anonymous>
|
||||
* `:on-compile-error` - callback when compilation fails - default is bad-compile
|
||||
* `:on-compile-warning` - callback for any linting error - default is warn-compile
|
||||
* `:evaluator` - callback that executes thunks. Signature is (evaluator thunk source env where)
|
||||
@@ -2287,11 +2323,14 @@
|
||||
(default on-compile-warning warn-compile)
|
||||
(default on-parse-error bad-parse)
|
||||
(default evaluator (fn evaluate [x &] (x)))
|
||||
(default default-where "<anonymous>")
|
||||
(default default-where :<anonymous>)
|
||||
(default guard :ydt)
|
||||
|
||||
(var where default-where)
|
||||
|
||||
(if (string? where)
|
||||
(put env :current-file where))
|
||||
|
||||
# Evaluate 1 source form in a protected manner
|
||||
(def lints @[])
|
||||
(defn eval1 [source &opt l c]
|
||||
@@ -2369,9 +2408,10 @@
|
||||
(buffer/clear buf))
|
||||
|
||||
[:source new-where]
|
||||
(if (string? new-where)
|
||||
(do
|
||||
(set where new-where)
|
||||
(set where default-where))
|
||||
(if (string? new-where)
|
||||
(put env :current-file new-where)))
|
||||
|
||||
(do
|
||||
(var pindex 0)
|
||||
@@ -2432,14 +2472,14 @@
|
||||
(if-not (= (fiber/status f) :dead)
|
||||
(error val))
|
||||
(set returnval val))
|
||||
:source "eval-string"})
|
||||
:source :eval-string})
|
||||
returnval)
|
||||
|
||||
(defn eval
|
||||
``Evaluates a form in the current environment. If more control over the
|
||||
environment is needed, use `run-context`.``
|
||||
[form]
|
||||
(def res (compile form (fiber/getenv (fiber/current)) "eval"))
|
||||
(def res (compile form (fiber/getenv (fiber/current)) :eval))
|
||||
(if (= (type res) :function)
|
||||
(res)
|
||||
(error (get res :error))))
|
||||
@@ -2601,7 +2641,7 @@
|
||||
|
||||
(defn dofile
|
||||
`Evaluate a file, file path, or stream and return the resulting environment. :env, :expander,
|
||||
:evaluator, :read, and :parser are passed through to the underlying
|
||||
:source, :evaluator, :read, and :parser are passed through to the underlying
|
||||
run-context call. If exit is true, any top level errors will trigger a
|
||||
call to (os/exit 1) after printing the error.`
|
||||
[path &keys
|
||||
@@ -2619,7 +2659,6 @@
|
||||
(def path-is-file (= f path))
|
||||
(default env (make-env))
|
||||
(def spath (string path))
|
||||
(put env :current-file (or src (if-not path-is-file spath)))
|
||||
(put env :source (or src (if-not path-is-file spath path)))
|
||||
(var exit-error nil)
|
||||
(var exit-fiber nil)
|
||||
@@ -2653,8 +2692,7 @@
|
||||
:on-status (fn [f x]
|
||||
(when (not= (fiber/status f) :dead)
|
||||
(when exit
|
||||
(eprint x)
|
||||
(debug/stacktrace f)
|
||||
(debug/stacktrace f x "")
|
||||
(eflush)
|
||||
(os/exit 1))
|
||||
(put env :exit true)
|
||||
@@ -2664,7 +2702,7 @@
|
||||
:expander expander
|
||||
:read read
|
||||
:parser parser
|
||||
:source (or src (if path-is-file "<anonymous>" spath))}))
|
||||
:source (or src (if path-is-file :<anonymous> spath))}))
|
||||
(if-not path-is-file (:close f))
|
||||
(when exit-error
|
||||
(if exit-fiber
|
||||
@@ -3067,6 +3105,7 @@
|
||||
(def bind-type
|
||||
(string " "
|
||||
(cond
|
||||
(x :redef) (type (in (x :ref) 0))
|
||||
(x :ref) (string :var " (" (type (in (x :ref) 0)) ")")
|
||||
(x :macro) :macro
|
||||
(x :module) (string :module " (" (x :kind) ")")
|
||||
@@ -3075,7 +3114,7 @@
|
||||
(def sm (x :source-map))
|
||||
(def d (x :doc))
|
||||
(print "\n\n"
|
||||
(when d bind-type)
|
||||
bind-type
|
||||
(when-let [[path line col] sm]
|
||||
(string " " path (when (and line col) (string " on line " line ", column " col))))
|
||||
(when sm "\n")
|
||||
@@ -3161,7 +3200,7 @@
|
||||
"Print the current fiber stack"
|
||||
[]
|
||||
(print)
|
||||
(with-dyns [:err-color false] (debug/stacktrace (.fiber) (.signal)))
|
||||
(with-dyns [:err-color false] (debug/stacktrace (.fiber) (.signal) ""))
|
||||
(print))
|
||||
|
||||
(defn .frame
|
||||
@@ -3358,9 +3397,7 @@
|
||||
(printf (get e :pretty-format "%q") x)
|
||||
(flush))
|
||||
(do
|
||||
(def ec (dyn :err-color))
|
||||
(eprint (if ec "\e[31m" "") fs ": " x)
|
||||
(debug/stacktrace f)
|
||||
(debug/stacktrace f x "")
|
||||
(eflush)
|
||||
(if (e :debug) (enter-debugger f x))))))
|
||||
|
||||
@@ -3369,7 +3406,7 @@
|
||||
:on-status (or onsignal (make-onsignal env 1))
|
||||
:parser parser
|
||||
:read read
|
||||
:source "repl"}))
|
||||
:source :repl}))
|
||||
|
||||
###
|
||||
###
|
||||
@@ -3514,8 +3551,7 @@
|
||||
(try
|
||||
(dofile path :evaluator flycheck-evaluator ;(kvs kwargs))
|
||||
([e f]
|
||||
(eprint e)
|
||||
(debug/stacktrace f)))
|
||||
(debug/stacktrace f e "")))
|
||||
nil)
|
||||
|
||||
###
|
||||
@@ -3529,7 +3565,8 @@
|
||||
|
||||
(defn- run-main
|
||||
[env subargs arg]
|
||||
(if-let [main (get (in env 'main) :value)]
|
||||
(if-let [entry (in env 'main)
|
||||
main (or (get entry :value) (in (get entry :ref) 0))]
|
||||
(let [thunk (compile [main ;subargs] env arg)]
|
||||
(if (function? thunk) (thunk) (error (thunk :error))))))
|
||||
|
||||
@@ -3648,14 +3685,18 @@
|
||||
(put env :args subargs)
|
||||
(put env :lint-error error-level)
|
||||
(put env :lint-warn warn-level)
|
||||
(if debug-flag (put env :debug true))
|
||||
(when debug-flag
|
||||
(put env :debug true)
|
||||
(put env :redef true))
|
||||
(run-main env subargs arg))
|
||||
(do
|
||||
(def env (make-env))
|
||||
(put env :args subargs)
|
||||
(put env :lint-error error-level)
|
||||
(put env :lint-warn warn-level)
|
||||
(if debug-flag (put env :debug true))
|
||||
(when debug-flag
|
||||
(put env :debug true)
|
||||
(put env :redef true))
|
||||
(if compile-only
|
||||
(flycheck arg :exit exit-on-error :env env)
|
||||
(do
|
||||
@@ -3665,7 +3706,7 @@
|
||||
|
||||
(if (or should-repl no-file)
|
||||
(if
|
||||
compile-only (flycheck stdin :source "stdin" :exit exit-on-error)
|
||||
compile-only (flycheck stdin :source :stdin :exit exit-on-error)
|
||||
(do
|
||||
(if-not quiet
|
||||
(print "Janet " janet/version "-" janet/build " " (os/which) "/" (os/arch) " - '(doc)' for help"))
|
||||
@@ -3681,7 +3722,9 @@
|
||||
(when-let [profile.janet (dyn :profilepath)]
|
||||
(def new-env (dofile profile.janet :exit true))
|
||||
(merge-module env new-env "" false))
|
||||
(if debug-flag (put env :debug true))
|
||||
(when debug-flag
|
||||
(put env :debug true)
|
||||
(put env :redef true))
|
||||
(def getter (if raw-stdin getstdin getline))
|
||||
(defn getchunk [buf p]
|
||||
(getter (getprompt p) buf env))
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 19
|
||||
#define JANET_VERSION_MINOR 20
|
||||
#define JANET_VERSION_PATCH 0
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.19.0"
|
||||
#define JANET_VERSION "1.20.0"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
|
||||
@@ -197,6 +197,39 @@ void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
|
||||
}
|
||||
}
|
||||
|
||||
static int lookup_missing(
|
||||
JanetCompiler *c,
|
||||
const uint8_t *sym,
|
||||
JanetFunction *handler,
|
||||
JanetBinding *out) {
|
||||
int32_t minar = handler->def->min_arity;
|
||||
int32_t maxar = handler->def->max_arity;
|
||||
if (minar > 1 || maxar < 1) {
|
||||
janetc_error(c, janet_cstring("missing symbol lookup handler must take 1 argument"));
|
||||
return 0;
|
||||
}
|
||||
Janet args[1] = { janet_wrap_symbol(sym) };
|
||||
JanetFiber *fiberp = janet_fiber(handler, 64, 1, args);
|
||||
if (NULL == fiberp) {
|
||||
janetc_error(c, janet_cstring("failed to call missing symbol lookup handler"));
|
||||
return 0;
|
||||
}
|
||||
fiberp->env = c->env;
|
||||
int lock = janet_gclock();
|
||||
Janet tempOut;
|
||||
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
|
||||
janet_gcunlock(lock);
|
||||
if (status != JANET_SIGNAL_OK) {
|
||||
janetc_error(c, janet_formatc("(lookup) %V", tempOut));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert return value as entry. */
|
||||
/* Alternative could use janet_resolve_ext(c->env, sym) to read result from environment. */
|
||||
*out = janet_binding_from_entry(tempOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allow searching for symbols. Return information about the symbol */
|
||||
JanetSlot janetc_resolve(
|
||||
JanetCompiler *c,
|
||||
@@ -230,6 +263,21 @@ JanetSlot janetc_resolve(
|
||||
/* Symbol not found - check for global */
|
||||
{
|
||||
JanetBinding binding = janet_resolve_ext(c->env, sym);
|
||||
if (binding.type == JANET_BINDING_NONE) {
|
||||
Janet handler = janet_table_get(c->env, janet_ckeywordv("missing-symbol"));
|
||||
switch (janet_type(handler)) {
|
||||
case JANET_NIL:
|
||||
break;
|
||||
case JANET_FUNCTION:
|
||||
if (!lookup_missing(c, sym, janet_unwrap_function(handler), &binding))
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
break;
|
||||
default:
|
||||
janetc_error(c, janet_formatc("invalid lookup handler %V", handler));
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
}
|
||||
|
||||
switch (binding.type) {
|
||||
default:
|
||||
case JANET_BINDING_NONE:
|
||||
@@ -239,6 +287,12 @@ JanetSlot janetc_resolve(
|
||||
case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */
|
||||
ret = janetc_cslot(binding.value);
|
||||
break;
|
||||
case JANET_BINDING_DYNAMIC_DEF:
|
||||
case JANET_BINDING_DYNAMIC_MACRO:
|
||||
ret = janetc_cslot(binding.value);
|
||||
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOTTYPE_ANY;
|
||||
ret.flags &= ~JANET_SLOT_CONSTANT;
|
||||
break;
|
||||
case JANET_BINDING_VAR: {
|
||||
ret = janetc_cslot(binding.value);
|
||||
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
|
||||
@@ -651,7 +705,7 @@ static int macroexpand1(
|
||||
}
|
||||
Janet macroval;
|
||||
JanetBindingType btype = janet_resolve(c->env, name, ¯oval);
|
||||
if (btype != JANET_BINDING_MACRO ||
|
||||
if (!(btype == JANET_BINDING_MACRO || btype == JANET_BINDING_DYNAMIC_MACRO) ||
|
||||
!janet_checktype(macroval, JANET_FUNCTION))
|
||||
return 0;
|
||||
|
||||
@@ -958,7 +1012,14 @@ JANET_CORE_FN(cfun,
|
||||
}
|
||||
const uint8_t *source = NULL;
|
||||
if (argc >= 3) {
|
||||
source = janet_getstring(argv, 2);
|
||||
Janet x = argv[2];
|
||||
if (janet_checktype(x, JANET_STRING)) {
|
||||
source = janet_unwrap_string(x);
|
||||
} else if (janet_checktype(x, JANET_KEYWORD)) {
|
||||
source = janet_unwrap_keyword(x);
|
||||
} else {
|
||||
janet_panic_type(x, 2, JANET_TFLAG_STRING | JANET_TFLAG_KEYWORD);
|
||||
}
|
||||
}
|
||||
JanetArray *lints = (argc >= 4) ? janet_getarray(argv, 3) : NULL;
|
||||
JanetCompileResult res = janet_compile_lint(argv[0], env, source, lints);
|
||||
|
||||
@@ -96,15 +96,19 @@ void janet_debug_find(
|
||||
}
|
||||
}
|
||||
|
||||
void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
const char *prefix = janet_checktype(err, JANET_NIL) ? NULL : "";
|
||||
janet_stacktrace_ext(fiber, err, prefix);
|
||||
}
|
||||
|
||||
/* Error reporting. This can be emulated from within Janet, but for
|
||||
* consitency with the top level code it is defined once. */
|
||||
void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
|
||||
|
||||
int32_t fi;
|
||||
const char *errstr = (const char *)janet_to_string(err);
|
||||
JanetFiber **fibers = NULL;
|
||||
|
||||
/* Don't print error line if it is nil. */
|
||||
int wrote_error = janet_checktype(err, JANET_NIL);
|
||||
int wrote_error = !prefix;
|
||||
|
||||
int print_color = janet_truthy(janet_dyn("err-color"));
|
||||
if (print_color) janet_eprintf("\x1b[31m");
|
||||
@@ -126,7 +130,6 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
/* Print prelude to stack frame */
|
||||
if (!wrote_error) {
|
||||
JanetFiberStatus status = janet_fiber_status(fiber);
|
||||
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
|
||||
janet_eprintf("%s%s: %s\n",
|
||||
prefix,
|
||||
janet_status_names[status],
|
||||
@@ -337,9 +340,9 @@ JANET_CORE_FN(cfun_debug_stack,
|
||||
"stack frame is the first table in the array, and the bottom-most stack frame "
|
||||
"is the last value. Each stack frame contains some of the following attributes:\n\n"
|
||||
"* :c - true if the stack frame is a c function invocation\n\n"
|
||||
"* :column - the current source column of the stack frame\n\n"
|
||||
"* :source-column - the current source column of the stack frame\n\n"
|
||||
"* :function - the function that the stack frame represents\n\n"
|
||||
"* :line - the current source line of the stack frame\n\n"
|
||||
"* :source-line - the current source line of the stack frame\n\n"
|
||||
"* :name - the human-friendly name of the function\n\n"
|
||||
"* :pc - integer indicating the location of the program counter\n\n"
|
||||
"* :source - string with the file path or other identifier for the source code\n\n"
|
||||
@@ -361,14 +364,15 @@ JANET_CORE_FN(cfun_debug_stack,
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_debug_stacktrace,
|
||||
"(debug/stacktrace fiber &opt err)",
|
||||
"(debug/stacktrace fiber &opt err prefix)",
|
||||
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
|
||||
"an error value to print the stack trace with. If `err` is nil or not "
|
||||
"provided, will skip the error line. Returns the fiber.") {
|
||||
janet_arity(argc, 1, 2);
|
||||
"provided, and no prefix is given, will skip the error line. Returns the fiber.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
|
||||
janet_stacktrace(fiber, x);
|
||||
const char *prefix = janet_optcstring(argv, argc, 2, NULL);
|
||||
janet_stacktrace_ext(fiber, x, prefix);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -464,9 +464,9 @@ const JanetAbstractType janet_stream_type = {
|
||||
|
||||
/* Register a fiber to resume with value */
|
||||
void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig) {
|
||||
if (fiber->flags & JANET_FIBER_FLAG_CANCELED) return;
|
||||
if (fiber->gc.flags & JANET_FIBER_EV_FLAG_CANCELED) return;
|
||||
JanetTask t = { fiber, value, sig, ++fiber->sched_id };
|
||||
if (sig == JANET_SIGNAL_ERROR) fiber->flags |= JANET_FIBER_FLAG_CANCELED;
|
||||
if (sig == JANET_SIGNAL_ERROR) fiber->gc.flags |= JANET_FIBER_EV_FLAG_CANCELED;
|
||||
janet_q_push(&janet_vm.spawn, &t, sizeof(t));
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ static int janet_chan_unpack(JanetChannel *chan, Janet *x, int is_cleanup) {
|
||||
return 1;
|
||||
case JANET_BUFFER: {
|
||||
JanetBuffer *buf = janet_unwrap_buffer(*x);
|
||||
int flags = is_cleanup ? JANET_MARSHAL_UNSAFE : (JANET_MARSHAL_UNSAFE | JANET_MARSHAL_DECREF);
|
||||
int flags = is_cleanup ? (JANET_MARSHAL_UNSAFE | JANET_MARSHAL_DECREF) : JANET_MARSHAL_UNSAFE;
|
||||
*x = janet_unmarshal(buf->data, buf->count, flags, NULL, NULL);
|
||||
janet_buffer_deinit(buf);
|
||||
janet_free(buf);
|
||||
@@ -744,7 +744,6 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
|
||||
int mode = msg.tag;
|
||||
JanetChannel *channel = (JanetChannel *) msg.argp;
|
||||
Janet x = msg.argj;
|
||||
janet_ev_dec_refcount();
|
||||
if (fiber->sched_id == sched_id) {
|
||||
if (mode == JANET_CP_MODE_CHOICE_READ) {
|
||||
janet_assert(!janet_chan_unpack(channel, &x, 0), "packing error");
|
||||
@@ -837,7 +836,6 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode) {
|
||||
pending.mode = mode ? JANET_CP_MODE_CHOICE_WRITE : JANET_CP_MODE_WRITE;
|
||||
janet_q_push(&channel->write_pending, &pending, sizeof(pending));
|
||||
janet_chan_unlock(channel);
|
||||
janet_ev_inc_refcount();
|
||||
if (is_threaded) {
|
||||
janet_gcroot(janet_wrap_fiber(pending.fiber));
|
||||
}
|
||||
@@ -855,7 +853,6 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode) {
|
||||
msg.argj = x;
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
janet_ev_dec_refcount();
|
||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||
janet_schedule(reader.fiber, make_read_result(channel, x));
|
||||
} else {
|
||||
@@ -888,7 +885,6 @@ static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice)
|
||||
pending.mode = is_choice ? JANET_CP_MODE_CHOICE_READ : JANET_CP_MODE_READ;
|
||||
janet_q_push(&channel->read_pending, &pending, sizeof(pending));
|
||||
janet_chan_unlock(channel);
|
||||
janet_ev_inc_refcount();
|
||||
if (is_threaded) {
|
||||
janet_gcroot(janet_wrap_fiber(pending.fiber));
|
||||
}
|
||||
@@ -907,7 +903,6 @@ static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice)
|
||||
msg.argj = janet_wrap_nil();
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
janet_ev_dec_refcount();
|
||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||
janet_schedule(writer.fiber, make_write_result(channel));
|
||||
} else {
|
||||
@@ -979,23 +974,30 @@ JANET_CORE_FN(cfun_channel_choice,
|
||||
JanetChannel *chan = janet_getchannel(data, 0);
|
||||
janet_chan_lock(chan);
|
||||
if (chan->closed) {
|
||||
janet_chan_unlock(chan);
|
||||
return make_close_result(chan);
|
||||
}
|
||||
if (janet_q_count(&chan->items) < chan->limit) {
|
||||
janet_chan_unlock(chan);
|
||||
janet_channel_push(chan, data[1], 1);
|
||||
return make_write_result(chan);
|
||||
}
|
||||
janet_chan_unlock(chan);
|
||||
} else {
|
||||
/* Read */
|
||||
JanetChannel *chan = janet_getchannel(argv, i);
|
||||
janet_chan_lock(chan);
|
||||
if (chan->closed) {
|
||||
janet_chan_unlock(chan);
|
||||
return make_close_result(chan);
|
||||
}
|
||||
if (chan->items.head != chan->items.tail) {
|
||||
Janet item;
|
||||
janet_chan_unlock(chan);
|
||||
janet_channel_pop(chan, &item, 1);
|
||||
return make_read_result(chan, item);
|
||||
}
|
||||
janet_chan_unlock(chan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,13 +1006,11 @@ JANET_CORE_FN(cfun_channel_choice,
|
||||
if (janet_indexed_view(argv[i], &data, &len) && len == 2) {
|
||||
/* Write */
|
||||
JanetChannel *chan = janet_getchannel(data, 0);
|
||||
if (chan->closed) continue;
|
||||
janet_channel_push(chan, data[1], 1);
|
||||
} else {
|
||||
/* Read */
|
||||
Janet item;
|
||||
JanetChannel *chan = janet_getchannel(argv, i);
|
||||
if (chan->closed) continue;
|
||||
janet_channel_pop(chan, &item, 1);
|
||||
}
|
||||
}
|
||||
@@ -1111,7 +1111,6 @@ JANET_CORE_FN(cfun_channel_close,
|
||||
msg.argj = janet_wrap_nil();
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
janet_ev_dec_refcount();
|
||||
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
|
||||
janet_schedule(writer.fiber, janet_wrap_nil());
|
||||
} else {
|
||||
@@ -1131,7 +1130,6 @@ JANET_CORE_FN(cfun_channel_close,
|
||||
msg.argj = janet_wrap_nil();
|
||||
janet_ev_post_event(vm, janet_thread_chan_cb, msg);
|
||||
} else {
|
||||
janet_ev_dec_refcount();
|
||||
if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
|
||||
janet_schedule(reader.fiber, janet_wrap_nil());
|
||||
} else {
|
||||
@@ -1228,22 +1226,27 @@ JanetFiber *janet_loop1(void) {
|
||||
while (janet_vm.spawn.head != janet_vm.spawn.tail) {
|
||||
JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK, 0};
|
||||
janet_q_pop(&janet_vm.spawn, &task, sizeof(task));
|
||||
task.fiber->flags &= ~JANET_FIBER_FLAG_CANCELED;
|
||||
if (task.fiber->gc.flags & JANET_FIBER_EV_FLAG_SUSPENDED) janet_ev_dec_refcount();
|
||||
task.fiber->gc.flags &= ~(JANET_FIBER_EV_FLAG_CANCELED | JANET_FIBER_EV_FLAG_SUSPENDED);
|
||||
if (task.expected_sched_id != task.fiber->sched_id) continue;
|
||||
Janet res;
|
||||
JanetSignal sig = janet_continue_signal(task.fiber, task.value, &res, task.sig);
|
||||
void *sv = task.fiber->supervisor_channel;
|
||||
int is_suspended = sig == JANET_SIGNAL_EVENT || sig == JANET_SIGNAL_YIELD || sig == JANET_SIGNAL_INTERRUPT;
|
||||
if (is_suspended) {
|
||||
task.fiber->gc.flags |= JANET_FIBER_EV_FLAG_SUSPENDED;
|
||||
janet_ev_inc_refcount();
|
||||
}
|
||||
if (NULL == sv) {
|
||||
if (!is_suspended) {
|
||||
janet_stacktrace(task.fiber, res);
|
||||
janet_stacktrace_ext(task.fiber, res, "");
|
||||
}
|
||||
} else if (sig == JANET_SIGNAL_OK || (task.fiber->flags & (1 << sig))) {
|
||||
JanetChannel *chan = janet_channel_unwrap(sv);
|
||||
janet_channel_push(chan, make_supervisor_event(janet_signal_names[sig],
|
||||
task.fiber, chan->is_threaded), 2);
|
||||
} else if (!is_suspended) {
|
||||
janet_stacktrace(task.fiber, res);
|
||||
janet_stacktrace_ext(task.fiber, res, "");
|
||||
}
|
||||
if (sig == JANET_SIGNAL_INTERRUPT) {
|
||||
/* On interrupts, return the interrupted fiber immediately */
|
||||
@@ -1431,7 +1434,7 @@ static void janet_epoll_sync_callback(JanetEVGenericMessage msg) {
|
||||
JanetAsyncStatus status2 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||
if (state->stream->_mask & JANET_ASYNC_LISTEN_WRITE)
|
||||
status1 = state->machine(state, JANET_ASYNC_EVENT_WRITE);
|
||||
if (state->stream->_mask & JANET_ASYNC_LISTEN_WRITE)
|
||||
if (state->stream->_mask & JANET_ASYNC_LISTEN_READ)
|
||||
status2 = state->machine(state, JANET_ASYNC_EVENT_READ);
|
||||
if (status1 == JANET_ASYNC_STATUS_DONE ||
|
||||
status2 == JANET_ASYNC_STATUS_DONE) {
|
||||
@@ -1611,9 +1614,6 @@ JanetTimestamp to_interval(const JanetTimestamp ts) {
|
||||
}
|
||||
#define JANET_KQUEUE_INTERVAL(timestamp) (to_interval((timestamp - ts_now())))
|
||||
|
||||
|
||||
/* TODO: make this available be we using kqueue or epoll, instead of
|
||||
* redefinining it for kqueue and epoll separately? */
|
||||
static JanetTimestamp ts_now(void) {
|
||||
struct timespec now;
|
||||
janet_assert(-1 != clock_gettime(CLOCK_MONOTONIC, &now), "failed to get time");
|
||||
@@ -2216,6 +2216,10 @@ JanetAsyncStatus ev_machine_read(JanetListenerState *s, JanetAsyncEvent event) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* Some handles (not all) read from the offset in lopOverlapped
|
||||
* if its not set before calling `ReadFile` these streams will always read from offset 0 */
|
||||
state->overlapped.Offset = (DWORD) state->bytes_read;
|
||||
|
||||
status = ReadFile(s->stream->handle, state->chunk_buf, chunk_size, NULL, &state->overlapped);
|
||||
if (!status && (ERROR_IO_PENDING != WSAGetLastError())) {
|
||||
if (WSAGetLastError() == ERROR_BROKEN_PIPE) {
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
|
||||
#define JANET_FIBER_STATUS_MASK 0x3F0000
|
||||
#define JANET_FIBER_RESUME_SIGNAL 0x400000
|
||||
#define JANET_FIBER_FLAG_CANCELED 0x400000
|
||||
#define JANET_FIBER_STATUS_OFFSET 16
|
||||
|
||||
#define JANET_FIBER_BREAKPOINT 0x1000000
|
||||
@@ -57,6 +56,9 @@
|
||||
#define JANET_FIBER_DID_LONGJUMP 0x8000000
|
||||
#define JANET_FIBER_FLAG_MASK 0xF000000
|
||||
|
||||
#define JANET_FIBER_EV_FLAG_CANCELED 0x10000
|
||||
#define JANET_FIBER_EV_FLAG_SUSPENDED 0x20000
|
||||
|
||||
#define janet_fiber_set_status(f, s) do {\
|
||||
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\
|
||||
(f)->flags |= (s) << JANET_FIBER_STATUS_OFFSET;\
|
||||
|
||||
@@ -483,6 +483,19 @@ static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
|
||||
janet_buffer_push_u8(buf, '\n');
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_FUNCTION: {
|
||||
/* Special case function */
|
||||
JanetFunction *fun = janet_unwrap_function(x);
|
||||
JanetBuffer *buf = janet_buffer(0);
|
||||
for (int32_t i = offset; i < argc; ++i) {
|
||||
janet_to_string_b(buf, argv[i]);
|
||||
}
|
||||
if (newline)
|
||||
janet_buffer_push_u8(buf, '\n');
|
||||
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||
janet_call(fun, 1, args);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
case JANET_NIL:
|
||||
f = dflt_file;
|
||||
if (f == NULL) janet_panic("cannot print to nil");
|
||||
|
||||
@@ -183,6 +183,8 @@ JANET_CORE_FN(os_arch,
|
||||
return janet_ckeywordv("sparc");
|
||||
#elif (defined(__ppc__))
|
||||
return janet_ckeywordv("ppc");
|
||||
#elif (defined(__ppc64__) || defined(_ARCH_PPC64) || defined(_M_PPC))
|
||||
return janet_ckeywordv("ppc64");
|
||||
#else
|
||||
return janet_ckeywordv("unknown");
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
fiber->env = env;
|
||||
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
|
||||
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
|
||||
janet_stacktrace(fiber, ret);
|
||||
janet_stacktrace_ext(fiber, ret, "");
|
||||
errflags |= 0x01;
|
||||
done = 1;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
ret = janet_wrap_string(cres.error);
|
||||
if (cres.macrofiber) {
|
||||
janet_eprintf("compile error in %s: ", sourcePath);
|
||||
janet_stacktrace(cres.macrofiber, ret);
|
||||
janet_stacktrace_ext(cres.macrofiber, ret, "");
|
||||
} else {
|
||||
janet_eprintf("compile error in %s: %s\n", sourcePath,
|
||||
(const char *)cres.error);
|
||||
@@ -121,7 +121,7 @@ int janet_loop_fiber(JanetFiber *fiber) {
|
||||
Janet out;
|
||||
status = janet_continue(fiber, janet_wrap_nil(), &out);
|
||||
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
|
||||
janet_stacktrace(fiber, out);
|
||||
janet_stacktrace_ext(fiber, out, "");
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
|
||||
@@ -154,6 +154,67 @@ static int destructure(JanetCompiler *c,
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
JanetSlot nextright = janetc_farslot(c);
|
||||
Janet subval = values[i];
|
||||
|
||||
if (janet_checktype(subval, JANET_SYMBOL) && !janet_cstrcmp(janet_unwrap_symbol(subval), "&")) {
|
||||
if (i + 1 >= len) {
|
||||
janetc_cerror(c, "expected symbol following '& in destructuring pattern");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (i + 2 < len) {
|
||||
int32_t num_extra = len - i - 1;
|
||||
Janet *extra = janet_tuple_begin(num_extra);
|
||||
janet_tuple_flag(extra) |= JANET_TUPLE_FLAG_BRACKETCTOR;
|
||||
|
||||
for (int32_t j = 0; j < num_extra; ++j) {
|
||||
extra[j] = values[j + i + 1];
|
||||
}
|
||||
|
||||
janetc_error(c, janet_formatc("expected a single symbol follow '& in destructuring pattern, found %q", janet_wrap_tuple(janet_tuple_end(extra))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (!janet_checktype(values[i + 1], JANET_SYMBOL)) {
|
||||
janetc_error(c, janet_formatc("expected symbol following '& in destructuring pattern, found %q", values[i + 1]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
JanetSlot argi = janetc_farslot(c);
|
||||
JanetSlot arg = janetc_farslot(c);
|
||||
JanetSlot len = janetc_farslot(c);
|
||||
|
||||
janetc_emit_si(c, JOP_LOAD_INTEGER, argi, i, 0);
|
||||
janetc_emit_ss(c, JOP_LENGTH, len, right, 0);
|
||||
|
||||
/* loop condition - reuse arg slot for the condition result */
|
||||
int32_t label_loop_start = janetc_emit_sss(c, JOP_LESS_THAN, arg, argi, len, 0);
|
||||
int32_t label_loop_cond_jump = janetc_emit_si(c, JOP_JUMP_IF_NOT, arg, 0, 0);
|
||||
|
||||
/* loop body */
|
||||
janetc_emit_sss(c, JOP_GET, arg, right, argi, 0);
|
||||
janetc_emit_s(c, JOP_PUSH, arg, 0);
|
||||
janetc_emit_ssi(c, JOP_ADD_IMMEDIATE, argi, argi, 1, 0);
|
||||
|
||||
/* loop - jump back to the start of the loop */
|
||||
int32_t label_loop_loop = janet_v_count(c->buffer);
|
||||
janetc_emit(c, JOP_JUMP);
|
||||
int32_t label_loop_exit = janet_v_count(c->buffer);
|
||||
|
||||
c->buffer[label_loop_cond_jump] |= (label_loop_exit - label_loop_cond_jump) << 16;
|
||||
c->buffer[label_loop_loop] |= (label_loop_start - label_loop_loop) << 8;
|
||||
|
||||
janetc_freeslot(c, argi);
|
||||
janetc_freeslot(c, arg);
|
||||
janetc_freeslot(c, len);
|
||||
|
||||
janetc_emit_s(c, JOP_MAKE_TUPLE, nextright, 1);
|
||||
|
||||
leaf(c, janet_unwrap_symbol(values[i + 1]), nextright, attr);
|
||||
janetc_freeslot(c, nextright);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 0x100) {
|
||||
janetc_emit_ssu(c, JOP_GET_INDEX, nextright, right, (uint8_t) i, 1);
|
||||
} else {
|
||||
@@ -298,8 +359,20 @@ static int varleaf(
|
||||
/* Global var, generate var */
|
||||
JanetSlot refslot;
|
||||
JanetTable *entry = janet_table_clone(reftab);
|
||||
JanetArray *ref = janet_array(1);
|
||||
janet_array_push(ref, janet_wrap_nil());
|
||||
|
||||
Janet redef_kw = janet_ckeywordv("redef");
|
||||
int is_redef = janet_truthy(janet_table_get(c->env, redef_kw));
|
||||
|
||||
JanetArray *ref;
|
||||
JanetBinding old_binding;
|
||||
if (is_redef && (old_binding = janet_resolve_ext(c->env, sym),
|
||||
old_binding.type == JANET_BINDING_VAR)) {
|
||||
ref = janet_unwrap_array(old_binding.value);
|
||||
} else {
|
||||
ref = janet_array(1);
|
||||
janet_array_push(ref, janet_wrap_nil());
|
||||
}
|
||||
|
||||
janet_table_put(entry, janet_ckeywordv("ref"), janet_wrap_array(ref));
|
||||
janet_table_put(entry, janet_ckeywordv("source-map"),
|
||||
janet_wrap_tuple(janetc_make_sourcemap(c)));
|
||||
@@ -331,14 +404,31 @@ static int defleaf(
|
||||
JanetTable *entry = janet_table_clone(tab);
|
||||
janet_table_put(entry, janet_ckeywordv("source-map"),
|
||||
janet_wrap_tuple(janetc_make_sourcemap(c)));
|
||||
JanetSlot valsym = janetc_cslot(janet_ckeywordv("value"));
|
||||
JanetSlot tabslot = janetc_cslot(janet_wrap_table(entry));
|
||||
|
||||
Janet redef_kw = janet_ckeywordv("redef");
|
||||
int is_redef = janet_truthy(janet_table_get(c->env, redef_kw));
|
||||
if (is_redef) janet_table_put(entry, redef_kw, janet_wrap_true());
|
||||
|
||||
if (is_redef) {
|
||||
JanetBinding binding = janet_resolve_ext(c->env, sym);
|
||||
JanetArray *ref;
|
||||
if (binding.type == JANET_BINDING_DYNAMIC_DEF || binding.type == JANET_BINDING_DYNAMIC_MACRO) {
|
||||
ref = janet_unwrap_array(binding.value);
|
||||
} else {
|
||||
ref = janet_array(1);
|
||||
janet_array_push(ref, janet_wrap_nil());
|
||||
}
|
||||
janet_table_put(entry, janet_ckeywordv("ref"), janet_wrap_array(ref));
|
||||
JanetSlot refslot = janetc_cslot(janet_wrap_array(ref));
|
||||
janetc_emit_ssu(c, JOP_PUT_INDEX, refslot, s, 0, 0);
|
||||
} else {
|
||||
JanetSlot valsym = janetc_cslot(janet_ckeywordv("value"));
|
||||
JanetSlot tabslot = janetc_cslot(janet_wrap_table(entry));
|
||||
janetc_emit_sss(c, JOP_PUT, tabslot, valsym, s, 0);
|
||||
}
|
||||
|
||||
/* Add env entry to env */
|
||||
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(entry));
|
||||
|
||||
/* Put value in table when evaulated */
|
||||
janetc_emit_sss(c, JOP_PUT, tabslot, valsym, s, 0);
|
||||
}
|
||||
return namelocal(c, sym, 0, s);
|
||||
}
|
||||
|
||||
@@ -224,13 +224,17 @@ int32_t janet_string_calchash(const uint8_t *str, int32_t len) {
|
||||
|
||||
#endif
|
||||
|
||||
uint32_t janet_hash_mix(uint32_t input, uint32_t more) {
|
||||
uint32_t mix1 = (more + 0x9e3779b9 + (input << 6) + (input >> 2));
|
||||
return input ^ (0x9e3779b9 + (mix1 << 6) + (mix1 >> 2));
|
||||
}
|
||||
|
||||
/* Computes hash of an array of values */
|
||||
int32_t janet_array_calchash(const Janet *array, int32_t len) {
|
||||
const Janet *end = array + len;
|
||||
uint32_t hash = 0;
|
||||
uint32_t hash = 33;
|
||||
while (array < end) {
|
||||
uint32_t elem = janet_hash(*array++);
|
||||
hash ^= elem + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash = janet_hash_mix(hash, janet_hash(*array++));
|
||||
}
|
||||
return (int32_t) hash;
|
||||
}
|
||||
@@ -238,10 +242,10 @@ int32_t janet_array_calchash(const Janet *array, int32_t len) {
|
||||
/* Computes hash of an array of values */
|
||||
int32_t janet_kv_calchash(const JanetKV *kvs, int32_t len) {
|
||||
const JanetKV *end = kvs + len;
|
||||
uint32_t hash = 0;
|
||||
uint32_t hash = 33;
|
||||
while (kvs < end) {
|
||||
hash ^= janet_hash(kvs->key) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= janet_hash(kvs->value) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash = janet_hash_mix(hash, janet_hash(kvs->key));
|
||||
hash = janet_hash_mix(hash, janet_hash(kvs->value));
|
||||
kvs++;
|
||||
}
|
||||
return (int32_t) hash;
|
||||
@@ -593,10 +597,8 @@ void janet_core_cfuns_ext(JanetTable *env, const char *regprefix, const JanetReg
|
||||
}
|
||||
#endif
|
||||
|
||||
JanetBinding janet_resolve_ext(JanetTable *env, const uint8_t *sym) {
|
||||
Janet ref;
|
||||
JanetBinding janet_binding_from_entry(Janet entry) {
|
||||
JanetTable *entry_table;
|
||||
Janet entry = janet_table_get(env, janet_wrap_symbol(sym));
|
||||
JanetBinding binding = {
|
||||
JANET_BINDING_NONE,
|
||||
janet_wrap_nil(),
|
||||
@@ -623,29 +625,41 @@ JanetBinding janet_resolve_ext(JanetTable *env, const uint8_t *sym) {
|
||||
binding.deprecation = JANET_BINDING_DEP_NORMAL;
|
||||
}
|
||||
|
||||
if (!janet_checktype(
|
||||
janet_table_get(entry_table, janet_ckeywordv("macro")),
|
||||
JANET_NIL)) {
|
||||
binding.value = janet_table_get(entry_table, janet_ckeywordv("value"));
|
||||
binding.type = JANET_BINDING_MACRO;
|
||||
int macro = janet_truthy(janet_table_get(entry_table, janet_ckeywordv("macro")));
|
||||
Janet value = janet_table_get(entry_table, janet_ckeywordv("value"));
|
||||
Janet ref = janet_table_get(entry_table, janet_ckeywordv("ref"));
|
||||
int ref_is_valid = janet_checktype(ref, JANET_ARRAY);
|
||||
int redef = ref_is_valid && janet_truthy(janet_table_get(entry_table, janet_ckeywordv("redef")));
|
||||
|
||||
if (macro) {
|
||||
binding.value = redef ? ref : value;
|
||||
binding.type = redef ? JANET_BINDING_DYNAMIC_MACRO : JANET_BINDING_MACRO;
|
||||
return binding;
|
||||
}
|
||||
|
||||
ref = janet_table_get(entry_table, janet_ckeywordv("ref"));
|
||||
if (janet_checktype(ref, JANET_ARRAY)) {
|
||||
if (ref_is_valid) {
|
||||
binding.value = ref;
|
||||
binding.type = JANET_BINDING_VAR;
|
||||
return binding;
|
||||
binding.type = redef ? JANET_BINDING_DYNAMIC_DEF : JANET_BINDING_VAR;
|
||||
} else {
|
||||
binding.value = value;
|
||||
binding.type = JANET_BINDING_DEF;
|
||||
}
|
||||
|
||||
binding.value = janet_table_get(entry_table, janet_ckeywordv("value"));
|
||||
binding.type = JANET_BINDING_DEF;
|
||||
return binding;
|
||||
}
|
||||
|
||||
JanetBinding janet_resolve_ext(JanetTable *env, const uint8_t *sym) {
|
||||
Janet entry = janet_table_get(env, janet_wrap_symbol(sym));
|
||||
return janet_binding_from_entry(entry);
|
||||
}
|
||||
|
||||
JanetBindingType janet_resolve(JanetTable *env, const uint8_t *sym, Janet *out) {
|
||||
JanetBinding binding = janet_resolve_ext(env, sym);
|
||||
*out = binding.value;
|
||||
if (binding.type == JANET_BINDING_DYNAMIC_DEF || binding.type == JANET_BINDING_DYNAMIC_MACRO) {
|
||||
*out = janet_array_peek(janet_unwrap_array(binding.value));
|
||||
} else {
|
||||
*out = binding.value;
|
||||
}
|
||||
return binding.type;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
} while (0)
|
||||
|
||||
/* Utils */
|
||||
uint32_t janet_hash_mix(uint32_t input, uint32_t more);
|
||||
#define janet_maphash(cap, hash) ((uint32_t)(hash) & (cap - 1))
|
||||
int janet_valid_utf8(const uint8_t *str, int32_t len);
|
||||
int janet_is_symbol_char(uint8_t c);
|
||||
@@ -83,6 +84,7 @@ void janet_buffer_format(
|
||||
int32_t argc,
|
||||
Janet *argv);
|
||||
Janet janet_next_impl(Janet ds, Janet key, int is_interpreter);
|
||||
JanetBinding janet_binding_from_entry(Janet entry);
|
||||
|
||||
/* Registry functions */
|
||||
void janet_registry_put(
|
||||
|
||||
@@ -324,7 +324,8 @@ int32_t janet_hash(Janet x) {
|
||||
as.d = janet_unwrap_number(x);
|
||||
uint32_t lo = (uint32_t)(as.u & 0xFFFFFFFF);
|
||||
uint32_t hi = (uint32_t)(as.u >> 32);
|
||||
hash = (int32_t)(hi ^ (lo >> 3));
|
||||
uint32_t hilo = (hi ^ lo) * 2654435769u;
|
||||
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
||||
break;
|
||||
}
|
||||
case JANET_ABSTRACT: {
|
||||
@@ -338,15 +339,17 @@ int32_t janet_hash(Janet x) {
|
||||
/* fallthrough */
|
||||
default:
|
||||
if (sizeof(double) == sizeof(void *)) {
|
||||
/* Assuming 8 byte pointer */
|
||||
/* Assuming 8 byte pointer (8 byte aligned) */
|
||||
uint64_t i = janet_u64(x);
|
||||
uint32_t lo = (uint32_t)(i & 0xFFFFFFFF);
|
||||
uint32_t hi = (uint32_t)(i >> 32);
|
||||
hash = (int32_t)(hi ^ (lo >> 3));
|
||||
uint32_t hilo = (hi ^ lo) * 2654435769u;
|
||||
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
||||
} else {
|
||||
/* Assuming 4 byte pointer (or smaller) */
|
||||
hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0);
|
||||
hash >>= 2;
|
||||
ptrdiff_t diff = ((char *)janet_unwrap_pointer(x) - (char *)0);
|
||||
uint32_t hilo = (uint32_t) diff * 2654435769u;
|
||||
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1763,6 +1763,7 @@ JANET_API JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out);
|
||||
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
|
||||
JANET_API Janet janet_mcall(const char *name, int32_t argc, Janet *argv);
|
||||
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
|
||||
JANET_API void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix);
|
||||
|
||||
/* Scratch Memory API */
|
||||
typedef void (*JanetScratchFinalizer)(void *);
|
||||
@@ -1778,7 +1779,9 @@ typedef enum {
|
||||
JANET_BINDING_NONE,
|
||||
JANET_BINDING_DEF,
|
||||
JANET_BINDING_VAR,
|
||||
JANET_BINDING_MACRO
|
||||
JANET_BINDING_MACRO,
|
||||
JANET_BINDING_DYNAMIC_DEF,
|
||||
JANET_BINDING_DYNAMIC_MACRO
|
||||
} JanetBindingType;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
(def str (string e))
|
||||
(if x
|
||||
(when is-verbose (eprintf "\e[32m✔\e[0m %s: %v" (describe e) x))
|
||||
(eprintf "\n\e[31m✘\e[0m %s: %v" (describe e) x))
|
||||
(eprintf "\e[31m✘\e[0m %s: %v" (describe e) x))
|
||||
x)
|
||||
|
||||
(defmacro assert-error
|
||||
|
||||
@@ -295,6 +295,21 @@
|
||||
(++ i))
|
||||
(assert (= i 6) "when macro"))
|
||||
|
||||
# Dynamic defs
|
||||
|
||||
(def staticdef1 0)
|
||||
(defn staticdef1-inc [] (+ 1 staticdef1))
|
||||
(assert (= 1 (staticdef1-inc)) "before redefinition without :redef")
|
||||
(def staticdef1 1)
|
||||
(assert (= 1 (staticdef1-inc)) "after redefinition without :redef")
|
||||
(setdyn :redef true)
|
||||
(def dynamicdef2 0)
|
||||
(defn dynamicdef2-inc [] (+ 1 dynamicdef2))
|
||||
(assert (= 1 (dynamicdef2-inc)) "before redefinition with dyn :redef")
|
||||
(def dynamicdef2 1)
|
||||
(assert (= 2 (dynamicdef2-inc)) "after redefinition with dyn :redef")
|
||||
(setdyn :redef nil)
|
||||
|
||||
# Denormal tables and structs
|
||||
|
||||
(assert (= (length {1 2 nil 3}) 1) "nil key struct literal")
|
||||
@@ -396,7 +411,7 @@
|
||||
compare-poly-tests
|
||||
[[(int/s64 3) (int/u64 3) 0]
|
||||
[(int/s64 -3) (int/u64 3) -1]
|
||||
[(int/s64 3) (int/u64 2) 1]
|
||||
[(int/s64 3) (int/u64 2) 1]
|
||||
[(int/s64 3) 3 0] [(int/s64 3) 4 -1] [(int/s64 3) -9 1]
|
||||
[(int/u64 3) 3 0] [(int/u64 3) 4 -1] [(int/u64 3) -9 1]
|
||||
[3 (int/s64 3) 0] [3 (int/s64 4) -1] [3 (int/s64 -5) 1]
|
||||
@@ -406,7 +421,7 @@
|
||||
[(int/u64 MAX_INT_IN_DBL_STRING) (scan-number MAX_INT_IN_DBL_STRING) 0]
|
||||
[(+ 1 (int/u64 MAX_INT_IN_DBL_STRING)) (scan-number MAX_INT_IN_DBL_STRING) 1]
|
||||
[(int/s64 0) INF -1] [(int/u64 0) INF -1]
|
||||
[MINUS_INF (int/u64 0) -1] [MINUS_INF (int/s64 0) -1]
|
||||
[MINUS_INF (int/u64 0) -1] [MINUS_INF (int/s64 0) -1]
|
||||
[(int/s64 1) NAN 0] [NAN (int/u64 1) 0]]]
|
||||
(each [x y c] compare-poly-tests
|
||||
(assert (= c (compare x y)) (string/format "compare polymorphic %q %q %d" x y c))))
|
||||
|
||||
@@ -137,6 +137,39 @@
|
||||
(assert (= a 1) "dictionary destructuring 3")
|
||||
(assert (= b 2) "dictionary destructuring 4")
|
||||
(assert (= c 4) "dictionary destructuring 5 - expression as key"))
|
||||
(let [test-tuple [:a :b 1 2]]
|
||||
(def [a b one two] test-tuple)
|
||||
(assert (= a :a) "tuple destructuring 1")
|
||||
(assert (= b :b) "tuple destructuring 2")
|
||||
(assert (= two 2) "tuple destructuring 3"))
|
||||
(let [test-tuple [:a :b 1 2]]
|
||||
(def [a & rest] test-tuple)
|
||||
(assert (= a :a) "tuple destructuring 4 - rest")
|
||||
(assert (= rest [:b 1 2]) "tuple destructuring 5 - rest"))
|
||||
(do
|
||||
(def [a b & rest] [:a :b nil :d])
|
||||
(assert (= a :a) "tuple destructuring 6 - rest")
|
||||
(assert (= b :b) "tuple destructuring 7 - rest")
|
||||
(assert (= rest [nil :d]) "tuple destructuring 8 - rest"))
|
||||
(do
|
||||
(def [[a b] x & rest] [[1 2] :a :c :b :a])
|
||||
(assert (= a 1) "tuple destructuring 9 - rest")
|
||||
(assert (= b 2) "tuple destructuring 10 - rest")
|
||||
(assert (= x :a) "tuple destructuring 11 - rest")
|
||||
(assert (= rest [:c :b :a]) "tuple destructuring 12 - rest"))
|
||||
(do
|
||||
(def [a b & rest] [:a :b])
|
||||
(assert (= a :a) "tuple destructuring 13 - rest")
|
||||
(assert (= b :b) "tuple destructuring 14 - rest")
|
||||
(assert (= rest []) "tuple destructuring 15 - rest"))
|
||||
|
||||
(do
|
||||
(def [[a b & r1] c & r2] [[:a :b 1 2] :c 3 4])
|
||||
(assert (= a :a) "tuple destructuring 16 - rest")
|
||||
(assert (= b :b) "tuple destructuring 17 - rest")
|
||||
(assert (= c :c) "tuple destructuring 18 - rest")
|
||||
(assert (= r1 [1 2]) "tuple destructuring 19 - rest")
|
||||
(assert (= r2 [3 4]) "tuple destructuring 20 - rest"))
|
||||
|
||||
# Marshal
|
||||
|
||||
@@ -288,6 +321,11 @@
|
||||
(assert (deep= (map + [1 2 3] [10 20 30] [100 200 300] [1000 2000 3000]) @[1111 2222 3333]))
|
||||
(assert (deep= (map + [1 2 3] [10 20 30] [100 200 300] [1000 2000 3000] [10000 20000 30000]) @[11111 22222 33333]))
|
||||
|
||||
# Mapping uses the shortest sequence
|
||||
(assert (deep= (map + [1 2 3 4] [10 20 30]) @[11 22 33]))
|
||||
(assert (deep= (map + [1 2 3 4] [10 20 30] [100 200]) @[111 222]))
|
||||
(assert (deep= (map + [1 2 3 4] [10 20 30] [100 200] [1000]) @[1111]))
|
||||
|
||||
# Sort function
|
||||
(assert (deep=
|
||||
(range 99)
|
||||
|
||||
@@ -168,6 +168,16 @@
|
||||
(assert (= (string out-buf) "Hello\nhi") "print and prin to buffer 1")
|
||||
(assert (= (string err-buf) "Sup\nnot much.") "eprint and eprin to buffer 1")
|
||||
|
||||
# Printing to functions
|
||||
(def out-buf @"")
|
||||
(defn prepend [x]
|
||||
(with-dyns [:out out-buf]
|
||||
(prin "> " x)))
|
||||
(with-dyns [:out prepend]
|
||||
(print "Hello world"))
|
||||
|
||||
(assert (= (string out-buf) "> Hello world\n") "print to buffer via function")
|
||||
|
||||
(assert (= (string '()) (string [])) "empty bracket tuple literal")
|
||||
|
||||
# with-vars
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
(assert (= nil (match {:a :hi} {:a a :b b} a)) "match 3")
|
||||
(assert (= nil (match [1 2] [a b c] a)) "match 4")
|
||||
(assert (= 2 (match [1 2] [a b] b)) "match 5")
|
||||
(assert (= [2 :a :b] (match [1 2 :a :b] [o & rest] rest)) "match 6")
|
||||
(assert (= [] (match @[:a] @[x & r] r :fallback)) "match 7")
|
||||
(assert (= :fallback (match @[1] @[x y & r] r :fallback)) "match 8")
|
||||
(assert (= [1 2 3 4] (match @[1 2 3 4] @[x y z & r] [x y z ;r] :fallback)) "match 9")
|
||||
|
||||
# And/or checks
|
||||
|
||||
|
||||
@@ -115,8 +115,21 @@
|
||||
# Cast to string to enable comparison
|
||||
(assert (= "123\n456\n" (string (slurp "unique.txt"))) "File writing 4.2")
|
||||
(os/rm "unique.txt"))
|
||||
|
||||
# ev/gather
|
||||
|
||||
# Test that the stream created by os/open can be read from
|
||||
(comment
|
||||
(assert-no-error "File reading 1.1"
|
||||
(def outstream (os/open "unique.txt" :wct))
|
||||
(defer (:close outstream)
|
||||
(:write outstream "123\n")
|
||||
(:write outstream "456\n"))
|
||||
|
||||
(def outstream (os/open "unique.txt" :r))
|
||||
(defer (:close outstream)
|
||||
(assert (= "123\n456\n" (string (:read outstream :all))) "File reading 1.2"))
|
||||
(os/rm "unique.txt")))
|
||||
|
||||
# ev/gather
|
||||
|
||||
(assert (deep= @[1 2 3] (ev/gather 1 2 3)) "ev/gather 1")
|
||||
(assert (deep= @[] (ev/gather)) "ev/gather 2")
|
||||
@@ -253,4 +266,13 @@
|
||||
(ev/rselect c2)
|
||||
(assert (= (slice arr) (slice (range 100))) "ev/chan-close 3")
|
||||
|
||||
# threaded channels
|
||||
|
||||
(def ch (ev/thread-chan 2))
|
||||
(def att (ev/thread-chan 109))
|
||||
(assert att "`att` was nil after creation")
|
||||
(ev/give ch att)
|
||||
(ev/do-thread
|
||||
(assert (ev/take ch) "channel packing bug for threaded abstracts on threaded channels."))
|
||||
|
||||
(end-suite)
|
||||
|
||||
@@ -21,11 +21,23 @@
|
||||
(import ./helper :prefix "" :exit true)
|
||||
(start-suite 11)
|
||||
|
||||
(assert (< 11899423.08 (math/gamma 11.5) 11899423.085)
|
||||
"math/gamma")
|
||||
# math gamma
|
||||
|
||||
(assert (< 2605.1158 (math/log-gamma 500) 2605.1159)
|
||||
"math/log-gamma")
|
||||
(assert (< 11899423.08 (math/gamma 11.5) 11899423.085) "math/gamma")
|
||||
(assert (< 2605.1158 (math/log-gamma 500) 2605.1159) "math/log-gamma")
|
||||
|
||||
# missing symbols
|
||||
|
||||
(defn lookup-symbol [sym] (defglobal sym 10) (dyn sym))
|
||||
|
||||
(setdyn :missing-symbol lookup-symbol)
|
||||
|
||||
(assert (= (eval-string "(+ a 5)") 15) "lookup missing symbol")
|
||||
|
||||
(setdyn :missing-symbol nil)
|
||||
(setdyn 'a nil)
|
||||
|
||||
(assert-error "compile error" (eval-string "(+ a 5)"))
|
||||
|
||||
(end-suite)
|
||||
|
||||
|
||||
24
tools/hashbench/ints1.janet
Normal file
24
tools/hashbench/ints1.janet
Normal file
@@ -0,0 +1,24 @@
|
||||
(def f @{})
|
||||
(var collisions 0)
|
||||
(loop [x :range [0 300] y :range [0 300]]
|
||||
(def key (hash (+ (* x 1000) y)))
|
||||
(if (in f key)
|
||||
(++ collisions))
|
||||
(put f key true))
|
||||
(print "ints 1 collisions: " collisions)
|
||||
|
||||
(def f @{})
|
||||
(var collisions 0)
|
||||
(loop [x :range [100000 101000] y :range [100000 101000]]
|
||||
(def key (hash [x y]))
|
||||
(if (in f key) (++ collisions))
|
||||
(put f key true))
|
||||
(print "int pair 1 collisions: " collisions)
|
||||
|
||||
(def f @{})
|
||||
(var collisions 0)
|
||||
(loop [x :range [10000 11000] y :range [10000 11000]]
|
||||
(def key (hash [x y]))
|
||||
(if (in f key) (++ collisions))
|
||||
(put f key true))
|
||||
(print "int pair 2 collisions: " collisions)
|
||||
Reference in New Issue
Block a user