mirror of
https://github.com/janet-lang/janet
synced 2025-11-07 02:53:02 +00:00
Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7491421c31 | ||
|
|
9d0da74347 | ||
|
|
e9870b293f | ||
|
|
ab910d060b | ||
|
|
b60ef68ac6 | ||
|
|
c9986936ed | ||
|
|
d77be46644 | ||
|
|
3715d7a184 | ||
|
|
1c96c7163a | ||
|
|
9f733b25db | ||
|
|
1419a33b64 | ||
|
|
f270739f9f | ||
|
|
e51a391286 | ||
|
|
c815185574 | ||
|
|
8045e29a52 | ||
|
|
bbb3e16fd1 | ||
|
|
3cd1657387 | ||
|
|
d7ea122cf7 | ||
|
|
6aea7c7f70 | ||
|
|
56ba1d9cd3 | ||
|
|
408b03ae0d | ||
|
|
d94fd746af | ||
|
|
dbd1316d1e | ||
|
|
75845c0283 | ||
|
|
88db9751d7 | ||
|
|
6f645c4cb7 | ||
|
|
4e31d85349 | ||
|
|
de542a81c0 | ||
|
|
461576e7a2 | ||
|
|
21bd62b1ce | ||
|
|
838cd1157c | ||
|
|
2f068b91d8 | ||
|
|
aba87bf1bd | ||
|
|
e64da8ede4 | ||
|
|
a9f38dfce4 | ||
|
|
a097537a03 | ||
|
|
66e0b53cf6 | ||
|
|
06f2e81dd5 | ||
|
|
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
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,6 +34,7 @@ local
|
||||
|
||||
# Common test files I use.
|
||||
temp.janet
|
||||
temp*.janet
|
||||
scratch.janet
|
||||
|
||||
# Emscripten
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,6 +1,33 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.21.1 - 2022-03-27
|
||||
- C functions `janet_dobytes` and `janet_dostring` will now enter the event loop if it is enabled.
|
||||
- Fix hashing regression - hash of negative 0 must be the same as positive 0 since they are equal.
|
||||
- The `flycheck` function no longer pollutes the module/cache
|
||||
- Fix quasiquote bug in compiler
|
||||
- Disallow use of `cancel` and `resume` on fibers scheduled or created with `ev/go`, as well as the root
|
||||
fiber.
|
||||
|
||||
## 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.
|
||||
|
||||
3
Makefile
3
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 $< $@
|
||||
@@ -238,6 +238,7 @@ build/janet-%.tar.gz: $(JANET_TARGET) \
|
||||
mkdir -p build/$(JANET_DIST_DIR)/lib/
|
||||
cp $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
|
||||
mkdir -p build/$(JANET_DIST_DIR)/man/man1/
|
||||
cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
|
||||
mkdir -p build/$(JANET_DIST_DIR)/src/
|
||||
cp build/c/janet.c build/c/shell.c build/$(JANET_DIST_DIR)/src/
|
||||
cp CONTRIBUTING.md LICENSE README.md build/$(JANET_DIST_DIR)/
|
||||
|
||||
@@ -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)
|
||||
@@ -285,7 +284,7 @@ Usually, one of a few reasons:
|
||||
Janet does not run on the JVM, and has a more primitive garbage collector.
|
||||
- We want to keep the Janet core small. With Lisps, usually a feature can be added as a library
|
||||
without feeling "bolted on", especially when compared to ALGOL like languages. Adding features
|
||||
to the core also makes it a bit more difficult keep Janet maximally portable.
|
||||
to the core also makes it a bit more difficult to keep Janet maximally portable.
|
||||
|
||||
### Why is my terminal spitting out junk when I run the REPL?
|
||||
|
||||
|
||||
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.21.0')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -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))
|
||||
@@ -1147,12 +1155,36 @@
|
||||
(array/push parts (tuple apply f $args)))
|
||||
(tuple 'fn (tuple '& $args) (tuple/slice parts 0)))
|
||||
|
||||
(defmacro defdyn
|
||||
``Define an alias for a keyword that is used as a dynamic binding. The
|
||||
alias is a normal, lexically scoped binding that can be used instead of
|
||||
a keyword to prevent typos. Defdyn does not set dynamic bindings or otherwise
|
||||
replace `dyn` and `setdyn`. The alias _must_ start and end with the `*` character, usually
|
||||
called "earmuffs".``
|
||||
[alias & more]
|
||||
(assert (symbol? alias) "alias must be a symbol")
|
||||
(assert (and (> (length alias) 2) (= 42 (first alias) (last alias))) "name must have leading and trailing '*' characters")
|
||||
(def prefix (dyn :defdyn-prefix))
|
||||
(def kw (keyword prefix (slice alias 1 -2)))
|
||||
~(def ,alias :dyn ,;more ,kw))
|
||||
|
||||
(defdyn *defdyn-prefix* "Optional namespace prefix to add to keywords declared with `defdyn`.
|
||||
Use this to prevent keyword collisions between dynamic bindings.")
|
||||
(defdyn *out* "Where normal print functions print output to.")
|
||||
(defdyn *err* "Where error printing prints output to.")
|
||||
|
||||
(defdyn *macro-form*
|
||||
"Inside a macro, is bound to the source form that invoked the macro")
|
||||
|
||||
(defdyn *current-file*
|
||||
"Bound to the name of the currently compiling file.")
|
||||
|
||||
(defmacro tracev
|
||||
`Print a value and a description of the form that produced that value to
|
||||
stderr. Evaluates to x.`
|
||||
[x]
|
||||
(def [l c] (tuple/sourcemap (dyn :macro-form ())))
|
||||
(def cf (dyn :current-file))
|
||||
(def [l c] (tuple/sourcemap (dyn *macro-form* ())))
|
||||
(def cf (dyn *current-file*))
|
||||
(def fmt-1 (if cf (string/format "trace [%s]" cf) "trace"))
|
||||
(def fmt-2 (if (or (neg? l) (neg? c)) ":" (string/format " on line %d, column %d:" l c)))
|
||||
(def fmt (string fmt-1 fmt-2 " %j is "))
|
||||
@@ -1647,10 +1679,13 @@
|
||||
(file/close f)
|
||||
nil)
|
||||
|
||||
(defdyn *pretty-format*
|
||||
"Format specifier for the `pp` function")
|
||||
|
||||
(defn pp
|
||||
`Pretty print to stdout or (dyn :out). The format string used is (dyn :pretty-format "%q").`
|
||||
`Pretty print to stdout or (dyn *out*). The format string used is (dyn *pretty-format* "%q").`
|
||||
[x]
|
||||
(printf (dyn :pretty-format "%q") x)
|
||||
(printf (dyn *pretty-format* "%q") x)
|
||||
(flush))
|
||||
|
||||
###
|
||||
@@ -1668,8 +1703,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 +1779,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 +1818,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
|
||||
@@ -1847,13 +1909,17 @@
|
||||
###
|
||||
###
|
||||
|
||||
(defdyn *macro-lints*
|
||||
"Bound to an array of lint messgae that will be reported by the compiler inside a macro.
|
||||
To indicate an error or warning, a macro author should use `maclintf`.")
|
||||
|
||||
(defn maclintf
|
||||
``When inside a macro, call this function to add a linter warning. Takes
|
||||
a `fmt` argument like `string/format` which is used to format the message.``
|
||||
[level fmt & args]
|
||||
(def lints (dyn :macro-lints))
|
||||
(def lints (dyn *macro-lints*))
|
||||
(when lints
|
||||
(def form (dyn :macro-form))
|
||||
(def form (dyn *macro-form*))
|
||||
(def [l c] (if (tuple? form) (tuple/sourcemap form) [nil nil]))
|
||||
(def l (if-not (= -1 l) l))
|
||||
(def c (if-not (= -1 c) c))
|
||||
@@ -1944,11 +2010,11 @@
|
||||
(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)))
|
||||
m? (do (setdyn *macro-form* t) (m ;(tuple/slice t 1)))
|
||||
(tuple/slice (map recur t))))
|
||||
|
||||
(def ret
|
||||
@@ -2156,10 +2222,13 @@
|
||||
(def newenv (table/setproto @{} parent))
|
||||
newenv)
|
||||
|
||||
(defdyn *err-color*
|
||||
"Whether or not to turn on error coloring in stacktraces and other error messages.")
|
||||
|
||||
(defn bad-parse
|
||||
"Default handler for a parse error."
|
||||
[p where]
|
||||
(def ec (dyn :err-color))
|
||||
(def ec (dyn *err-color*))
|
||||
(def [line col] (:where p))
|
||||
(eprint
|
||||
(if ec "\e[31m" "")
|
||||
@@ -2178,24 +2247,25 @@
|
||||
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"
|
||||
[msg level where &opt line col]
|
||||
(def ec (dyn :err-color))
|
||||
(def ec (dyn *err-color*))
|
||||
(eprin
|
||||
(if ec "\e[33m" "")
|
||||
where
|
||||
@@ -2213,7 +2283,7 @@
|
||||
(defn bad-compile
|
||||
"Default handler for a compile error."
|
||||
[msg macrof where &opt line col]
|
||||
(def ec (dyn :err-color))
|
||||
(def ec (dyn *err-color*))
|
||||
(eprin
|
||||
(if ec "\e[31m" "")
|
||||
where
|
||||
@@ -2223,7 +2293,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 +2325,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 +2357,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 +2442,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 +2506,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 +2675,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 +2693,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)
|
||||
@@ -2630,7 +2703,7 @@
|
||||
(os/exit 1))
|
||||
(put env :exit true)
|
||||
(def buf @"")
|
||||
(with-dyns [:err buf :err-color false]
|
||||
(with-dyns [*err* buf *err-color* false]
|
||||
(bad-parse x y))
|
||||
(set exit-error (string/slice buf 0 -2)))
|
||||
(defn bc [&opt x y z a b]
|
||||
@@ -2639,7 +2712,7 @@
|
||||
(os/exit 1))
|
||||
(put env :exit true)
|
||||
(def buf @"")
|
||||
(with-dyns [:err buf :err-color false]
|
||||
(with-dyns [*err* buf *err-color* false]
|
||||
(bad-compile x nil z a b))
|
||||
(set exit-error (string/slice buf 0 -2))
|
||||
(set exit-fiber y))
|
||||
@@ -2653,8 +2726,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 +2736,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
|
||||
@@ -2789,6 +2861,12 @@
|
||||
[&opt env local]
|
||||
(env-walk keyword? env local))
|
||||
|
||||
(defdyn *doc-width*
|
||||
"Width in columns to print documentation printed with `doc-format`")
|
||||
|
||||
(defdyn *doc-color*
|
||||
"Whether or not to colorize documentation printed with `doc-format`.")
|
||||
|
||||
(defn doc-format
|
||||
`Reformat a docstring to wrap a certain width. Docstrings can either be plaintext
|
||||
or a subset of markdown. This allows a long single line of prose or formatted text to be
|
||||
@@ -2796,10 +2874,10 @@
|
||||
[str &opt width indent colorize]
|
||||
|
||||
(default indent 4)
|
||||
(def max-width (- (or width (dyn :doc-width 80)) 8))
|
||||
(def max-width (- (or width (dyn *doc-width* 80)) 8))
|
||||
(def has-color (if (not= nil colorize)
|
||||
colorize
|
||||
(dyn :doc-color)))
|
||||
(dyn *doc-color*)))
|
||||
|
||||
# Terminal codes for emission/tokenization
|
||||
(def delimiters
|
||||
@@ -3067,6 +3145,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 +3154,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 +3240,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 +3437,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 +3446,7 @@
|
||||
:on-status (or onsignal (make-onsignal env 1))
|
||||
:parser parser
|
||||
:read read
|
||||
:source "repl"}))
|
||||
:source :repl}))
|
||||
|
||||
###
|
||||
###
|
||||
@@ -3511,13 +3588,17 @@
|
||||
arbitrary execution is possible. Other arguments are the same as dofile. `path` can also be
|
||||
a file value such as stdin. Returns nil.``
|
||||
[path &keys kwargs]
|
||||
(def old-modcache (table/clone module/cache))
|
||||
(table/clear module/cache)
|
||||
(try
|
||||
(dofile path :evaluator flycheck-evaluator ;(kvs kwargs))
|
||||
([e f]
|
||||
(eprint e)
|
||||
(debug/stacktrace f)))
|
||||
(debug/stacktrace f e "")))
|
||||
(table/clear module/cache)
|
||||
(merge-into module/cache old-modcache)
|
||||
nil)
|
||||
|
||||
|
||||
###
|
||||
###
|
||||
### CLI Tool Main
|
||||
@@ -3529,16 +3610,27 @@
|
||||
|
||||
(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))))))
|
||||
|
||||
(defdyn *args*
|
||||
"Dynamic bindings that will contain command line arguments at program start")
|
||||
|
||||
(defdyn *executable*
|
||||
"Name of the interpreter executable used to execute this program. Corresponds to argv[0] in the call to
|
||||
int main(int argc, char **argv);")
|
||||
|
||||
(defdyn *profilepath*
|
||||
"Path to profile file loaded when starting up the repl.")
|
||||
|
||||
(defn cli-main
|
||||
`Entrance for the Janet CLI tool. Call this function with the command line
|
||||
arguments as an array or tuple of strings to invoke the CLI interface.`
|
||||
[args]
|
||||
|
||||
(setdyn :args args)
|
||||
(setdyn *args* args)
|
||||
|
||||
(var should-repl false)
|
||||
(var no-file true)
|
||||
@@ -3554,7 +3646,7 @@
|
||||
(var expect-image false)
|
||||
|
||||
(if-let [jp (getenv-alias "JANET_PATH")] (setdyn :syspath jp))
|
||||
(if-let [jprofile (getenv-alias "JANET_PROFILE")] (setdyn :profilepath jprofile))
|
||||
(if-let [jprofile (getenv-alias "JANET_PROFILE")] (setdyn *profilepath* jprofile))
|
||||
|
||||
(defn- get-lint-level
|
||||
[i]
|
||||
@@ -3564,7 +3656,7 @@
|
||||
# Flag handlers
|
||||
(def handlers
|
||||
{"h" (fn [&]
|
||||
(print "usage: " (dyn :executable "janet") " [options] script args...")
|
||||
(print "usage: " (dyn *executable* "janet") " [options] script args...")
|
||||
(print
|
||||
```
|
||||
Options are:
|
||||
@@ -3626,7 +3718,7 @@
|
||||
"d" (fn [&] (set debug-flag true) 1)
|
||||
"w" (fn [i &] (set warn-level (get-lint-level i)) 2)
|
||||
"x" (fn [i &] (set error-level (get-lint-level i)) 2)
|
||||
"R" (fn [&] (setdyn :profilepath nil) 1)})
|
||||
"R" (fn [&] (setdyn *profilepath* nil) 1)})
|
||||
|
||||
(defn- dohandler [n i &]
|
||||
(def h (in handlers n))
|
||||
@@ -3648,14 +3740,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 +3761,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"))
|
||||
@@ -3678,10 +3774,12 @@
|
||||
(file/flush stdout)
|
||||
(file/read stdin :line buf))
|
||||
(def env (make-env))
|
||||
(when-let [profile.janet (dyn :profilepath)]
|
||||
(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))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#define JANETCONF_H
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 19
|
||||
#define JANET_VERSION_PATCH 0
|
||||
#define JANET_VERSION_MINOR 21
|
||||
#define JANET_VERSION_PATCH 1
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.19.0"
|
||||
#define JANET_VERSION "1.21.1"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -339,7 +339,10 @@ JANET_CORE_FN(janet_core_native,
|
||||
|
||||
JANET_CORE_FN(janet_core_describe,
|
||||
"(describe x)",
|
||||
"Returns a string that is a human-readable description of a value x.") {
|
||||
"Returns a string that is a human-readable description of `x`. "
|
||||
"For recursive data structures, the string returned contains a "
|
||||
"pointer value from which the identity of `x` "
|
||||
"can be determined.") {
|
||||
JanetBuffer *b = janet_buffer(0);
|
||||
for (int32_t i = 0; i < argc; ++i)
|
||||
janet_description_b(b, argv[i]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -464,9 +464,10 @@ 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;
|
||||
fiber->gc.flags |= JANET_FIBER_FLAG_ROOT;
|
||||
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 +621,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 +745,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 +837,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 +854,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 +886,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 +904,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 +975,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 +1007,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 +1112,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 +1131,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 +1227,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 */
|
||||
@@ -1257,8 +1261,25 @@ JanetFiber *janet_loop1(void) {
|
||||
memset(&to, 0, sizeof(to));
|
||||
int has_timeout;
|
||||
/* Drop timeouts that are no longer needed */
|
||||
while ((has_timeout = peek_timeout(&to)) && (to.curr_fiber == NULL) && to.fiber->sched_id != to.sched_id) {
|
||||
pop_timeout(0);
|
||||
while ((has_timeout = peek_timeout(&to))) {
|
||||
if (to.curr_fiber != NULL) {
|
||||
JanetFiberStatus s = janet_fiber_status(to.curr_fiber);
|
||||
int is_finished = (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 (is_finished) {
|
||||
pop_timeout(0);
|
||||
continue;
|
||||
}
|
||||
} else if (to.fiber->sched_id != to.sched_id) {
|
||||
pop_timeout(0);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Run polling implementation only if pending timeouts or pending events */
|
||||
if (janet_vm.tq_count || janet_vm.listener_count || janet_vm.extra_listeners) {
|
||||
@@ -1431,7 +1452,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 +1632,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 +2234,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) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -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,10 @@
|
||||
#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_FLAG_ROOT 0x40000
|
||||
|
||||
#define janet_fiber_set_status(f, s) do {\
|
||||
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\
|
||||
(f)->flags |= (s) << JANET_FIBER_STATUS_OFFSET;\
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose & contributors
|
||||
* Copyright (c) 2022 Calvin Rose & contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -207,6 +207,92 @@ JANET_CORE_FN(cfun_it_u64_new,
|
||||
return janet_wrap_u64(janet_unwrap_u64(argv[0]));
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_to_number,
|
||||
"(int/to-number value)",
|
||||
"Convert an int/u64 or int/s64 to a number. Fails if the number is out of range for an int32.") {
|
||||
janet_fixarity(argc, 1);
|
||||
if (janet_type(argv[0]) == JANET_ABSTRACT) {
|
||||
void *abst = janet_unwrap_abstract(argv[0]);
|
||||
|
||||
if (janet_abstract_type(abst) == &janet_s64_type) {
|
||||
int64_t value = *((int64_t *)abst);
|
||||
if (value > JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
if (value < -JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
return janet_wrap_number((double)value);
|
||||
}
|
||||
|
||||
if (janet_abstract_type(abst) == &janet_u64_type) {
|
||||
uint64_t value = *((uint64_t *)abst);
|
||||
if (value > JANET_INTMAX_INT64) {
|
||||
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
|
||||
}
|
||||
|
||||
return janet_wrap_number((double)value);
|
||||
}
|
||||
}
|
||||
|
||||
janet_panicf("expected int/u64 or int/s64, got %q", argv[0]);
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_to_bytes,
|
||||
"(int/to-bytes value &opt endianness buffer)",
|
||||
"Write the bytes of an `int/s64` or `int/u64` into a buffer.\n"
|
||||
"The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n"
|
||||
"Returns the modified buffer.\n"
|
||||
"The `endianness` paramater indicates the byte order:\n"
|
||||
"- `nil` (unset): system byte order\n"
|
||||
"- `:le`: little-endian, least significant byte first\n"
|
||||
"- `:be`: big-endian, most significant byte first\n") {
|
||||
janet_arity(argc, 1, 3);
|
||||
if (janet_is_int(argv[0]) == JANET_INT_NONE) {
|
||||
janet_panicf("int/to-bytes: expected an int/s64 or int/u64, got %q", argv[0]);
|
||||
}
|
||||
|
||||
int reverse = 0;
|
||||
if (argc > 1 && !janet_checktype(argv[1], JANET_NIL)) {
|
||||
JanetKeyword endianness_kw = janet_getkeyword(argv, 1);
|
||||
if (!janet_cstrcmp(endianness_kw, "le")) {
|
||||
#if JANET_BIG_ENDIAN
|
||||
reverse = 1;
|
||||
#endif
|
||||
} else if (!janet_cstrcmp(endianness_kw, "be")) {
|
||||
#if JANET_LITTLE_ENDIAN
|
||||
reverse = 1;
|
||||
#endif
|
||||
} else {
|
||||
janet_panicf("int/to-bytes: expected endianness :le, :be or nil, got %v", argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
JanetBuffer *buffer = NULL;
|
||||
if (argc > 2 && !janet_checktype(argv[2], JANET_NIL)) {
|
||||
if (!janet_checktype(argv[2], JANET_BUFFER)) {
|
||||
janet_panicf("int/to-bytes: expected buffer or nil, got %q", argv[2]);
|
||||
}
|
||||
|
||||
buffer = janet_unwrap_buffer(argv[2]);
|
||||
janet_buffer_extra(buffer, 8);
|
||||
} else {
|
||||
buffer = janet_buffer(8);
|
||||
}
|
||||
|
||||
uint8_t *bytes = janet_unwrap_abstract(argv[0]);
|
||||
if (reverse) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
buffer->data[buffer->count + 7 - i] = bytes[i];
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer->data + buffer->count, bytes, 8);
|
||||
}
|
||||
buffer->count += 8;
|
||||
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Code to support polymorphic comparison.
|
||||
* int/u64 and int/s64 support a "compare" method that allows
|
||||
@@ -514,6 +600,8 @@ void janet_lib_inttypes(JanetTable *env) {
|
||||
JanetRegExt it_cfuns[] = {
|
||||
JANET_CORE_REG("int/s64", cfun_it_s64_new),
|
||||
JANET_CORE_REG("int/u64", cfun_it_u64_new),
|
||||
JANET_CORE_REG("int/to-number", cfun_to_number),
|
||||
JANET_CORE_REG("int/to-bytes", cfun_to_bytes),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, it_cfuns);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -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");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose and contributors.
|
||||
* Copyright (c) 2022 Calvin Rose and contributors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose and contributors.
|
||||
* Copyright (c) 2022 Calvin Rose and contributors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -39,10 +39,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef JANET_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
@@ -67,12 +63,6 @@ extern char **environ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For macos */
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
/* Not POSIX, but all Unixes but Solaris have this function. */
|
||||
#if defined(JANET_POSIX) && !defined(__sun)
|
||||
time_t timegm(struct tm *tm);
|
||||
@@ -183,6 +173,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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
/* Run a string */
|
||||
@@ -50,7 +51,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 +59,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);
|
||||
@@ -100,6 +101,14 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
|
||||
/* Clean up and return errors */
|
||||
janet_parser_deinit(&parser);
|
||||
if (where) janet_gcunroot(janet_wrap_string(where));
|
||||
#ifdef JANET_EV
|
||||
/* Enter the event loop if we are not already in it */
|
||||
if (janet_vm.stackn == 0) {
|
||||
janet_gcroot(ret);
|
||||
janet_loop();
|
||||
janet_gcunroot(ret);
|
||||
}
|
||||
#endif
|
||||
if (out) *out = ret;
|
||||
return errflags;
|
||||
}
|
||||
@@ -121,7 +130,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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -62,6 +62,8 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
|
||||
return janetc_cslot(janet_wrap_nil());
|
||||
}
|
||||
JanetSlot *slots = NULL;
|
||||
JanetFopts subopts = opts;
|
||||
subopts.flags &= ~JANET_FOPTS_HINT;
|
||||
switch (janet_type(x)) {
|
||||
default:
|
||||
return janetc_cslot(x);
|
||||
@@ -82,7 +84,7 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
janet_v_push(slots, quasiquote(opts, tup[i], depth - 1, level));
|
||||
janet_v_push(slots, quasiquote(subopts, tup[i], depth - 1, level));
|
||||
return qq_slots(opts, slots, (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR)
|
||||
? JOP_MAKE_BRACKET_TUPLE
|
||||
: JOP_MAKE_TUPLE);
|
||||
@@ -91,7 +93,7 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
|
||||
int32_t i;
|
||||
JanetArray *array = janet_unwrap_array(x);
|
||||
for (i = 0; i < array->count; i++)
|
||||
janet_v_push(slots, quasiquote(opts, array->data[i], depth - 1, level));
|
||||
janet_v_push(slots, quasiquote(subopts, array->data[i], depth - 1, level));
|
||||
return qq_slots(opts, slots, JOP_MAKE_ARRAY);
|
||||
}
|
||||
case JANET_TABLE:
|
||||
@@ -100,8 +102,8 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
|
||||
int32_t len, cap = 0;
|
||||
janet_dictionary_view(x, &kvs, &len, &cap);
|
||||
while ((kv = janet_dictionary_next(kvs, cap, kv))) {
|
||||
JanetSlot key = quasiquote(opts, kv->key, depth - 1, level);
|
||||
JanetSlot value = quasiquote(opts, kv->value, depth - 1, level);
|
||||
JanetSlot key = quasiquote(subopts, kv->key, depth - 1, level);
|
||||
JanetSlot value = quasiquote(subopts, kv->value, depth - 1, level);
|
||||
key.flags &= ~JANET_SLOT_SPLICED;
|
||||
value.flags &= ~JANET_SLOT_SPLICED;
|
||||
janet_v_push(slots, key);
|
||||
@@ -154,6 +156,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 +361,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 +406,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);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -36,6 +36,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JANET_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Base 64 lookup table for digits */
|
||||
@@ -224,13 +228,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 +246,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 +601,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 +629,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;
|
||||
}
|
||||
|
||||
@@ -775,11 +793,6 @@ int32_t janet_sorted_keys(const JanetKV *dict, int32_t cap, int32_t *index_buffe
|
||||
|
||||
/* Clock shims for various platforms */
|
||||
#ifdef JANET_GETTIME
|
||||
/* For macos */
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
#ifdef JANET_WINDOWS
|
||||
int janet_gettime(struct timespec *spec) {
|
||||
FILETIME ftime;
|
||||
@@ -792,7 +805,10 @@ int janet_gettime(struct timespec *spec) {
|
||||
spec->tv_nsec = wintime % 10000000LL * 100;
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__MACH__)
|
||||
/* clock_gettime() wasn't available on Mac until 10.12. */
|
||||
#elif defined(JANET_APPLE) && !defined(MAC_OS_X_VERSION_10_12)
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
int janet_gettime(struct timespec *spec) {
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -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(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -322,9 +322,11 @@ int32_t janet_hash(Janet x) {
|
||||
uint64_t u;
|
||||
} as;
|
||||
as.d = janet_unwrap_number(x);
|
||||
as.d += 0.0; /* normalize negative 0 */
|
||||
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 +340,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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -315,7 +315,7 @@ 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_check_can_resume(JanetFiber *fiber, Janet *out, int is_cancel);
|
||||
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out);
|
||||
|
||||
/* Interpreter main loop */
|
||||
@@ -1056,7 +1056,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
vm_maybe_auto_suspend(1);
|
||||
vm_assert_type(stack[B], JANET_FIBER);
|
||||
JanetFiber *child = janet_unwrap_fiber(stack[B]);
|
||||
if (janet_check_can_resume(child, &retreg)) {
|
||||
if (janet_check_can_resume(child, &retreg, 0)) {
|
||||
vm_commit();
|
||||
janet_panicv(retreg);
|
||||
}
|
||||
@@ -1096,7 +1096,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
Janet retreg;
|
||||
vm_assert_type(stack[B], JANET_FIBER);
|
||||
JanetFiber *child = janet_unwrap_fiber(stack[B]);
|
||||
if (janet_check_can_resume(child, &retreg)) {
|
||||
if (janet_check_can_resume(child, &retreg, 1)) {
|
||||
vm_commit();
|
||||
janet_panicv(retreg);
|
||||
}
|
||||
@@ -1330,7 +1330,7 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||
return *janet_vm.return_reg;
|
||||
}
|
||||
|
||||
static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
|
||||
static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out, int is_cancel) {
|
||||
/* Check conditions */
|
||||
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||
if (janet_vm.stackn >= JANET_RECURSION_GUARD) {
|
||||
@@ -1338,6 +1338,20 @@ static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
|
||||
*out = janet_cstringv("C stack recursed too deeply");
|
||||
return JANET_SIGNAL_ERROR;
|
||||
}
|
||||
/* If a "task" fiber is trying to be used as a normal fiber, detect that. See bug #920.
|
||||
* Fibers must be marked as root fibers manually, or by the ev scheduler. */
|
||||
if (janet_vm.fiber != NULL && (fiber->gc.flags & JANET_FIBER_FLAG_ROOT)) {
|
||||
#ifdef JANET_EV
|
||||
*out = janet_cstringv(is_cancel
|
||||
? "cannot cancel root fiber, use ev/cancel"
|
||||
: "cannot resume root fiber, use ev/go");
|
||||
#else
|
||||
*out = janet_cstringv(is_cancel
|
||||
? "cannot cancel root fiber"
|
||||
: "cannot resume root fiber");
|
||||
#endif
|
||||
return JANET_SIGNAL_ERROR;
|
||||
}
|
||||
if (old_status == JANET_STATUS_ALIVE ||
|
||||
old_status == JANET_STATUS_DEAD ||
|
||||
(old_status >= JANET_STATUS_USER0 && old_status <= JANET_STATUS_USER4) ||
|
||||
@@ -1452,14 +1466,14 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
||||
/* 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);
|
||||
JanetSignal tmp_signal = janet_check_can_resume(fiber, out, 0);
|
||||
if (tmp_signal) return tmp_signal;
|
||||
return janet_continue_no_check(fiber, in, out);
|
||||
}
|
||||
|
||||
/* Enter the main vm loop but immediately raise a signal */
|
||||
JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig) {
|
||||
JanetSignal tmp_signal = janet_check_can_resume(fiber, out);
|
||||
JanetSignal tmp_signal = janet_check_can_resume(fiber, out, sig != JANET_SIGNAL_OK);
|
||||
if (tmp_signal) return tmp_signal;
|
||||
if (sig != JANET_SIGNAL_OK) {
|
||||
JanetFiber *child = fiber;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -57,8 +57,8 @@ extern "C" {
|
||||
#define JANET_BSD 1
|
||||
#endif
|
||||
|
||||
/* Check for Mac */
|
||||
#ifdef __APPLE__
|
||||
/* Check for macOS or OS X */
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define JANET_APPLE 1
|
||||
#endif
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
* Copyright (c) 2022 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include <janet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -75,6 +76,9 @@ static void simpleline(JanetBuffer *buffer) {
|
||||
int c;
|
||||
for (;;) {
|
||||
c = fgetc(in);
|
||||
if (c < 0 && !feof(in) && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (feof(in) || c < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -112,7 +116,6 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -742,7 +745,11 @@ static int line() {
|
||||
char c;
|
||||
char seq[3];
|
||||
|
||||
if (read(STDIN_FILENO, &c, 1) <= 0) return -1;
|
||||
int rc;
|
||||
do {
|
||||
rc = read(STDIN_FILENO, &c, 1);
|
||||
} while (rc < 0 && errno == EINTR);
|
||||
if (rc <= 0) return -1;
|
||||
|
||||
switch (c) {
|
||||
default:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -39,6 +39,25 @@
|
||||
(def c (u64 "32rvv_vv_vv_vv"))
|
||||
(def d (u64 "123456789"))))
|
||||
|
||||
# Conversion back to an int32
|
||||
(assert (= (int/to-number (u64 0xFaFa)) 0xFaFa))
|
||||
(assert (= (int/to-number (i64 0xFaFa)) 0xFaFa))
|
||||
(assert (= (int/to-number (u64 9007199254740991)) 9007199254740991))
|
||||
(assert (= (int/to-number (i64 9007199254740991)) 9007199254740991))
|
||||
(assert (= (int/to-number (i64 -9007199254740991)) -9007199254740991))
|
||||
|
||||
(assert-error
|
||||
"u64 out of bounds for safe integer"
|
||||
(int/to-number (u64 "9007199254740993"))
|
||||
|
||||
(assert-error
|
||||
"s64 out of bounds for safe integer"
|
||||
(int/to-number (i64 "-9007199254740993"))))
|
||||
|
||||
(assert-error
|
||||
"int/to-number fails on non-abstract types"
|
||||
(int/to-number 1))
|
||||
|
||||
(assert-no-error
|
||||
"create some int64 bigints"
|
||||
(do
|
||||
@@ -72,6 +91,39 @@
|
||||
"trap INT64_MIN / -1"
|
||||
(:/ (int/s64 "-0x8000_0000_0000_0000") -1))
|
||||
|
||||
# int/s64 and int/u64 serialization
|
||||
(assert (deep= (int/to-bytes (u64 0)) @"\x00\x00\x00\x00\x00\x00\x00\x00"))
|
||||
|
||||
(assert (deep= (int/to-bytes (i64 1) :le) @"\x01\x00\x00\x00\x00\x00\x00\x00"))
|
||||
(assert (deep= (int/to-bytes (i64 1) :be) @"\x00\x00\x00\x00\x00\x00\x00\x01"))
|
||||
(assert (deep= (int/to-bytes (i64 -1)) @"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"))
|
||||
(assert (deep= (int/to-bytes (i64 -5) :be) @"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFB"))
|
||||
|
||||
(assert (deep= (int/to-bytes (u64 1) :le) @"\x01\x00\x00\x00\x00\x00\x00\x00"))
|
||||
(assert (deep= (int/to-bytes (u64 1) :be) @"\x00\x00\x00\x00\x00\x00\x00\x01"))
|
||||
(assert (deep= (int/to-bytes (u64 300) :be) @"\x00\x00\x00\x00\x00\x00\x01\x2C"))
|
||||
|
||||
# int/s64 int/u64 to existing buffer
|
||||
(let [buf1 @""
|
||||
buf2 @"abcd"]
|
||||
(assert (deep= (int/to-bytes (i64 1) :le buf1) @"\x01\x00\x00\x00\x00\x00\x00\x00"))
|
||||
(assert (deep= buf1 @"\x01\x00\x00\x00\x00\x00\x00\x00"))
|
||||
(assert (deep= (int/to-bytes (u64 300) :be buf2) @"abcd\x00\x00\x00\x00\x00\x00\x01\x2C")))
|
||||
|
||||
# int/s64 and int/u64 paramater type checking
|
||||
(assert-error
|
||||
"bad value passed to int/to-bytes"
|
||||
(int/to-bytes 1))
|
||||
|
||||
(assert-error
|
||||
"invalid endianness passed to int/to-bytes"
|
||||
(int/to-bytes (u64 0) :little))
|
||||
|
||||
(assert-error
|
||||
"invalid buffer passed to int/to-bytes"
|
||||
(int/to-bytes (u64 0) :little :buffer))
|
||||
|
||||
|
||||
# Dynamic bindings
|
||||
(setdyn :a 10)
|
||||
(assert (= 40 (with-dyns [:a 25 :b 15] (+ (dyn :a) (dyn :b)))) "dyn usage 1")
|
||||
|
||||
@@ -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,34 @@
|
||||
(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)"))
|
||||
|
||||
# 919
|
||||
(defn test
|
||||
[]
|
||||
(var x 1)
|
||||
(set x ~(,x ()))
|
||||
x)
|
||||
|
||||
(assert (= (test) '(1 ())) "issue #919")
|
||||
|
||||
(assert (= (hash 0) (hash (* -1 0))) "hash -0 same as hash 0")
|
||||
|
||||
(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