1
0
mirror of https://github.com/janet-lang/janet synced 2025-10-28 14:17:42 +00:00

Compare commits

...

1685 Commits

Author SHA1 Message Date
Calvin Rose
2bf5e341d3 Update for 1.12.1 2020-09-07 16:10:33 -05:00
Calvin Rose
b53890ddae Make some changes for WASM build. 2020-09-07 16:08:43 -05:00
Calvin Rose
93602ad9ea Prepare 1.12.0 Release. 2020-09-07 15:28:46 -05:00
Calvin Rose
ff57b3eb72 Make zero?, one?, neg? and pos? polymorphic. 2020-09-06 19:05:58 -05:00
Calvin Rose
1837e89fe4 Address #470 - hyphen's in native module names. 2020-09-06 15:23:24 -05:00
Calvin Rose
24b8b0e382 Fix NaNboxing bug that cause flaky builds.
The macro janet_checktype(x, JANET_NUMBER) was incorrect when
x was NaN. This caused the initial unmarshalling dictionary to be missing
entries in certain cases.
2020-09-06 14:59:29 -05:00
Calvin Rose
321a758ab9 Change hash implementation for pointers. 2020-09-06 11:41:45 -05:00
Calvin Rose
1a9c14acde Add checksum to build/janet.c to check for inconsistent builds. 2020-09-06 11:04:07 -05:00
Calvin Rose
e8734c77b4 Fix bug by casting to unsigned char.
Higher unciode codepoints where being read as negative char values.
We need to cast to unsigned char before comparing to 0x20 to check
for unprintable characters.
2020-09-06 10:47:05 -05:00
Calvin Rose
1eb00a9f74 Remove restriction on bytes being input to getline. 2020-09-06 10:36:38 -05:00
Calvin Rose
922a21d359 Run make format. 2020-09-05 21:26:21 -05:00
Calvin Rose
4a4f314768 Update changelog. 2020-09-05 20:23:55 -05:00
Calvin Rose
3c64596ea1 Add %t formatter to janet.
Was not present in printf and family.
2020-09-05 20:21:49 -05:00
Calvin Rose
33283b1b6e Change linking process for standalone executables.
We separate compilation and linking so that mixed C/C++ binaries
will work.
2020-09-05 10:19:34 -05:00
Calvin Rose
2f89bdc672 Conditional compilation on some c99 syntax in header.
If the header is in a C++11 compilation unit, use C++11
aggregate initialization syntax instead.
2020-09-05 09:45:34 -05:00
Calvin Rose
2d275c4782 Enable exception handling for C++ with MSVC. 2020-09-04 21:43:34 -05:00
Calvin Rose
25156eb83e For #469 - Add support for C++ and mixed C/C++
WIP and for native modules. Required a few changes to headers and
some changes to JPM.
2020-09-04 17:41:36 -05:00
Calvin Rose
39032b45c9 Remove extra file. 2020-09-04 14:55:47 -05:00
Calvin Rose
821a8dca3b Fix os/spawn - os/execute switch. 2020-09-04 14:54:58 -05:00
Calvin Rose
0145b133a1 Add os/spawn instead of os/execute with :a 2020-09-04 08:09:05 -05:00
Calvin Rose
b0b137d7f0 Apply formatting to windows changes. 2020-09-02 19:12:27 -05:00
Calvin Rose
b0c09153c2 Allow IO redirection on windows. 2020-09-02 19:07:45 -05:00
Calvin Rose
0485078c6c Fix some issues on BSD and Windows. 2020-09-01 21:47:08 -05:00
Calvin Rose
7079cc43c9 Make some improvements and add os/proc-kill as well. 2020-09-01 21:36:49 -05:00
Calvin Rose
e7fca0051e Add :a option to os/execute, and allow redirecting stdio.
This should help cover a number of common cases for
use of subprocesses. This should also eventually work well
with the ev branch via
2020-09-01 20:06:35 -05:00
Calvin Rose
6273e56886 Add janet_getjfile to C API. 2020-08-29 17:36:14 -05:00
Calvin Rose
8b9ad2dce8 Add :x flag to os/execute. 2020-08-29 10:27:32 -05:00
Calvin Rose
301cbb0e68 Update changelog 2020-08-29 09:22:10 -05:00
Calvin Rose
5313963baf Don't run main when flychecking. 2020-08-29 09:05:18 -05:00
Calvin Rose
f60348eee4 Merge branch 'master' of github.com:janet-lang/janet into master 2020-08-27 08:20:31 -05:00
Calvin Rose
a31e079f93 Fix import macro to not coerce everything to string. 2020-08-27 08:19:41 -05:00
Calvin Rose
556edc9f0d Fix import macro to not coerce everything to string. 2020-08-27 07:46:51 -05:00
Calvin Rose
5dda83dc73 Add second argument to disasm. 2020-08-22 16:18:10 -05:00
Calvin Rose
28439d822a Add cancel function.
This should allow better stack unwinding on a fiber that
no longer needs to complete.
2020-08-22 15:35:37 -05:00
Calvin Rose
b1d8ee19ca Enable mutliline paste in shell.c with TCSADRAIN.
Replaces TCSAFLUSH.
2020-08-22 11:39:57 -05:00
Calvin Rose
f7c556ed8d Add curenv to core. 2020-08-22 10:16:14 -05:00
Calvin Rose
5377e10532 Address #466?
Do not restore pc when returning from top most fiber frame.

Also add JANET_DEBUG config define for various debugging related
configurations. In fiber.c, when debug is enabled we reallocate the
entire stack everytime we push a frame to help uncover use after free
errors.
2020-08-17 07:01:58 -05:00
Calvin Rose
58374623b7 Add a vm_commit before JOP_NEXT. 2020-08-13 22:28:50 -05:00
Calvin Rose
7e7498350f Fix #463
Fix outdated code in macex1, such as checking for unquote-splicing,
    which no longer exists. Also fix macex1 for quasiquoted tables and
    structs. macex1 is not the macro expander used by the compiler, so
    these bugs only affected code which called macex manually, such as
    the short-fn macro.
2020-08-12 06:10:42 -05:00
Calvin Rose
06c268c274 Start working on throwing errors from async functions. 2020-08-11 08:33:24 -05:00
Calvin Rose
9b36e2b145 Be aggressive with setting SO_NOSIGPIPE on BSD/Apple. 2020-08-10 18:59:53 -05:00
Calvin Rose
ca75f8dc20 Address #463 - prevent sigpipe on client connections.
We erroneously did not set SO_NOSIGPIPE on connections aquired with
net/connect, only those quired thorugh net/server. This meant that
failed writes by a client could send sigpipe.
2020-08-10 18:45:44 -05:00
Calvin Rose
6f2f3fdb68 Return an error message if writes fail. Address #462. 2020-08-10 11:06:31 -05:00
Calvin Rose
c903e49a4f Change feature flags for BSD. 2020-08-10 10:42:56 -05:00
Calvin Rose
9121feb44f Update changelog.` 2020-08-09 11:39:40 -05:00
Calvin Rose
7b42ed66f2 Add xprint, xprin, xprintf, and xprinf. 2020-08-09 09:30:58 -05:00
Calvin Rose
c3af30d520 Fix broken links in README.md 2020-08-07 19:48:06 -05:00
Calvin Rose
2598123140 Rename test suites such that it is easier to add more of them. 2020-08-07 15:34:13 -05:00
Calvin Rose
40627191f3 Merge pull request #460 from andrewchambers/fix
Add missing JANET_API to janet_cryptorand.
2020-08-07 11:46:44 -05:00
Andrew Chambers
38dc844e85 Add missing JANET_API to janet_cryptorand. 2020-08-07 14:02:26 +12:00
Calvin Rose
abc4405a76 Address #459 - Update meson.build
Don't search for cross compilerUnless needed.
This should help prevent issues building Meson on debian. Also
fix issue using the wrong set of flags to build the native janet
interpreter vs. the cross compiled janet interpreter.
2020-08-06 20:45:18 -05:00
Calvin Rose
243c66442d Add PRF enabled build to sourcehut builds. 2020-08-04 10:30:54 -05:00
Calvin Rose
9afcec77f6 Disable PRF by default. 2020-08-03 21:52:57 -05:00
Calvin Rose
70ad98cc6f Fix arc4random_buf implementation. 2020-08-03 21:49:49 -05:00
Calvin Rose
76cfbde933 Add JANET_HASHSEED environment variable. 2020-08-03 20:56:11 -05:00
Calvin Rose
f200bd9594 Merge pull request #455 from andrewchambers/prfseed
Initialize PRF with random data when it is enabled.
2020-08-03 20:14:51 -05:00
Andrew Chambers
4d4ca7bb36 Initialize PRF with random data when it is enabled. 2020-08-04 12:13:36 +12:00
Calvin Rose
78c3c6dafa Merge branch 'master' of github.com:janet-lang/janet into master 2020-08-03 17:44:37 -05:00
Calvin Rose
6d859dec67 Exit with error code if jpm install fails. 2020-08-03 17:41:16 -05:00
Calvin Rose
3563e7e1aa Add -fPIC to default cflags when building boot image. 2020-08-03 17:32:41 -05:00
Calvin Rose
8c1eb23aa1 Add -fPIC to default cflags when building boot image. 2020-08-02 13:52:21 -05:00
Calvin Rose
b564087db0 Add index-of to core library. 2020-08-02 13:47:56 -05:00
Calvin Rose
1748e8510e Fix typo in docstring. 2020-08-02 13:27:49 -05:00
Calvin Rose
fb31c3b46d Merge pull request #454 from soapdog/fix-windows-on-arm64
Make sure JANET_NO_NANBOX is defined for ARM targets
2020-07-29 13:13:47 -05:00
Andre Alves Garzia
ba2beffcd8 Make sure JANET_NO_NANBOX is defined for ARM targets 2020-07-28 16:51:19 +01:00
Calvin Rose
0601d851d0 Merge pull request #453 from niacat/master
Fix build on NetBSD.
2020-07-26 22:15:46 -05:00
nia
b731f6ab03 Fix build on NetBSD.
The NetBSD C library's headers do not expose extensions when
compiling with -std=c99 (as opposed to -std=gnu99 or no -std=
option), so define _NETBSD_SOURCE to get timegm, and functions
that would otherwise require an _XOPEN_SOURCE definition, e.g.
realpath.

Note that, as with FreeBSD, you need gmake to compile janet
on NetBSD, and can also install it from packages.
2020-07-27 00:21:15 +01:00
Calvin Rose
4cc680965c Prepare for 1.11.1 release. 2020-07-25 13:48:43 -05:00
Calvin Rose
ba08e487cb Disable PRF by default.
Since it is not any better by default without initializing the key, we
disable it by default. It can be turned on with JANET_PRF in
janetconf.h.
2020-07-25 13:34:40 -05:00
Calvin Rose
d37eda4e9b Don't use x43bot to test install. 2020-07-25 13:23:57 -05:00
Calvin Rose
5be5e5b58f Update soname. 2020-07-25 13:11:52 -05:00
Calvin Rose
04ac9b8e32 Update README.md 2020-07-25 10:14:59 -05:00
Calvin Rose
409a8a3a43 Fix #452 - Bad file marshal
We forgot a call to janet_marshal_abstract, which corrupted the output.
2020-07-25 08:09:22 -05:00
Calvin Rose
1ba3f72e4c Update meson build. 2020-07-24 13:03:10 -05:00
Calvin Rose
3e5e9e57e9 Fix sourcehut builds yml file. 2020-07-24 12:29:31 -05:00
Calvin Rose
02e5e49de2 Fix buffer overflow. 2020-07-24 07:04:32 -05:00
Calvin Rose
43438d3824 Allow getting typed arrays from byte sequences.
Fix native importing for .so files in current directory.
2020-07-24 07:01:34 -05:00
Calvin Rose
8f82d19fd1 Merge branch 'master' of github.com:janet-lang/janet 2020-07-21 13:40:58 -05:00
Calvin Rose
ee450bcd77 Fix jpm on windows with multiple git binaries. 2020-07-21 13:40:23 -05:00
Calvin Rose
fa55283f62 Release 1.11.0 2020-07-18 16:21:01 -05:00
Calvin Rose
9e163db491 Test building binaries with jpm.
Test in CI with both meson and normal build.
Also test windows.
2020-07-18 15:50:58 -05:00
Calvin Rose
286230f477 Fix meson paths. 2020-07-18 15:44:04 -05:00
Calvin Rose
3ba2c7e7e8 Address #394 and #451 - Prepare for 1.11.0
Prefix MANPATH and PKG_CONFIG_PATH variables
with JANET_ to disassociate with standard env variables
that have a different format.
2020-07-18 13:09:53 -05:00
Calvin Rose
b4f5e5bc00 Update docs for -l option. 2020-07-06 21:25:41 -05:00
Calvin Rose
f580d2e41a Add forever macro and add names to anon fns.
Adding names to anon functions that may error improves
stack traces, especially for user visible traces.
2020-07-06 19:26:37 -05:00
Calvin Rose
a1feb32a2f Update CHANGELOG.md 2020-07-06 17:21:55 -05:00
Calvin Rose
7478ad115f Add any? predicate to core.
This is the contrapositive to `every?`, and is analagous to `or` as
`every?` is to `and`.
2020-07-06 09:19:10 -05:00
Calvin Rose
9d8e338a11 Update default repl prompt to match errors. 2020-07-05 23:32:59 -05:00
Calvin Rose
ed4163cfde Replace copyright on boot with system information. 2020-07-05 23:24:07 -05:00
Calvin Rose
463e6d9316 Merge pull request #448 from GrayJack/fix-table-remove
Fix janet_table_remove returning the key instead of the value
2020-07-05 18:36:54 -05:00
Calvin Rose
3358811788 Update changelog and sort listing. 2020-07-05 17:51:49 -05:00
Calvin Rose
a45509d28e Add list-pkgs and list-installed to jpm. 2020-07-05 17:43:39 -05:00
Calvin Rose
68a12d1d17 Minor fixes for meson minimum build.
Also, fix regression that looses function name information.
2020-07-03 20:41:55 -05:00
Calvin Rose
c97d3cf359 Fix minimum meson build. 2020-07-03 20:30:09 -05:00
Calvin Rose
4721337c7c issues with gettime on mach kernel. 2020-07-03 20:19:36 -05:00
Calvin Rose
2b36ed967c Address some windows issues. 2020-07-03 20:13:49 -05:00
Calvin Rose
3bb8f1ac8d Don't use CLOCK_MONOTONIC for pthread stuff.
Also fix marshalling functions without full
sourcemapping information, as well as thread/receive
ignoring bad messages. Instead, thread/receive will error
on bad messages.
2020-07-03 19:54:58 -05:00
Calvin Rose
617ec7f565 Threading improvements.
- Add thread/exit to kill the current thread.
- Add global lock aroung custom getline and add atexit handler
- to prevent any possible issues when exiting program.
- Allow sending stderr, stdout, and stdin over thread.
2020-07-03 16:28:07 -05:00
Calvin Rose
dc259b9f8e Set fiber env for heavyweight threads.
Since you already incur the cost of creating the
core environment, this is probably what you want anyways.
This will make eval and other reflective code work as expected.
2020-07-03 15:20:19 -05:00
Calvin Rose
7b31a87b3c Update integer limits and printing. 2020-07-03 14:14:59 -05:00
Calvin Rose
6ea530cc48 Address compilation warnings and errors. 2020-07-03 12:25:24 -05:00
Calvin Rose
55cf9f5e1c Don't break reverse backwards compat.
Breaking backwards compatibiliy here is not worth it.
Also update changelog.
2020-07-03 10:17:50 -05:00
Calvin Rose
b89f0fac7b Move clock shims to util (Helps #430).
The thread module should also use these clock shims rather
than clock_gettime, which is not available on older mac systems.
2020-07-03 09:54:58 -05:00
GrayJack
8b3b3182bd Add tests to check janet_table_remove behaviour 2020-07-02 11:03:08 -03:00
Calvin Rose
97c64f27ff Remove duplicate code in loop macro.
Also evaluate for loop and range step exactly once.
Multiple evaluations can be inefficent and make infinite loop
detection impossible.
2020-07-01 22:37:04 -05:00
Calvin Rose
e548e1f6e0 Add peg/replace and peg/replace-all 2020-07-01 21:29:24 -05:00
GrayJack
7ea1c7d85a Fix janet_table_remove returning the key instead of the value 2020-07-01 20:05:07 -03:00
Calvin Rose
e08235b575 Merge pull request #436 from cellularmitosis/no_arc4random_buf
Add support for systems which are missing arc4random_buf
2020-07-01 15:54:15 -05:00
Calvin Rose
783c672130 Merge pull request #437 from pepe/add-peg-find-tests
Add tests for peg/find and peg/find-all
2020-07-01 15:48:43 -05:00
Calvin Rose
5351a6b2ed Merge pull request #447 from cellularmitosis/nan
math/nan
2020-07-01 15:47:13 -05:00
Jason Pepas
a110b103e8 math/nan 2020-07-01 15:35:36 -05:00
Josef Pospíšil
c26f573620 Add tests for peg/find and peg/find-all 2020-06-30 17:03:13 +02:00
Jason Pepas
f06e9ae30c Switch to using /dev/urandom for OS X prior to 10.7 2020-06-30 04:18:08 -05:00
Jason Pepas
f5d208d5d6 eliminate large stack allocation from arc4random_buf bodge 2020-06-30 04:06:20 -05:00
Calvin Rose
7fb8c4a68d Merge branch 'master' of github.com:janet-lang/janet 2020-06-29 22:57:46 -05:00
Calvin Rose
647fc56d47 Replace for with forv in most places in boot.janet
Generates slightly better bytecode with current compiler
(gets rid of a single extra move instruction per loop iteration).
2020-06-29 22:56:16 -05:00
Jason Pepas
597d84e263 Add support for systems missing arc4random_buf 2020-06-29 21:06:13 -05:00
Calvin Rose
977b0c3c0c Merge pull request #429 from pepe/fix-reverse-doc
Tune reverse[d] docstrings
2020-06-29 20:55:04 -05:00
Calvin Rose
1b0d6de735 Merge pull request #432 from cellularmitosis/no_cloexec
Support for systems missing O_CLOEXEC
2020-06-29 20:54:41 -05:00
Calvin Rose
2f5bb7774e Fix recursive post-deps. 2020-06-29 20:51:38 -05:00
Jason Pepas
5565f02dbd Simplifying workaround for missing O_CLOEXEC 2020-06-29 19:36:18 -05:00
Calvin Rose
17a131ac21 Add peg/find and peg/find-all.
These peg functions should make pegs a bit easier to use
and more efficient in some common cases.
2020-06-29 19:13:06 -05:00
Calvin Rose
9a5cfe9f75 Merge branch 'master' of github.com:janet-lang/janet 2020-06-29 13:47:02 -05:00
Calvin Rose
cc936d9977 Merge pull request #435 from pepe/add-keyword-symbol-slice-tests
Add keyword/slice and symbol/slice tests
2020-06-29 09:11:35 -05:00
Josef Pospíšil
e9911fee4d Add keyword/slice and symbol/slice tests 2020-06-29 09:18:26 +02:00
Calvin Rose
aefde67aa2 And lots of optimization functionality. 2020-06-28 18:16:57 -05:00
Calvin Rose
a1ea62a923 Fix optimization of do_get.
When the target slot (register) is the same as the default
register, do not clobber it.
2020-06-28 15:52:59 -05:00
Calvin Rose
7209ced446 Merge branch 'master' of github.com:janet-lang/janet 2020-06-28 15:09:01 -05:00
Calvin Rose
db63d352a2 Add specialization for 3 argument get.
This can be inlined with jmpnn instruction (jump if not nil) to
skip over the default value.

(get a b c)

can be exanded statically to

asm start:
    (get $0 $1 $2)
    (jmpnn $0 :label)
    ... Instructions to load default value to $0 - often a load.
    :label
asm end.
2020-06-28 15:03:01 -05:00
Josef Pospíšil
289de840fd Specify input types actions 2020-06-28 20:49:44 +02:00
Calvin Rose
cb34a8b620 Merge pull request #434 from elimisteve/master
Add .gitattributes: syntax highlight .janet files as Clojure
2020-06-27 17:01:45 -05:00
Calvin Rose
95c633914f Add auto-resizing of gc interval.
This should prevent over use of GC and O(n^2)
behavior.
2020-06-27 16:51:20 -05:00
Calvin Rose
d033412b1f Add symbol/slice and keyword/slice 2020-06-27 15:22:15 -05:00
Calvin Rose
9c5e97144d More small changes to help with cross compilation
via makefile. Add option to turn off built in
getline via janetconf.
2020-06-27 12:39:16 -05:00
Calvin Rose
8b96289e2f Merge branch 'master' of github.com:janet-lang/janet 2020-06-27 11:24:03 -05:00
Calvin Rose
51ff43e2f2 Update range checks for 64 bit integers. 2020-06-27 11:23:47 -05:00
Calvin Rose
1e30f4f973 Merge pull request #427 from pyrmont/nil-empty-string
Change default string representation of nil to empty string
2020-06-26 22:47:16 -05:00
Calvin Rose
36f66661f7 Merge pull request #431 from cellularmitosis/master
Add ppc to os/arch
2020-06-26 22:43:41 -05:00
Steve Phillips
de27fc15b6 Add .gitattributes: detect/syntax highlight .janet files as Clojure 2020-06-26 20:31:42 -07:00
Jason Pepas
f9f90ba1d6 Support for systems missing O_CLOEXEC 2020-06-26 14:44:57 -05:00
Jason Pepas
51bf8a3538 Add ppc to os/arch 2020-06-26 04:11:21 -05:00
Josef Pospíšil
7b033a48a3 Wrap both reverse and reversed docstring to 80 chr 2020-06-25 09:43:10 +02:00
Josef Pospíšil
1b420f69aa Fix reverse docstring 2020-06-25 09:35:03 +02:00
Calvin Rose
6a187a384b Make zipcoll more generic.
Work with any iterable (next) type.
2020-06-24 16:10:57 -05:00
Calvin Rose
ac5de1f96e Change compare-primitive to cmp.
cmp is implemented as a VM instruction rather than
a function.
2020-06-24 16:00:00 -05:00
Calvin Rose
6c917f686a Add :h default peg class, as well as ad \v to whitespace. 2020-06-24 08:40:23 -05:00
Calvin Rose
de9951594e Allow setting dynamic bindings at C top level.
Before, these bindings we just ignored. However, it useful for
controlling janet_printf and janet_eprintf, for example. These can
be called from C code without being inside a call to janet_continue.
2020-06-22 08:56:04 -05:00
Calvin Rose
561fc15ae9 Address #426 parse errors in *out janet_dostring
This should make its use a little more robust for
simple usage. To avoid printing to stderr, use

janet_table_put(env, janet_ckeywordv("err"), janet_wrap_false());
2020-06-22 08:34:17 -05:00
Calvin Rose
d65814c53f Update changelog.md 2020-06-21 18:52:10 -05:00
Calvin Rose
803f17aa90 Add eachy and repeat to make looping easier.
Like eachk and eachp, use eachy and repeat to bring loop
verbs outside of the loop macro. These new macros are very simple
and easy to understand, in contrast to the loop macro which is of
medium complexity.
2020-06-21 18:48:06 -05:00
Calvin Rose
08a3687eb5 Fix #428
Add binding check for generate verb in loops. The check is present
in other loop verbs.
2020-06-21 15:57:55 -05:00
Michael Camilleri
c4035b2273 Change string representation of nil to empty string 2020-06-21 17:54:06 +09:00
Calvin Rose
5c364e0f7c Better roundtrip jdn.
Use the most precise format specifier, such that output jdn numbers
are more accurate.
2020-06-18 21:54:34 -05:00
Calvin Rose
9cfc3d9d37 Update to 1.10.1 2020-06-18 19:24:17 -05:00
Calvin Rose
b5fdd30b77 Fix meson build version. 2020-06-18 18:43:10 -05:00
Calvin Rose
280292d3f5 Update CHANGELOG.md 2020-06-18 18:41:09 -05:00
Calvin Rose
c593d864be Merge branch 'master' of github.com:janet-lang/janet 2020-06-18 18:38:17 -05:00
Calvin Rose
6d17348c72 Merge pull request #425 from pyrmont/bugfix.make-install-paths-fn
Make install-paths a function
2020-06-18 15:13:36 -05:00
Michael Camilleri
536648ec19 Use function for install-paths 2020-06-18 19:07:43 +09:00
Calvin Rose
b5e32a9ce5 Expose janet_table_clear. 2020-06-15 15:33:41 -05:00
Calvin Rose
4077822e37 Update changelog. 2020-06-15 11:54:51 -05:00
Calvin Rose
e2d8750625 Update jpm.
Silence git warnings on git pull, and fix issue with double
dependencies in rules.
2020-06-15 11:22:32 -05:00
Calvin Rose
79f5751375 Add array/trim and buffer/trim. 2020-06-14 17:40:48 -05:00
Calvin Rose
106437bd45 Fixes #423
Re-add ifdef for realpath config option.
2020-06-14 15:50:09 -05:00
Calvin Rose
b7cd13bb0b Fix changelog typo. 2020-06-14 15:10:54 -05:00
Calvin Rose
be1ec1b973 Conditionally install jpm in meson. 2020-06-14 14:27:22 -05:00
Calvin Rose
1bddb87a0c Fix MSVC Warnings. 2020-06-14 14:20:38 -05:00
Calvin Rose
fbe23d8c33 Prepare for 1.10.0 release. 2020-06-14 14:16:01 -05:00
Calvin Rose
f435bb24ab Remove extra function on some installs. 2020-06-14 14:09:32 -05:00
Calvin Rose
853b33b67c On nix platforms, patch jpm with path information.
This means we no longer need to guess paths after install.
Custom directory layouts can now be better supported at install
time without need for environment variables.
2020-06-14 14:04:23 -05:00
Calvin Rose
19f3568e18 Update for 1.10.0. 2020-06-14 12:15:56 -05:00
Calvin Rose
911c2cbe58 Update CHANGELOG.md 2020-06-14 12:12:41 -05:00
Calvin Rose
17bdfbb08b Fix broken trace functionality.
This was an older regression that caused trace to emit
garbage output in most cases.
2020-06-14 11:58:20 -05:00
Calvin Rose
80f29ae859 Add some more bindings for jpm for future proofing. 2020-06-14 11:43:26 -05:00
Calvin Rose
0b114d680e Update CHANGELOG.md. 2020-06-13 14:10:35 -05:00
Calvin Rose
c87a0910d0 Add some flags to creating threads for more control.
Allow lightweight/heavyweight threads, and make default lightweight.
This means multithreaded programs can save lots of memory by default.
2020-06-13 09:42:16 -05:00
Calvin Rose
86e12369b6 Add alias for PEG repeat.
A tuple where the first element is an integer is
a shortand for this.
2020-06-11 11:23:43 -05:00
Calvin Rose
6d096551f0 Add Peg combinators 'to' and 'thru'.
Inpsired by the REBOL operators of the same name, these
combinators match bytes up to or inculding a given pattern.
(to patt) is (almost) equalivalent to (any (if-not patt 1)), and
(thru patt) is equivalent to (* (to patt) patt). The one difference
is that if the end of the input is reached and patt is not
matched, the entire pattern does not match.
2020-06-10 21:18:50 -05:00
Calvin Rose
2595c8a853 Properly hide private functions in boot.janet 2020-06-10 00:02:07 -05:00
Calvin Rose
2a9923999b Merge pull request #422 from MikeBeller/compare
Implement polymorphic compare
2020-06-10 00:58:33 -04:00
Calvin Rose
03cbeac1ea Remove snapcraft.yaml.
Removing explicit snapcraft support from janet. Getting things working
with snapcraft is not something I have had luck with, and snapcraft.io
has been spamming me with emails. Since this is not completely zero
overhead, I am simply removing support for snapcraft.
2020-06-06 11:35:43 -05:00
Mike Beller
9824a34d76 Remove dead code. 2020-06-06 08:55:20 -04:00
Mike Beller
76c3436377 Remove vestigial comparison methods from int types 2020-06-05 11:07:48 -04:00
Mike Beller
a4178d4b3c All tests pass for compare. 2020-06-05 10:51:35 -04:00
Mike Beller
3e423722c6 Actually got the comparisons working for s64 (still need to fix u64) 2020-06-04 18:27:48 -04:00
Mike Beller
01837f2bb6 All tests pass. 2020-06-04 15:27:36 -04:00
Mike Beller
411c5da6d3 compare functions now work for built ins and 'objects' 2020-06-04 13:49:09 -04:00
Mike Beller
7658ea8335 primitive tests working. issues remain with polymorphic. 2020-06-04 12:46:58 -04:00
Mike Beller
81d301a42b Initial commit of base functionality for compare 2020-06-04 12:23:54 -04:00
MikeBeller
0b500730e0 Merge pull request #1 from janet-lang/master
Bringing fork up to date
2020-06-04 10:35:03 -04:00
Calvin Rose
6c08dbab0e Merge pull request #420 from leafgarland/master
Implement os/realpath with _fullpath
2020-06-02 20:57:28 -04:00
Leaf
bed02c2f95 Remove unused flags 2020-06-02 09:14:31 +00:00
Leaf
75bc69ba2f Implement os/realpath on Window with _fullpath
This is similar to realpath but differs in that realpath will complain
if the path does not exist. We could add our own exists check if we
really wanted to match that behaviour.
2020-06-02 09:05:41 +00:00
Calvin Rose
eb9f74a273 Silence MSVC warning. 2020-05-30 10:06:39 -04:00
Calvin Rose
4056b94e01 Merge pull request #418 from ahungry/bugfix/Fix-double-free-fclose
Fix for double free on fclose due to GC not knowing it failed
2020-05-28 17:24:09 -04:00
Matthew Carter
ee94828355 Fix for double free on fclose due to GC not knowing it failed 2020-05-28 15:35:09 -04:00
Calvin Rose
fff66649aa Fix issue #416.
Be really sure we don't pass too large of a size to memcpy.
There seem to be some situations where the slotcount and the ua.count
do not match at all, so use the mimimum for copying.
2020-05-28 10:47:22 -05:00
Calvin Rose
b33fdc1674 Merge pull request #415 from leafgarland/fix_numarray_example
Fix numarray example to work with jpm and latest Janet c-api
2020-05-25 14:04:58 -04:00
Leaf Garland
6909d9c9c9 Fix c code for latest Janet 2020-05-24 21:30:23 +12:00
Leaf Garland
0d5d820f4f Remove cook code 2020-05-24 21:29:20 +12:00
Leaf Garland
6fbca3416a Move tests to tests dir 2020-05-24 21:28:16 +12:00
Leaf Garland
466d9b31ce Add project.janet for numarray 2020-05-24 21:25:52 +12:00
Calvin Rose
b6fdaaac41 Merge pull request #414 from roobie/update-readme
adds WiX details to README
2020-05-23 12:08:35 -04:00
Calvin Rose
c19bbfce78 Make style consistent. 2020-05-23 11:07:57 -05:00
Calvin Rose
e9fdbe0c89 Merge pull request #411 from LouisJackman/make-ctrl-c-interrupt-current-form
Make Ctrl-C Cancel the Current Form; Only Exit if Column 0 Outside of Form
2020-05-23 11:33:19 -04:00
bjorn roberg
f2299eab8f rephrase the info about WiX and .msi 2020-05-23 14:15:19 +02:00
LouisJackman
e220f44953 Simplify and don't replace history for cancelled forms 2020-05-23 08:36:40 +01:00
bjorn roberg
b750a84ab1 adds WiX details to README 2020-05-22 23:53:31 +02:00
Calvin Rose
41f8be2c53 Fix flycheck when using the use macro.
Flycheck originally expected `use` to have
the same arguments as `import`, but this is not the case.
2020-05-21 18:51:17 -05:00
LouisJackman
c3e4cbe950 Address compilation warning about modifier order 2020-05-21 18:51:25 +01:00
LouisJackman
50df5000c2 Update older run-context code 2020-05-21 18:47:47 +01:00
LouisJackman
3c8930b72b Get tests passing again by returning keyword rather than nil from chunks 2020-05-21 18:37:15 +01:00
LouisJackman
f0572c4d5f Remove REPL-within-form thread-local bool 2020-05-21 18:31:21 +01:00
Calvin Rose
057ba8a4e1 Fixes #409
Use the correct count in a memcpy.
2020-05-21 01:35:37 -05:00
Calvin Rose
677737d345 Fixes #412 Lookahead does not move cursor. 2020-05-21 01:22:08 -05:00
Calvin Rose
930ac9c57d Merge branch 'master' of https://github.com/janet-lang/janet 2020-05-21 00:18:45 -04:00
Calvin Rose
5caa0371c4 Replace forward slash in xcopy commands.
xcopy doesn't handle them in paths.
2020-05-21 00:18:07 -04:00
Calvin Rose
e6e1cb1b43 Merge pull request #410 from MikeBeller/tarray-next
Fix issue #408 -- make "next" work for typed arrays, and also fix
2020-05-20 19:00:06 -04:00
LouisJackman
164ed0b325 Get expected behaviour; cleanup after confirming behaviour is desired 2020-05-20 22:40:05 +01:00
Mike Beller
8263789602 Fix issue #408 -- make "next" work for typed arrays, and also fix
bug where tarray/new failed to fully check the type of it's last
argument.
2020-05-20 13:30:48 -04:00
Calvin Rose
a99906c6f0 Remove NSIS artifacts.
NSIS installer has been replaced by WiX installer.
2020-05-19 22:25:04 -05:00
Calvin Rose
617338457d More windows shenanigans with jpm.
Cannot remove open file, get rid of double rm.
2020-05-19 20:03:49 -04:00
Calvin Rose
1026d2173b Quick fix. 2020-05-19 19:21:30 -04:00
Calvin Rose
ca9c9ee807 Add the clear-manifest command. 2020-05-19 19:20:09 -04:00
Calvin Rose
bef51fe9ff Fix jpm. 2020-05-19 18:41:17 -04:00
Calvin Rose
b72845609f Add JANET_GIT to jpm.
This should allow work arounds for some windows installs.
Also, be clever about finding the location of te current git
executable on windows to avoid some path issues that seem to
occur on some windows installations.
2020-05-19 18:36:58 -04:00
Calvin Rose
ccd8b71c4b Fix os/shell usage in jpm on windows. 2020-05-19 16:28:43 -05:00
Calvin Rose
e623690295 Use keywords in the assembly interface.
This is simply more idiomatic, removes some unused and undocumented
features of the assembly interface, and simplifies it somewhat.
2020-05-19 13:51:39 -05:00
Calvin Rose
070baea3c4 Merge branch 'master' of github.com:janet-lang/janet 2020-05-19 09:47:11 -05:00
Calvin Rose
0e828792ae Fix segfault on bad loop. Fixes #407. 2020-05-19 09:45:45 -05:00
Calvin Rose
31a8dfa063 Merge pull request #406 from leafgarland/master
Add Wix/msi installer for Windows
2020-05-19 06:49:41 -04:00
Leaf Garland
338ef8f2e4 Update Appveyor to build Wix installer 2020-05-19 17:00:42 +12:00
Leaf Garland
737fee94d0 Change build_win.bat to build Wix installer 2020-05-19 16:57:26 +12:00
Leaf Garland
4a2d770066 Add Wix/msi installer for Windows 2020-05-19 16:56:50 +12:00
Calvin Rose
b7cfc08fc5 Improve line and col tracking in parser.
Unconditionally add line and column information if
a parsed value is a tuple - before, some parsed tuples
had line and col information omitted.
2020-05-18 19:05:27 -05:00
Calvin Rose
92f0e1719b Be less eager to set macro-form in macex1. 2020-05-18 18:37:41 -05:00
Calvin Rose
9e5f203302 Expose line, col in macros via (dyn :macro-form)
This exposes line and column indirectly via
tuple/sourcemap and allows interesting debug macros.
2020-05-18 18:27:35 -05:00
Calvin Rose
17cb0c1aee Merge pull request #402 from andrewchambers/linelockfiles
Format lock files for nicer diffs.
2020-05-18 18:45:25 -04:00
Calvin Rose
df32cd0aca Update tracev macro to be simpler and single arity.
Reference #401
2020-05-18 17:43:41 -05:00
Calvin Rose
ae5dc8c45b Merge pull request #401 from LouisJackman/add-dbg-core-macro
Add a dbg macro for easy var dumping
2020-05-18 18:30:14 -04:00
LouisJackman
b1ed5b0707 Add "trace " prefix missed out from previous commit 2020-05-18 22:02:56 +01:00
Calvin Rose
eefdb3f156 Merge pull request #403 from kryptine/master
Fix spelling errors
2020-05-18 17:01:41 -04:00
LouisJackman
e9a5cfaddd Adopt Andrew Chamber's suggestions 2020-05-18 21:55:21 +01:00
kryptine
f5f2997cc2 Fix spelling errors 2020-05-18 06:32:00 +00:00
Andrew Chambers
43d2ba6275 Format lock files for nicer diffs. 2020-05-18 15:43:52 +12:00
Calvin Rose
8b98b331cc Add :hardcode-syspath option to declare-binscript.
This should make fully correct installs easier.
2020-05-17 09:29:45 -05:00
LouisJackman
e0130e7fd7 "Literal" -> "Expression" for trace-pp msg 2020-05-17 08:18:44 +01:00
LouisJackman
fb491f0d7c Put back erroneously deleted "Literal" 2020-05-17 08:12:54 +01:00
Calvin Rose
33b5d9651f Remove more mentions of lisp in descriptions. 2020-05-16 15:22:34 -05:00
LouisJackman
9109e369ff Incorporate suggestions from PR 2020-05-16 20:18:00 +01:00
Calvin Rose
b97e011715 Remove some lisp claims from README for branding. 2020-05-16 14:12:21 -05:00
Calvin Rose
1bb9a9368b Make sure winsock2.h is included before windows.h
This should be true in the normal build, and especially in the
amalgamated build.
2020-05-16 12:41:26 -05:00
LouisJackman
ca3dac7e87 Return an immutable tuple instead 2020-05-16 15:50:47 +01:00
LouisJackman
59302d4f42 Return dbg values to work inside complex exprs 2020-05-16 15:42:16 +01:00
LouisJackman
fabb722c8d Add a dbg macro for easy var dumping 2020-05-16 15:15:57 +01:00
Calvin Rose
657fae490c Update CHANGELOG.md 2020-05-16 08:36:32 -05:00
Calvin Rose
e9acebe0e8 Merge branch 'master' of github.com:janet-lang/janet 2020-05-16 08:29:30 -05:00
Calvin Rose
7a84fc4742 Fix infinite loop in some cases.
Problem - reusing a tainted variable without reinitializing.
2020-05-16 08:28:50 -05:00
Calvin Rose
4be3d66a32 Merge pull request #395 from zyga/master
Add snapcraft packaging
2020-05-15 19:04:26 -04:00
Calvin Rose
92df01b99d Add valtest and debug to Makefile help. 2020-05-15 17:59:05 -05:00
Calvin Rose
5c9c738913 Merge pull request #399 from LouisJackman/add-make-help-target
Add make help target
2020-05-15 18:55:23 -04:00
Calvin Rose
83c357d9d1 Merge branch 'master' of github.com:janet-lang/janet 2020-05-15 17:24:21 -05:00
Calvin Rose
3bb3adefbb Rename jpm repl to jpm debug-repl. 2020-05-15 17:22:30 -05:00
Calvin Rose
cf670153f9 Add :fresh option to import. 2020-05-15 17:19:37 -05:00
LouisJackman
d6cd69e659 Add make help target 2020-05-15 07:51:21 +01:00
Calvin Rose
48d31ad7bc Merge pull request #396 from halfhorst/documentation/update-readme-embedding
update janetconf.h path in README embedding section
2020-05-13 18:13:53 -04:00
halfhorst
20aa258f0e update janetconf.h path in README embedding section 2020-05-13 14:54:44 -07:00
Zygmunt Krynicki
45a60956a6 Add snapcraft packaging
Snapcraft allows the latest version of Janet to be immediately available
to developers on most popular Linux distributions. This patch provides
the snapcraft.yaml file, which provides information about the package,
how to build it and how to install it.

Both janet and jpm are exposed, though the latter requires a store side
alias to be provided, as snap names also control application names, to
avoid clashes between applications.

For this prototype I've selected classic confinement. Application
language packages are usually provided with classic confinement, as that
is most flexible for developers.

Snaps do not support providing manual pages yet, so no entries for those
were created.

Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
2020-05-13 19:04:10 +02:00
Calvin Rose
4ae372262b 1.9.1 release. 2020-05-12 09:19:09 -05:00
Calvin Rose
02167a15d1 Add new Makefile options to meson. 2020-05-12 09:04:38 -05:00
Calvin Rose
b50a4669d2 Update README and CHANGELOG. 2020-05-12 08:56:58 -05:00
Calvin Rose
c947bda604 Remove .breakall and .clearall conditionally.
If disasm not available, these functions cannot be implemented.
2020-05-12 08:52:36 -05:00
Calvin Rose
00451777fe Add meson builds to sourcehut CI. 2020-05-12 08:46:26 -05:00
Calvin Rose
a65386e925 Merge branch 'master' of github.com:janet-lang/janet 2020-05-11 01:10:58 -05:00
Calvin Rose
2d7d154ffc Merge pull request #392 from t6/patch-meson
Unbreak Meson build
2020-05-11 00:08:25 -04:00
Calvin Rose
3100080a50 Add NO_UMASK and NO_REALPATH config options. 2020-05-10 23:07:54 -05:00
Tobias Kortkamp
7275370ae5 Unbreak Meson build
The Meson build system
Version: 0.54.0
Source dir: /wrkdirs/usr/ports/lang/janet/work/janet-1.9.0
Build dir: /wrkdirs/usr/ports/lang/janet/work/janet-1.9.0/_build
Build type: native build

meson.build:225:2: ERROR: Expecting rbracket got string.
  'test/suite9.janet'
  ^
For a block that started at 215,13
test_files = [
             ^
2020-05-11 06:02:26 +02:00
Calvin Rose
e013381e72 Conditionally ignore pclose as well as popen. 2020-05-10 21:06:52 -05:00
Calvin Rose
d05bb1c125 Fix nanboxing issue. 2020-05-10 20:14:47 -05:00
Calvin Rose
273d1ff2d0 Fix external grammar to disallow | and \ in symbols. 2020-05-10 16:57:42 -05:00
Calvin Rose
235605bfa4 1.9.0 Release.
Fix up some documentation as well.
2020-05-10 16:45:33 -05:00
Calvin Rose
e8b3587946 Silence clang warnings about missing initializers. 2020-05-10 16:00:55 -05:00
Calvin Rose
9040ac6a0c Silence some warnings about pointer signedness. 2020-05-09 23:58:45 -05:00
Calvin Rose
a73ba56ebb Address #387
Introduce linker flags vs. library flags in jpm
in a backwards compatible way - most usage of lflags was for library
flags, so we will preserve that behavior.
2020-05-09 21:11:26 -05:00
Calvin Rose
1168f47768 Update default path for installed binaries.
This is useful for installing binaries in a default install
(when JANET_PATH or JANET_MODPATH is not explicitly set).
2020-05-09 19:02:12 -05:00
Calvin Rose
73dba691b1 Re-disable processes on emscripten build. 2020-05-09 12:04:47 -05:00
Calvin Rose
b1f76139a7 Add several configurable options - #379 2020-05-09 12:00:01 -05:00
Calvin Rose
6b986fecb0 Merge branch 'master' of github.com:janet-lang/janet 2020-05-09 11:07:15 -05:00
Calvin Rose
535ab8302b Add errorf to core. 2020-05-09 11:06:20 -05:00
Calvin Rose
7125b3430c Merge pull request #383 from andrewchambers/rngdoc
Improve rng doc string accuracy.
2020-05-09 11:35:01 -04:00
Calvin Rose
0615d09b7a Merge pull request #385 from andrewchambers/fnctlfix
Avoid setting O_CLOEXEC on stdin/stdout/stderr.
2020-05-09 11:34:37 -04:00
Calvin Rose
1add0c7d43 make test-install should be easier to clean. 2020-05-09 10:30:09 -05:00
Calvin Rose
8194f5ccaf Refactor jpm.
Make install and uninstall commands variadic.
Add :libs option to many decalre commands. This behaves much like
lflags, but will be places after all linker flags are given.
2020-05-09 10:22:46 -05:00
Andrew Chambers
057486cf56 Avoid setting O_CLOEXEC on stdin/stdout/stderr. 2020-05-09 22:26:50 +12:00
Andrew Chambers
f94e726271 Improve rng doc string accuracy. 2020-05-09 12:11:08 +12:00
Calvin Rose
95660002e1 fix include sys/fcntl.h to fcntl.h 2020-05-07 14:54:03 -05:00
Calvin Rose
95c669389b Merge pull request #378 from andrewchambers/tweak
Tweak comment, remove extra include.
2020-05-07 10:33:19 -04:00
Calvin Rose
084fc9776d Use SOCK_CLOEXEC correctly. 2020-05-07 07:55:08 -05:00
Andrew Chambers
1498fdb7b0 Tweak comment, remove extra include. 2020-05-07 20:44:04 +12:00
Calvin Rose
79c3139748 Check for SOCK_CLOEXEC.
Not available on all platforms.
2020-05-06 23:44:01 -05:00
Calvin Rose
bdd64f5656 Merge branch 'master' of github.com:janet-lang/janet 2020-05-06 18:52:57 -05:00
Calvin Rose
dc3e9fb77c Add CLOEXECs when getting file descriptors (#374)
This should help address leaking file descriptors in multithreaded
programs. There are a few cases where a race can occur though, as
some apis (fopen and mktemp).
2020-05-06 18:33:25 -05:00
Calvin Rose
4b417c0e9d Merge pull request #375 from andrewchambers/mttemp
Set the CLOEXEC flag on file/temp files.
2020-05-06 18:19:11 -04:00
Andrew Chambers
06c28f3a4d Set the CLOEXEC flag on file/temp files. 2020-05-06 11:16:08 +12:00
Calvin Rose
688fe6db5e Merge pull request #370 from andrewchambers/spawnrace
Fix (mostly nonsensible) race condition in multi threaded processes
2020-05-05 10:33:41 -04:00
Calvin Rose
9aefb59afe Format jpm with spork. 2020-05-05 09:21:50 -05:00
Calvin Rose
e3862b86b5 Use spork indent on boot.janet. 2020-05-05 09:17:09 -05:00
Calvin Rose
125cd222bb Pretty print tab characters as \t. 2020-05-05 00:03:12 -05:00
Andrew Chambers
a0f351c9fa Fix (mostly nonsensible) race condition in multi threaded processes using os/execute with os/setenv. 2020-05-05 16:03:13 +12:00
Calvin Rose
f7b49a2c91 Improve use of @ in match. 2020-05-04 18:28:20 -05:00
Calvin Rose
fd70b47768 Merge branch 'master' of github.com:janet-lang/janet 2020-05-02 23:40:11 -05:00
Calvin Rose
5d1fd390a6 Fix debugger regression. 2020-05-02 23:40:00 -05:00
Calvin Rose
8b5663e385 Merge pull request #363 from uasi/fix-typo-in-doc
Fix typo in doc
2020-05-02 12:11:18 -04:00
Calvin Rose
8b5bcaee3c Add lenprefix combinator to pegs.
This lets peg match n repeitions of a pattern, where
n is supplied from other parsed input and is not a constant.
2020-05-02 10:39:35 -05:00
Tomoki Aonuma
ca845aa256 Fix typo in doc 2020-05-02 02:36:55 +09:00
Calvin Rose
761ea65d81 Add fiber/roor and allow net/server to take
a numeric port.
2020-04-30 23:21:26 -05:00
Calvin Rose
1dc32d5e3d Revert inclusion of dedent.
Dedent has been moved to spork as misc function.
There are two many different, incompatible ways to 'dedent'
as string, and it seems rather specific to add to the core like it is.
2020-04-30 21:35:22 -05:00
Calvin Rose
1c0a015cc8 s/WSALastError/WSAGetLastError()/g 2020-04-30 13:26:14 -05:00
Calvin Rose
bee415217d Fix extra bindings. 2020-04-29 21:57:19 -05:00
Calvin Rose
73989f5cc7 Consolidate windows and posix socket code.
Also remove code that ignored sigpipe and instead try
our best to ignore through various platform specific mechanisms.
2020-04-29 21:07:21 -05:00
Calvin Rose
dd458c8ab5 Make JANET_NO_ASSEMBLER not break build. 2020-04-28 23:04:24 -05:00
Calvin Rose
63e9790123 Fix flag check in pretty print. 2020-04-28 10:00:24 -05:00
Calvin Rose
70e1f3ac81 Fix regression in repl. 2020-04-28 08:20:07 -05:00
Calvin Rose
67f1872f4a Expose debugger-env
This makes it easier/possible to use the debugging
functionality in a more flexible way.
2020-04-27 23:32:21 -05:00
Calvin Rose
8bbb7907d6 Run parser error handler in the correct env in run-context. 2020-04-27 20:29:16 -05:00
Calvin Rose
c98e1f3cae Update documentation for net/read and net/chunk. 2020-04-27 19:26:05 -05:00
Calvin Rose
6b0f93ce8a Update documentation for the -q flag. 2020-04-27 18:57:53 -05:00
Calvin Rose
80f19a0ab7 Fix behavior of -q flag.
Don't surpress errors at the repl.
2020-04-27 18:12:22 -05:00
Calvin Rose
41894eb285 Add docstrings to net.c 2020-04-26 14:11:47 -05:00
Calvin Rose
3535efd977 Remove %u format specifiers. 2020-04-26 13:47:36 -05:00
Calvin Rose
f6bd41ada7 Add %M, %m, %N, and %n formatters.
These will not truncate long values.
2020-04-26 13:17:28 -05:00
Calvin Rose
7b5f40772f Disable networking for emscripten build. 2020-04-26 12:37:27 -05:00
Calvin Rose
d2ebf4b52d Merge branch 'net' 2020-04-26 12:27:37 -05:00
Calvin Rose
0fe5c672a6 Use dedent in jpm create-executable. 2020-04-26 12:14:43 -05:00
Calvin Rose
ce7d51f9be Add dedent to core.
Makes longstrings easier to use - can be combined with comptime
for overhead free long strings.
2020-04-26 11:53:26 -05:00
Calvin Rose
cc1f84d1d3 Fix NSIS installer after moving jpm. 2020-04-26 08:58:53 -05:00
Calvin Rose
74126d9f24 Merge branch 'master' of github.com:janet-lang/janet 2020-04-26 08:55:59 -05:00
Calvin Rose
69eb9531da Rename auxbin/jpm -> jpm. 2020-04-26 08:55:32 -05:00
Calvin Rose
da4d8254fa Silence warning in MSVC about VLAs.
When janet.h is included as a C++ header in
MSVC, shows warnings.
2020-04-25 17:13:25 -04:00
Calvin Rose
57332c5ccf Change order of declarations for MSVC C++ support. 2020-04-25 15:42:44 -05:00
Calvin Rose
9bc5ac05c4 Add the parse function. 2020-04-25 12:46:32 -04:00
Calvin Rose
0a4d58468e Remove Debug build from appveyor. 2020-04-25 12:06:22 -04:00
Calvin Rose
8ce092da68 Update create-dirs to work on windows style paths. 2020-04-25 12:01:09 -04:00
Calvin Rose
fce1529bf2 Re-enable NSIS unicode. 2020-04-25 10:01:27 -05:00
Calvin Rose
61edf22a45 Remove Unicode True
This seems like it might trigger mS defender based on an old bug.
Don't think we really need it, so I will remove it just in case.
2020-04-25 09:26:56 -05:00
Calvin Rose
84974d6c56 Make repl printing work from current environment.
Although this "unprotects" output in the repl, people
in a repl usually want control, not protection.
2020-04-24 22:29:02 -05:00
Calvin Rose
da438a93e0 Restore lexicographic comparison of tuples. 2020-04-24 16:51:04 -05:00
Calvin Rose
a87015598c Make janet_equals and janet_compare non recursive
This makes these operatios use constant stack space rather
than linear stackspace given the size of the inputs. This is important
to prevent certain parser input from causing a stack overflow - in
general, we try to avoid unbounded recursion.
2020-04-24 16:18:31 -05:00
Calvin Rose
c335bf5dc5 Update doc doc. 2020-04-23 12:15:12 -05:00
Calvin Rose
c6a782c0ce Add information on lockfiles to the man page. 2020-04-23 12:10:22 -05:00
Calvin Rose
d148e14aa2 Merge pull request #357 from andrewchambers/lockfilejdn
Lockfiles are jdn, not code.
2020-04-23 13:03:51 -04:00
Andrew Chambers
748a5d41c1 Lockfiles are jdn, not code. 2020-04-23 21:53:36 +12:00
Calvin Rose
c876e63010 Fix overflow in exponent estimation in strtod.c.
Found by OSS-Fuzz.
2020-04-21 18:32:59 -05:00
Calvin Rose
23b811243f Update CHANGELOG.md 2020-04-21 18:24:46 -05:00
Calvin Rose
99d9c57154 Add the --offline flag to jpm.
This will let jpm install things only from the cache, and not
try and sync the latest from git.
2020-04-21 12:41:08 -05:00
Calvin Rose
13559baecc Merge pull request #354 from andrewchambers/safeclean
Do not recurse into symlinks when cleaning.
2020-04-21 13:21:42 -04:00
Calvin Rose
481647ed5d Merge pull request #355 from sogaiu/fiber-new-err-msg
Add flags to fiber/new error message
2020-04-21 13:21:11 -04:00
sogaiu
5c162ce588 Add flags to fiber/new error message 2020-04-21 13:47:56 +01:00
Andrew Chambers
e1b6175efd Do not recurse into symlinks when cleaning. 2020-04-21 15:11:51 +12:00
Calvin Rose
ea46f096c2 Remove placeholder config variables. 2020-04-20 20:10:24 -05:00
Calvin Rose
da88dd8cfa Streamline tree printing code. 2020-04-20 19:50:32 -05:00
Calvin Rose
9b5c6112e5 The -q option no longer disables repl output. 2020-04-20 19:28:30 -05:00
Calvin Rose
ea1341a129 Show post-deps rules in rule tree. 2020-04-20 19:19:53 -05:00
Calvin Rose
343cb779d2 Remove extra os/mkdir. 2020-04-20 19:06:53 -05:00
Calvin Rose
b0af01a762 Remove ./build as default rule.
Instead, all compilation rules do the equivalent of
mkdir -p to make sure that we can build the output file.
2020-04-20 19:02:09 -05:00
Calvin Rose
d8617514f8 Add jpm rule-tree.
Useful for debugging jpm project.janet files.
This tree printing logic can also be reused for
showing dependency information in the future.
2020-04-20 18:32:25 -05:00
Calvin Rose
e579d1d89f Add jpm rule-tree.
Useful for debugging jpm. This funtionality also maybe reused for
for showing a dependency tree as well.
2020-04-20 18:31:14 -05:00
Calvin Rose
63812c9f80 Merge pull request #350 from DavidKorczynski/master
Updated the libfuzzer to target marshalling.
2020-04-19 18:56:51 -04:00
David Korczynski
676a0afe4c Fixed up very wrong fuzzer to go more for the parser. 2020-04-19 20:36:38 +01:00
Calvin Rose
42c257d0fc Merge branch 'master' into net 2020-04-19 13:38:51 -05:00
Calvin Rose
d5e5c98dc8 Merge branch 'net' of github.com:janet-lang/janet into net 2020-04-19 13:37:54 -05:00
Calvin Rose
12d21dcb85 Update CHANGELOG.md 2020-04-19 10:57:50 -05:00
Calvin Rose
5054eb4276 Add JANET_MARSH_UNSAFE flag.
This allows unmarshal to optional marshal raw
pointers and cfunctions and send them across threads.
This flag is only exposed in the C API as it is very easy
to misuse and cause segfaults.
2020-04-19 10:56:39 -05:00
Calvin Rose
122c77dbf6 Merge pull request #353 from andrewchambers/require
Fix outdated require docstring.
2020-04-19 10:44:37 -04:00
Calvin Rose
3c66cab4e7 Remove extra binding in require. 2020-04-19 09:44:02 -05:00
Calvin Rose
738fd479b3 Merge branch 'master' of github.com:janet-lang/janet 2020-04-19 09:41:49 -05:00
Calvin Rose
5c612095a1 Address #352, #351, Use :source argument in dofile
Also re-add circular dependency detection.
2020-04-19 09:38:18 -05:00
Calvin Rose
3e60e82529 Add circular dependency detection.
This detection will not stop compilation, as errors
in general do not stop compilation unless exit on error
is passed inside an import, but should notify the user something
is going on.
2020-04-19 09:35:14 -05:00
Calvin Rose
60f8dd0bfc Renable :source argument to dofile.
Allows for some more interesting usage of
loaders.
2020-04-19 08:54:24 -05:00
Andrew Chambers
2a7008a82c Fix outdated require docstring. 2020-04-19 23:02:35 +12:00
Calvin Rose
0d3c6abee8 POLLER -> POLLERR 2020-04-18 19:15:59 -04:00
Calvin Rose
4a693222b4 Port net code to windows.
Use winsock2 and WSAPoll. Not the most high performance
solution but should work well.
2020-04-18 19:14:38 -04:00
David Korczynski
82e052f2ec Updated the libfuzzer to target marshalling. 2020-04-18 22:04:26 +01:00
Calvin Rose
0745c15d7b Fix return value from shell.c 2020-04-18 15:31:46 -05:00
Calvin Rose
2904c19ed9 Switch to poll from select.
Simpler and more flexible interface, and also lets
us use epoll more easily on linux, which is the most important
plantform to optimize for network performance.
2020-04-18 15:22:20 -05:00
Calvin Rose
16fe0a301c Merge pull request #349 from sogaiu/tweak-unknown-signal-handling
Tweak unknown signal handling
2020-04-18 06:22:29 -05:00
sogaiu
aebb8010d4 Tweak unknown signal handling 2020-04-18 08:26:16 +01:00
Calvin Rose
4ac382e553 Add alias JANET_SIGNAL_EVENT. 2020-04-17 16:27:02 -05:00
Calvin Rose
596111c988 Merge branch 'master' into net 2020-04-17 15:08:26 -05:00
Calvin Rose
e202d30835 Use make format. 2020-04-17 13:39:23 -05:00
Calvin Rose
fbe903b277 Add janet_cfuns_prefix to janet.h
Makes adding functions to the current environment easier.
2020-04-17 13:37:52 -05:00
Calvin Rose
8a89e50c13 :octal-permissions -> :int-permissions (#347) 2020-04-16 19:05:00 -05:00
Calvin Rose
6cb0e0dcea Merge branch 'master' of github.com:janet-lang/janet 2020-04-16 19:02:58 -05:00
Calvin Rose
a147ea3e80 Use JANET_PRETTY_DICT_LIMIT. 2020-04-16 19:01:49 -05:00
Calvin Rose
557988e530 Merge pull request #344 from DavidKorczynski/master
Added a fuzzer and integration with OSS-Fuzz.
2020-04-16 18:50:07 -05:00
Calvin Rose
67fb2c212f Address #348
Remove extreneous data from lockfile.
2020-04-16 18:44:21 -05:00
Calvin Rose
3765b08cca Merge branch 'master' of github.com:janet-lang/janet 2020-04-16 12:11:59 -05:00
Calvin Rose
3eb84fcb13 Fix some typos, make jpm repl work without a project.janet. 2020-04-16 12:11:17 -05:00
Calvin Rose
bea76e8e08 Merge pull request #345 from sogaiu/checks-after-allocs
Check some *alloc return values
2020-04-15 19:45:39 -05:00
Calvin Rose
f5433dcaa4 Fix core getline that doesn't use replacement. 2020-04-15 19:45:17 -05:00
Calvin Rose
ef3b953a42 Fix docstrings. 2020-04-14 21:32:50 -05:00
Calvin Rose
605a205008 Range errors for slice-likes include negatives.
Makes for less confusing errors when calling something
like `(slice [] 0 -10)`.
2020-04-14 21:27:48 -05:00
Calvin Rose
058f63b440 Add sh-rule and sh-phony to jpm dialect.
Provides useful shorthand for writing rules that invoke
shell commands.
2020-04-14 20:43:53 -05:00
Calvin Rose
71882475d6 janet_formatb -> janet_formatbv, new janet_formatb
The old function was not very useable. In the likely
case that there is no external code using this
(not well documented/janet_formatc is more convenient), we
can change this.
2020-04-14 07:38:41 -05:00
sogaiu
a3d29a15df Check some *alloc return values 2020-04-14 10:22:45 +01:00
Calvin Rose
a09112404d Add better error message on unexpected eos.
Show innermost open delimiter
2020-04-13 23:18:27 -05:00
Calvin Rose
93fc11ea21 Add edefer.
Also improve error messages from vm internal errors.
(Show bad value, not its type).
2020-04-13 20:24:11 -05:00
davkor
4faa129b8e Added a first fuzzer. 2020-04-13 17:33:58 +01:00
Calvin Rose
6c4ed0409d Add emscripten check to features.h. 2020-04-12 14:13:55 -05:00
Calvin Rose
ea2811f14f Merge branch 'master' of github.com:janet-lang/janet 2020-04-11 13:42:34 -05:00
Calvin Rose
8bc2987a71 (struct ...) with duped keys will use last value. 2020-04-11 13:42:25 -05:00
Calvin Rose
1d13095d19 Merge pull request #340 from pepe/get-vs-in-last
Fix last for empty collection, add tests
2020-04-10 19:03:21 -05:00
Calvin Rose
5ed76f197a Differentiate error from resume and error from resumed fiber. 2020-04-10 18:29:10 -05:00
Calvin Rose
e1f4cadf41 Add debugger to the core repl.
Debugger functions are prefixed by periods.
2020-04-10 17:20:23 -05:00
Calvin Rose
3b0e6357ad Make Ctrl-G in repl show docstring for symbol.
Can be used to browse docs without poluting your repl session.
2020-04-10 11:36:23 -05:00
Calvin Rose
02f17bd4e4 Add sort-by and sorted-by. 2020-04-09 20:43:51 -05:00
Josef Pospíšil
b63a0796fd Fix last for empty collection, add tests 2020-04-09 14:35:57 +02:00
Calvin Rose
e6d4e729fb Keep reference alive so unmarshalled object not collected. 2020-04-06 17:24:52 -05:00
Calvin Rose
b75a22b753 Make JANET_FRAME_SIZE consistent across architectures.
This means unmarshalling fibers should work across arches.
2020-04-06 12:41:56 -05:00
Calvin Rose
72beeeeaaa Move funcenv verification to runtime.
Lazy verification makes it easier to not leave funcenvs
in an invalid state, as well as be more precise with the validation.
We needed to verify the FuncEnvs actually pointed to a stack frame if
they were of the "on-stack" variant. There was some minor checking
before, but it was not enough to prevent func envs from pointing to
memory that was off of the fiber stack, overlapping stack frames, etc.
2020-04-06 10:58:47 -05:00
Calvin Rose
c3c42ef56f Fix case for #336.
Also consider ascii 127 (delete) non-printable for string escapes.
2020-04-06 00:11:22 -05:00
Calvin Rose
a3c55681b2 Address #336 case 6 2020-04-05 21:39:39 -05:00
Calvin Rose
cc70388846 Merge pull request #338 from andrewchambers/unmarshalfuzz2
Make unmarshal fuzzer exercise more code paths.
2020-04-05 20:36:30 -05:00
Calvin Rose
fcc610f539 Address #336 case 4
Set funcenv fields to NULL before any possible panics.
2020-04-05 19:18:59 -05:00
Calvin Rose
5bbd507858 Address #336 case 3
Fix error condition for bad abstract types - don't return NULL, panic.
2020-04-05 17:38:14 -05:00
Andrew Chambers
45156c0c47 Make unmarshal fuzzer exercise more code paths. 2020-04-06 09:59:00 +12:00
Calvin Rose
553e38ffd6 Merge pull request #337 from andrewchambers/fuzzunmarshal
Setup some simple fuzz helpers for unmarshal.
2020-04-05 08:17:42 -05:00
Calvin Rose
c4ca0490ee Prevent unmarsal DOS in arrays,buffers,tables,and structs. 2020-04-05 08:16:40 -05:00
Calvin Rose
b145d47863 Address cases 1 and 2 of #336.
Mainly related to not checking ints < 0.
2020-04-05 08:01:18 -05:00
Calvin Rose
095827a261 Update CHANGELOG.md 2020-04-05 07:12:00 -05:00
Calvin Rose
87ecdb8112 Change \UXXXXXXXX -> \UXXXXXX and check codepoint max.
No need to add two extra leading zeros, as the max unicode
codepoint is 0x10FFFF.
2020-04-05 07:09:53 -05:00
Andrew Chambers
98b2fa4d64 Setup some simple fuzz helpers for unmarshal. 2020-04-05 23:05:18 +12:00
Calvin Rose
810ef7401c Update changelog and bump version to dev version. 2020-04-04 21:50:27 -05:00
Calvin Rose
ae70a03383 Address #306 - Add unicode escapes.
Unicode escapes have the same syntax as go - \uXXXX or \UXXXXXXXX.
2020-04-04 21:46:08 -05:00
Calvin Rose
081d132538 Address #321
Also improve docs for dofile and related functions.
2020-04-04 21:17:15 -05:00
Calvin Rose
bb5c478704 Switch to two digit sonames.
Janet's versioning scheme is not 'true' semantic versioning.
Minor versions can have and often do have breaking changes.
Although such breakages are mostly avoided, only limited effort is
made to prevent this, and no system is in place to verify this.
Thus, stricter version pinning is needed.
2020-04-04 18:30:18 -05:00
Calvin Rose
ff6601f29e Add version and soversion to meson libjanet. 2020-04-04 18:04:22 -05:00
Calvin Rose
320c6c6f05 Increase NSIS installer verbosity. 2020-04-04 13:58:27 -05:00
Calvin Rose
6b89da4bb2 Use -Wl,-install_name,... on macos. 2020-04-04 13:44:21 -05:00
Calvin Rose
5b82b9e101 Address compiler warning on macos. 2020-04-04 13:34:16 -05:00
Calvin Rose
1d0e862129 Update Makefile for pkg-config issues and soname. 2020-04-04 13:09:59 -05:00
Calvin Rose
f089b2001f Add several math functions to the math module. 2020-04-04 12:52:34 -05:00
Calvin Rose
9f8420bf50 Add jpm repl subcommand and post-deps macro for jpm.
This will allow more flexibility in writing jpm project files.
2020-04-03 19:33:54 -05:00
Calvin Rose
8275da63fb Address #331 - Add :octal-permissions 2020-04-03 18:29:45 -05:00
Calvin Rose
72696600d8 Add :deps opiton to declare-executable.
This allows the addition of custom dependencies.
2020-04-03 17:53:41 -05:00
Calvin Rose
1aeb317863 Revise, revise, revise, and proofread. 2020-04-03 17:04:05 -05:00
Calvin Rose
b49b510732 Update os/link docstring. 2020-04-03 16:58:45 -05:00
Calvin Rose
a0d61e45d5 Change os/perm-str to os/perm-string. 2020-04-03 15:23:29 -05:00
Calvin Rose
95f1ef7561 Add umask support for windows, and allow parsing mode strings. 2020-04-03 15:14:11 -05:00
Calvin Rose
edb2fab64c Merge branch 'master' of github.com:janet-lang/janet 2020-04-03 15:04:39 -05:00
Calvin Rose
464fb73d83 Add os/perm-int and os/perm-str.
This helps address #331. While we could also
make os/stat return an integer, we don't do that yet
for api breakage reasons.

This also lets us use this logic on other functions
that take permission strings.
2020-04-03 15:02:12 -05:00
Calvin Rose
6a4e63a17d Merge pull request #333 from andrewchambers/umask
Add os/umask.
2020-04-03 14:48:52 -05:00
Calvin Rose
168f94d29a Merge pull request #330 from DEADB17/patch-1
Correct typo and match wording for consistency
2020-04-03 14:46:15 -05:00
Andrew Chambers
3c2b1baff2 Add os/umask. 2020-04-02 23:33:50 +13:00
Calvin Rose
f2815d7068 Actually run the installer in build_win.bat. 2020-04-01 09:26:20 -05:00
Calvin Rose
f48d9465f5 Fix appveyor.yml 2020-04-01 09:23:19 -05:00
Calvin Rose
6b1d5c6d7b Work on improving deployment for windows. 2020-04-01 09:22:27 -05:00
Calvin Rose
789ef3608b Make format. 2020-04-01 08:54:01 -05:00
DEADB17
57b08a57a0 Corret typo and match wording for consistency 2020-03-31 23:32:17 -04:00
Calvin Rose
5b6b9f1597 Prepare for 1.8.1 release. 2020-03-31 09:49:09 -05:00
Calvin Rose
47f246ba66 Merge pull request #329 from pepe/master
Fix typo flie
2020-03-31 09:17:39 -05:00
Josef Pospíšil
b6b70d54ef Fix typo flie 2020-03-31 15:31:27 +02:00
Calvin Rose
417d9a14cc s/yaml/yml/g in README.md 2020-03-31 08:03:38 -05:00
Calvin Rose
244566ccd4 Remove manual feature definitions in boot.
Instead, reuse features as defined in features.h
2020-03-31 07:52:20 -05:00
Calvin Rose
ca4a35c90a Update CHANGELOG.md 2020-03-30 16:59:51 -05:00
Calvin Rose
e4ea8bc867 Fix features for bsd.
Don't define XOPEN_SOURCE unless we actually need it.
2020-03-30 15:38:03 -05:00
q66
5d840b944b Fix wrong check on big endian systems
We can't randomly type pun random-sized types on big endian
systems.
2020-03-30 13:38:49 -05:00
q66
1e28876494 Fix typo in big endian unmarshalling code
This was subtly breaking everything.
2020-03-30 13:38:49 -05:00
q66
a40b2767c5 Fix endian check for little endian PowerPC and maybe others
This fixes various subtle breakage on ppc64le at very least.
2020-03-30 13:38:49 -05:00
Calvin Rose
279b536646 Prepare for 1.8.0 release. 2020-03-29 14:18:28 -05:00
Calvin Rose
ff163a5ae4 Use modulo instead of remainder for even?/odd?.
Works better for negative and fractional numbers.
2020-03-28 10:23:28 -05:00
Calvin Rose
65379741f7 Address edge case of reduce2 when ind is empty.
Same for accumulate 2.
2020-03-27 12:45:40 -05:00
Calvin Rose
3eb0927a2b Add accumulate(2) and reduce2
These functions are variations on reduce and can be quite useful.
Improve error message for jpm as well.
2020-03-26 21:35:11 -05:00
Calvin Rose
a3a45511e5 Remove lockfile.janet 2020-03-26 00:40:03 -05:00
Calvin Rose
a20ea702e2 Add infinite loop detection and complex deps.
We needed to handle dependencies that had both a url
and a tag component.
2020-03-26 00:34:34 -05:00
Calvin Rose
d2d0300c7e Remove use of cd in make-lockfile. 2020-03-26 00:12:18 -05:00
Calvin Rose
6e8aac984f Update CHANGELOG.md 2020-03-25 21:06:45 -05:00
Calvin Rose
6721c70b9e Fix typo in jpm. 2020-03-25 21:01:54 -05:00
Calvin Rose
b8c1c1c144 Get lockfile info from manifest, not cache.
Make manifest files track more information.
Use jdn to store manifest files, as well as repo url and
sha.
2020-03-25 20:58:53 -05:00
Calvin Rose
e380c01dd1 Add lockfiles to jpm.
Add make-lockfile and load-lockfile commands.
2020-03-25 19:44:30 -05:00
Calvin Rose
655633ef34 Tweak docstring. 2020-03-25 18:00:15 -05:00
Calvin Rose
3d1de237f6 Several changes to the os module.
- Add os/symlink
- Add os/realpath
2020-03-24 19:47:21 -05:00
Calvin Rose
6a63b13d69 Fix os/link docstring - Address #323 2020-03-21 16:18:58 -05:00
Calvin Rose
3aca5502dc Allow :dst to be nil to set tm_isdst to be -1. 2020-03-18 22:23:27 -05:00
Calvin Rose
665f4bf248 Remove windows MSVC warnings about _stat. 2020-03-18 21:37:55 -05:00
Calvin Rose
b76ff3bdfc Fix omission of daylight savings time in mktime
Since with daylight savings times, certain times
are ambiguous (the hours before and after the switch), mktime
needs to allow reading a dst flag.
2020-03-18 21:23:35 -05:00
Calvin Rose
00450cd9db try and remove warnings on windows, format os.c. 2020-03-18 21:15:50 -05:00
Calvin Rose
c344a543b0 Merge pull request #318 from leahneukirchen/mktime
os/date fixes and os/mktime
2020-03-18 20:59:08 -05:00
Calvin Rose
554202f6e8 Merge branch 'master' of github.com:janet-lang/janet 2020-03-18 18:37:11 -05:00
Calvin Rose
7590cfc610 Update meson build file to try and fix LGTM. 2020-03-18 18:36:41 -05:00
Calvin Rose
eee8338064 Merge pull request #319 from leahneukirchen/lstat
os/lstat and os/readlink
2020-03-18 17:58:32 -05:00
Calvin Rose
3b5183a74e Fixes #316: os/execute should return non-zero on signals
Behave more like shells, and catch segfaults.
2020-03-18 17:49:20 -05:00
Leah Neukirchen
3ee43c3abb add os/mktime, an inverse to os/date. 2020-03-18 23:45:02 +01:00
Leah Neukirchen
efdb13f0c7 os/date: allow negative timestamps.
Why not?  Even on 32-bit time_t systems this lasts until late 1901.
2020-03-18 23:45:02 +01:00
Leah Neukirchen
f013c6e48d os/date: check the second argument truthy, not the third. 2020-03-18 23:45:02 +01:00
Leah Neukirchen
6e67899401 Add os/readlink. 2020-03-18 20:05:48 +01:00
Leah Neukirchen
381dd1ce98 Add os/lstat. 2020-03-18 20:05:48 +01:00
Calvin Rose
b0d8369534 Increase reference accuracy of on-stack close envs.
Using a bitset to indicate which stack values are upvalues, we
can more accurately track when a reference to a stack value
persists after the stack frame exits.
2020-03-18 09:30:10 -05:00
Calvin Rose
4a7b18d841 Merge pull request #317 from andrewchambers/closureenvs
Add test cases for closure edge cases.
2020-03-17 22:05:35 -05:00
Andrew Chambers
7c4ffe9b9a Add test cases for closure edge cases. 2020-03-18 15:40:41 +13:00
Calvin Rose
de4f8f9aaf Marshal alive fibers in func envs as detached.
This will help with marshaling fibers.
2020-03-17 20:53:11 -05:00
Calvin Rose
6554cc4a8d Merge branch 'master' of github.com:janet-lang/janet 2020-03-17 18:58:33 -05:00
Calvin Rose
fac47e8ecb When marshalling a closure, try to detach funcenvs
If possible, this will reduce the need to marshal fibers
in many cases. Also add this logic to the GC so holding a closure
that originally came from a fiber that crashed does not cause that fiber
to hang around forever.
2020-03-17 18:55:32 -05:00
Calvin Rose
7443305039 Merge pull request #315 from andrewchambers/u64
Properly export u64_type
2020-03-16 17:15:20 -05:00
Andrew Chambers
635ae3a523 Properly export u64_type 2020-03-17 11:02:57 +13:00
Calvin Rose
4a05b4556e Fix MSVC build warning. 2020-03-14 12:02:31 -05:00
Calvin Rose
c074615550 Revert to 9 char permission strings on windows. 2020-03-14 12:00:11 -05:00
Calvin Rose
bac2b74b3d Add os/chmod. 2020-03-14 11:57:04 -05:00
Calvin Rose
a3aaa6634d Use separate registry table for abstract types.
This avoids overloading the registry table, which is intended
for names of c functions.
2020-03-14 10:25:39 -05:00
Calvin Rose
6a3a983f43 Expose abstract type definitions in janet.h
This makes certain operations easier, and allows
more access to built in APIs.
2020-03-14 10:12:47 -05:00
Calvin Rose
7996edfef9 Update README.md - Fixes #308 2020-03-13 20:00:32 -05:00
Calvin Rose
0600b32908 Fix docstring for os/cd - Fixes #307 2020-03-13 15:01:48 -05:00
Calvin Rose
77343e02e9 Fixes #304
Add chr macro.
2020-03-10 22:46:50 -05:00
Calvin Rose
a3d4ecddba Address #301
Incorrect bounds checking and offset calculation in buffer/blit.
2020-03-08 20:44:03 -05:00
Calvin Rose
65403ec9fe Merge branch 'master' into net 2020-03-07 14:06:51 -06:00
Calvin Rose
3d3d314fb7 Remove warning about math.h on aarch64 ubuntu gcc. 2020-03-07 14:05:28 -06:00
Calvin Rose
90b3730a0a Merge branch 'master' into net 2020-03-07 13:34:13 -06:00
Calvin Rose
3f3b756b61 Merge pull request #298 from leahneukirchen/m-del
Make alt-backspace behave like ctrl-w.
2020-03-07 10:14:14 -06:00
Calvin Rose
d3b9b8d452 For #293, correct wildcards in dictinoaries. 2020-03-07 10:13:10 -06:00
Calvin Rose
390c042027 Update README.md 2020-03-07 09:49:25 -06:00
Calvin Rose
c864828735 Address #293 - wildcard to match macro.
The _ symbol will match any value without creating a binding.
2020-03-07 09:40:02 -06:00
Calvin Rose
e0c9910d85 Add :range-to and :down-to to loop.
Fully inclusive ranges are generally useful and
do not complicate implementation much.
2020-03-07 09:34:11 -06:00
Calvin Rose
e62f12426b Update ci build files. 2020-03-06 18:11:29 -06:00
Calvin Rose
d3af50e4cc Rename: s/yaml/yml/g 2020-03-06 17:42:35 -06:00
Calvin Rose
cbdb700edf No need for doubly hidden files. 2020-03-06 17:35:03 -06:00
Calvin Rose
6010b95fca Remove spaces from build manifests for sourcehut. 2020-03-06 17:30:36 -06:00
Calvin Rose
e351dde651 Update CHANGELOG.md and docs for loop and pp. 2020-03-06 17:12:06 -06:00
Calvin Rose
714bd61d56 Address #300
Check for empty capture stack in replace rule.
2020-03-06 10:05:20 -06:00
Calvin Rose
f9e9c70b6c Update CHANGELOG.md 2020-03-06 08:40:51 -06:00
Calvin Rose
6123c41f13 Harden semantics for and and or macros.
There was perviously a bit of fuzziness on returning false/nil
from these macros that has been removed.
2020-03-06 08:37:59 -06:00
Leah Neukirchen
1aaa5618de Make alt-backspace behave like ctrl-w.
Another common binding in readline and its clones.
2020-03-06 10:55:45 +01:00
Calvin Rose
16202216b2 Address #291
When resuming a fiber with a child, the root fiber was set incorrectly.
2020-03-05 19:18:45 -06:00
Calvin Rose
8f1527712e Merge branch 'master' into net 2020-03-05 18:08:35 -06:00
Calvin Rose
fbe8998ca8 Merge branch 'master' of github.com:janet-lang/janet 2020-03-05 09:35:04 -06:00
Calvin Rose
47e8f669f5 Fix match behavior for lone nil. 2020-03-05 09:35:00 -06:00
Calvin Rose
d804ee3c07 Merge pull request #296 from leahneukirchen/ctrl-d
Make ctrl-d behave like delete, but exit on an empty line.
2020-03-04 20:42:05 -06:00
Calvin Rose
06a78d90d9 Merge pull request #295 from leahneukirchen/meson-pkgconfig
Create janet.pc also from Meson.
2020-03-04 20:39:24 -06:00
Leah Neukirchen
bc2ebce086 Make ctrl-d behave like delete, but exit on an empty line.
This is the default readline behavior.
2020-03-04 14:56:04 +01:00
Leah Neukirchen
a07de921d0 Create janet.pc also from Meson. 2020-03-04 14:35:57 +01:00
Calvin Rose
6bc67b70a6 Address #294
Correct invalid format string, which masked a panic
with another, less useful panic.
2020-03-03 22:26:26 -06:00
Calvin Rose
f06addfe06 For #240, address case when LDCONFIG is empty 2020-03-03 18:13:25 -06:00
Calvin Rose
7c2c50ee16 For #240 - don't run ldconfig for DESTDIR installs. 2020-03-03 18:03:44 -06:00
Calvin Rose
8580d3c27e Address #240 - Support DESTDIR in Makefile. 2020-03-03 17:45:59 -06:00
Calvin Rose
951e10f272 Address #292
Faulty Makefile fallback.
2020-03-03 08:21:14 -06:00
Calvin Rose
2349ea9405 Update docs for buffer/push-word
Should be little endian, not big endian.
2020-03-01 12:05:24 -06:00
Calvin Rose
b17bf259f7 Fix typo: destory -> destroy 2020-02-28 09:04:28 -06:00
Calvin Rose
6b093bdcca Address #288 and partially #287
The %q formatter for janet_formatc now expects a Janet, not a JanetString or
JanetSymbol or JanetKeyword.

Also fix some reference counting issues with threads when destroying
threads, which should fix #287's
SIGSEGV. Still fails to send messages sometimes, though.
2020-02-27 17:58:17 -06:00
Calvin Rose
10ec319c32 Add better debug info to amalgamated source. 2020-02-27 00:16:54 -06:00
Calvin Rose
8cb63cebbe Remove 'make test-amalg' from CI. 2020-02-25 20:31:38 -06:00
Calvin Rose
7d26de6697 Update changelog. 2020-02-25 20:08:22 -06:00
Calvin Rose
8262290bff Improve C string format (janet_formatc, janet_panicf)
The supported formatters here now match up more with
the string/format, buffer/format, printf, eprintf, etc.
2020-02-25 20:05:45 -06:00
Calvin Rose
2779037f13 Clean up Makefile. 2020-02-25 20:02:03 -06:00
Calvin Rose
734c85d7ef Properly handle recursion with labels.
Use an empty buffer, which has pointer equality semantics, for
tag from a label.
2020-02-23 17:35:01 -06:00
Calvin Rose
05bd5767de Add label macro.
A lexically scoped version of prompt is often useful.
2020-02-23 17:15:04 -06:00
Calvin Rose
59d288c429 Add prompt and return.
User friendly delimited continuations. While this was doable with
signals before, this does not require C and will play nicely with
existing error handling, defers, and with statements.
2020-02-23 16:46:54 -06:00
Calvin Rose
8c41c0b6a7 Address MSVC warning. 2020-02-23 15:27:57 -06:00
Calvin Rose
f5f3858da1 Update CHANGELOG.md 2020-02-23 14:55:21 -06:00
Calvin Rose
738490e674 Allow function that takes 1 argument to fiber/new.
This allows reuse of closures when creating many fibers.
2020-02-23 14:47:29 -06:00
Calvin Rose
6a13703e32 Add signal and fiber/can-resume?.
These additions, along with the change that user signals 0-4 cannot
be resumed, allow delimited continuation semantics, while repsecting
existing forms like `defer`, `with`, `with-vars`, etc.
2020-02-23 13:31:27 -06:00
Calvin Rose
20d5d560f3 Add bf to main test suite. 2020-02-22 19:18:08 -06:00
Calvin Rose
aaabca6fc7 Make flychecker handle more kinds of defs.
This should help when redefining certain forms. Will also
not do functional arity checking against nil forms, as that
is the default value when a def doesn't evaluate.
2020-02-21 21:20:40 -06:00
Calvin Rose
4b440618d6 Correct docs for type form. 2020-02-21 20:22:43 -06:00
Calvin Rose
01a79dc965 Remove extra functionality. 2020-02-20 20:10:03 -06:00
Calvin Rose
0df220780a Fix issues with #282
Bad handling of write errors, as well as janet_root_fiber().
2020-02-20 19:54:31 -06:00
Calvin Rose
a360cb7922 Update marshal to take 3 arguments. 2020-02-15 10:04:44 -06:00
Calvin Rose
b9a2bb8104 Fix documentation for defer. 2020-02-12 09:34:23 -06:00
Calvin Rose
f4a46ba6ea Add methods to streams.
This makes streams polymorphic with files in many cases.
printf family functions still need porting.
2020-02-12 09:32:41 -06:00
Calvin Rose
79bb9e54d5 Remove direct references to file descriptors.
If a descriptor is freed by the Janet code, other
uses of that descriptor, say in the event loop, need
to know that it has been closed.
2020-02-11 08:57:44 -06:00
Calvin Rose
135aff9e17 Add janet_loop() call to static binaries. 2020-02-09 20:02:35 -06:00
Calvin Rose
8ae6ae65a1 Merge branch 'master' into net 2020-02-09 20:00:58 -06:00
Calvin Rose
f4d7fd97f6 Working TCP echo server and client.
Required a few changes to APIs, namely janet_root_fiber()
to get topmost fiber that is active in the current scheduler.
This is distinct from janet_current_fiber(), which gets the bottom
most fiber in the fiber stack - it might have a parent, and so cannot
be reliably resumed.
This is the kind of situation that makes symmetric coroutines more
attractive.
2020-02-09 20:00:50 -06:00
Calvin Rose
031a9894b0 Update inlining options for next and resume. 2020-02-08 13:03:03 -06:00
Calvin Rose
fcc09d7ea9 Clarify docs for some and all. 2020-02-05 21:06:39 -06:00
Calvin Rose
7f1f684b21 Merge branch 'master' into net 2020-02-03 20:46:32 -06:00
Calvin Rose
d8d482e433 Merge branch 'master' of github.com:janet-lang/janet 2020-02-03 18:18:29 -06:00
Calvin Rose
3fdc053d6c Add flush and eflush (#278)
These functions interact with Janet's dynamically scoped
IO functions in a manner that is more useful the file/flush.
We can still redirect to a buffer without changing our code.
2020-02-03 18:14:32 -06:00
Calvin Rose
8be3ce18aa Merge pull request #280 from pepe/fix-next-arity
Fix next function arity
2020-02-03 18:00:36 -06:00
Calvin Rose
eda61455d3 Work on tcp server code. 2020-02-03 09:29:51 -06:00
Josef Pospíšil
00107c092c Fix next function arity 2020-02-03 15:36:42 +01:00
Calvin Rose
c5907258c3 Merge branch 'master' into net 2020-02-02 13:16:47 -06:00
Calvin Rose
64e1961193 Update version strings to 1.7.1-dev. 2020-02-02 09:38:44 -06:00
Calvin Rose
f7ee8bd30d Update to version 1.7.0. 2020-02-01 23:35:17 -06:00
Calvin Rose
c0d2140d14 Begin net/ module in core.
Humble beginnings.
2020-02-01 20:39:54 -06:00
Calvin Rose
1bdde9c4f7 Fix warnings. 2020-01-28 23:46:14 -06:00
Calvin Rose
333ae7c4f8 Make amalgamtion the default when building.
This way we can support fewer build configurations. Also, remove
all undefined behavior due to use of memcpy with NULL pointers. GCC
was exploiting this to remove NULL checks in some builds.
2020-01-28 23:38:52 -06:00
Calvin Rose
f7b7c83264 Address #276 2020-01-25 12:08:43 -06:00
Calvin Rose
6f9c9879ca Add var-
We had defn-, def-, defmacro-, but no var-.
2020-01-24 22:52:28 -06:00
Calvin Rose
b8df47e063 Fix regression in take/drop. 2020-01-24 17:39:25 -06:00
Calvin Rose
9dad8bf56d Remove min-order and max-order.
Also address #275 by exposing lflags and cflags
to declare-executable
2020-01-24 17:35:21 -06:00
Calvin Rose
689f2dcbb4 Change default import prefix.
Changed from `(string path "/")` to
`(string (last (string/split "/" path)) "/)`.
2020-01-24 16:54:06 -06:00
Calvin Rose
163e2a5b22 Add string support to %j format. 2020-01-24 08:52:27 -06:00
Calvin Rose
e36334e14b Revert issue with removing buffer self print check. 2020-01-23 23:39:49 -06:00
Calvin Rose
60304c7e27 Update CHANGELOG.md 2020-01-23 19:07:09 -06:00
Calvin Rose
28d41039b8 Add mod function to core.
The `mod` function is a pair function with `%`, or te remainder
function and is distinct from it. This is taken from common lisp.
2020-01-23 18:54:30 -06:00
Calvin Rose
b8d530da36 Remove file/fileno and file/fdopen.
Also fully add call function pointer to
abstract types, including in methods, etc.
2020-01-23 09:01:33 -06:00
Calvin Rose
4fad0714e7 Add janet_gcpressure. Address #269. 2020-01-22 20:52:35 -06:00
Calvin Rose
ca17eb4a2b Address #273 2020-01-22 19:01:49 -06:00
Calvin Rose
4fe005e3c3 Add righthand operator overloading.
This is like python. Now, we just need to readd fuzzy
comparisons to have what python needs. Overloading
math functions would be neat, too.
2020-01-22 18:59:41 -06:00
Calvin Rose
2f9ed8a572 Use memmove instead of copying.
Also some comment things, and re-add old code from linenoise.
It seems to have a purpose for some keyboard layouts, so I will leave
it.
2020-01-21 23:11:00 -06:00
Calvin Rose
688e18a891 Merge pull request #268 from crocket/master
Make REPL key bindings more similar to those on GNU readline.
2020-01-21 23:09:45 -06:00
crocket
8162c64ca3 Make REPL key bindings more similar to those on GNU readline.
* I deleted Alt-H and Alt-L because Ctrl-F and Ctrl-B serve the same
roles.
* Ctrl-W, Alt-D, Alt-F, and Alt-B behave more similarly to the same
key bindings on GNU readline.
* Improved documentation of REPL keybindings on man page.
* Home and End keys now work on more terminal environments.
* Removed bindings for `Esc OH` and `Esc OF` because andrewchambers
doesn't need those bindings and the bindings don't seem to make much
sense for Home and End. `Esc O` is Single Shift Select of G3 Character
Set in xterm. https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
2020-01-22 13:55:44 +09:00
Calvin Rose
e179f26d50 Add call function pointer to abstract types.
This will allow better JITs, FFIs, DSLs, etc.
2020-01-21 18:22:24 -06:00
Calvin Rose
8db68c04c4 Merge branch 'master' of github.com:janet-lang/janet 2020-01-21 17:48:54 -06:00
Calvin Rose
7c92c64730 Remove mutable operators on inttypes.
Mutations break hash table invariants, are a rather
silly performance optimization for a language like Janet.
2020-01-21 17:47:34 -06:00
Calvin Rose
01c6ffe1d5 Merge pull request #266 from andrewchambers/idempotentclose
Make file/close idempotent.
2020-01-21 10:16:06 -06:00
Andrew Chambers
46f57f5c38 Make file/close idempotent.
It is easier to use constructs like defer
with complex control flow if it is safe to close
a file twice.
2020-01-21 22:03:57 +13:00
Calvin Rose
1ec2e08f21 Add manpage docs for repl keybindings. 2020-01-20 17:29:29 -06:00
Calvin Rose
77742dec11 Add source file info on macro compiler error. 2020-01-20 16:45:57 -06:00
Calvin Rose
3cb947b37e Fix macro errors.
debug/stacktrace was being called incorrectly.
2020-01-20 16:05:08 -06:00
Calvin Rose
62cf407f0c Remove lto.
Gosh Darnit, Travis!
2020-01-20 13:53:59 -06:00
Calvin Rose
bbed72f39f Only enable lto on linux for now.
Was failing with clang, as the default clang linker doesn't
do LTO.
2020-01-20 13:37:10 -06:00
Calvin Rose
99c94a78d6 Add -flto to jpm builds as well. 2020-01-20 13:28:57 -06:00
Calvin Rose
2dd852da54 Use ATEND macros to add fields to abstract types.
This means we can add new properties to abstract types without
breaking old code. We can also make simple abstract types without
needing to add many NULL fields to the type.
2020-01-20 13:06:50 -06:00
Calvin Rose
3c87d89df3 Enable LTO by default
Most compilers support it, and it gives a good perf increase OOTB.
2020-01-20 11:38:22 -06:00
Calvin Rose
f4ad627b54 Fix regression in while loops inside each macros.
There was a specialization for `(while (not= nil _) ...)` that
was incorrect when the while loop regresses to a thunk.
2020-01-19 16:25:10 -06:00
Calvin Rose
68a5667a1a Add history first and history last shortcuts.
Alt-, and Alt-.
2020-01-19 15:45:04 -06:00
Calvin Rose
693c6d63d4 Add alt-d binding to repl. 2020-01-19 11:39:10 -06:00
Calvin Rose
f18c3323ea Clear completion list if fully complete. 2020-01-19 11:31:42 -06:00
Calvin Rose
f74e19e673 Improve alt keys and at alt-f and alt-b to repl 2020-01-19 11:16:41 -06:00
Calvin Rose
da70807292 Make autocompletion more zsh like
Also add a few ctrl sequences from readline, and
ignore unknown ctrl sequences.

Address #264

Adds Ctrl-n, Ctrl-p, and Ctrl-w
Ignores unknown ctrl sequences
No alt-* sequences yet.
2020-01-19 10:38:35 -06:00
Calvin Rose
9f8bc6bb8a Please, sir hat? 2020-01-18 21:00:06 -06:00
Calvin Rose
64b9482602 Make history not duplicate itself in getline. 2020-01-18 20:56:35 -06:00
Calvin Rose
8fbcae6029 Remove -march=native from Makefile
Instead, one can pass in CFLAGS to make
2020-01-18 20:01:12 -06:00
Calvin Rose
064475cb8d Add eachk and eachp.
These should make iterating over datastructures easier
without needing the loop macro.
2020-01-18 18:46:49 -06:00
Calvin Rose
f4077b678a Allow calling next on abstracts.
This will allow the creation of infinte
streams, low cost generators, etc.
2020-01-18 18:09:20 -06:00
Calvin Rose
51678c1aba Extend power of the each form
This changes the implementation of the `next` function which
is now used to implement each. This let's us iterate over
more types, not just tables and structs.
2020-01-18 17:55:07 -06:00
Calvin Rose
17a2fdbf1b Update for sourcehut builds.
We needed to include repo in sources array.
2020-01-18 14:42:02 -06:00
Calvin Rose
65d7c3eed1 Use stderr for getline output instead of stdout. 2020-01-18 14:34:29 -06:00
Calvin Rose
41bb8c543b Merge branch 'master' of github.com:janet-lang/janet 2020-01-18 09:46:37 -06:00
Calvin Rose
bbd7355313 Merge pull request #259 from andrewchambers/futureproofhash
Make hash api more future proof.
2020-01-18 09:45:47 -06:00
Calvin Rose
772916593b Address #262
Pressing tab only does one thing at a time.
2020-01-18 09:44:59 -06:00
Calvin Rose
9d8af7355f Improve getline. 2020-01-18 00:30:46 -06:00
Calvin Rose
521a29446f Don't rely on obscure printf features.
They may not work on all platforms.
2020-01-18 00:27:40 -06:00
Calvin Rose
a8e4c4bed0 Add special forms and sort completions.
Also fix case when no completion is needed.
2020-01-18 00:17:08 -06:00
Calvin Rose
6471b4d100 Add preliminary repl completion via tab. 2020-01-17 23:03:50 -06:00
Calvin Rose
7f9b2b34d1 Clarify import docs for dynamic bindings. 2020-01-17 18:06:00 -06:00
Calvin Rose
789c5f135a Add ctrl-a and ctrl-e to control line in repl
Emacs to start of line and to end of line key bindings.
2020-01-17 09:33:30 -06:00
Andrew Chambers
344f0b743d Make hash api more future proof. 2020-01-17 17:25:40 +13:00
Calvin Rose
d8841de180 Address #188
Delete repo folder if clone fails.
2020-01-16 22:14:23 -06:00
Calvin Rose
23c7c3bf1c Allow disabling keyed hash function (prf) in conf
In some cases, one might want to disable what is currently
SipHash for speed / better security mechansims. For example, using
red black trees for caches rather than hash tables.
2020-01-16 21:06:03 -06:00
Calvin Rose
3d117804dd Merge branch 'master' into HEAD 2020-01-16 20:08:34 -06:00
Calvin Rose
77bb0ebe3f Add limits to format to discourage huge prints.
This should make system crashing prints happen less often in repl.
Instead, display a ...
2020-01-16 18:57:01 -06:00
Calvin Rose
6d9e51e4be Fix documentation for if-with.
It was the same as when-with.
2020-01-16 18:12:05 -06:00
Calvin Rose
174ff87946 Change printing of abstracts with tostring in pp
This change makes pretty printing not hide "abstractness".
2020-01-16 18:10:17 -06:00
Andrew Chambers
ea02b2fde9 Use siphash for string hashing.
The hash key still needs to randomly initialized
for the security advantage, but this patch is a
step closer to avoiding hash based DOS.

Further work may including exposing the raw hash
function for use by abstract types who also choose to
implement hash.
2020-01-17 12:06:55 +13:00
Calvin Rose
962cd7e5f5 Add when-with and if-with
This is useful for reading from files.
2020-01-15 22:56:40 -06:00
Calvin Rose
65be9ae095 Add defer and assert to the core. 2020-01-15 22:39:14 -06:00
Calvin Rose
bc2bac8cd3 Fix memory issue in allocating decode buffer.
Since the decode table is currently a single table
per thread, we just make it a thread local to avoid
issues.
2020-01-15 19:58:14 -06:00
Calvin Rose
b567ece401 Address #252
Add repeat form (instead of exactly).
2020-01-14 19:58:03 -06:00
Calvin Rose
f001b0a40c Update Changelog
Also change how add-body in jpm works. We keep an array of thunks
instead of a single thunk.
2020-01-13 20:51:11 -06:00
Calvin Rose
04579664fd update parse.c 2020-01-12 22:43:39 -06:00
Calvin Rose
f709d7eb40 Add module/add-paths
This should make it much easier to make custom DSLs work
well with the import system. No need to mess about with import paths,
 things will just work.
2020-01-12 20:59:45 -06:00
Calvin Rose
2df8660f8b Avoid buffer overrun
On very long binding names > 256 characters, a buffer overrun would be
trigger in janet_cfuns. Not a huge issue, since this is not really code
that would ever be user facing, but we can fix this.
2020-01-12 11:31:41 -06:00
Calvin Rose
a68ee7aac6 Update Copyright 2020. 2020-01-12 10:50:37 -06:00
Calvin Rose
f0e04e734c Test for regressions in #249
Use two separate natives in compiled executable.
2020-01-12 10:45:59 -06:00
Calvin Rose
0e7cf51890 Fix MSVC warnings. 2020-01-12 10:19:51 -06:00
Calvin Rose
b54d9725d8 Fix MSVC errors. 2020-01-12 10:18:03 -06:00
Calvin Rose
2f0570aad6 Address #249
If JANET_ENTRY_NAME is defined, we are compiling into a single binary.
In this case, we don't want to define the config symbol multiple times
with same name, as this causes the linker error.
2020-01-12 10:13:06 -06:00
Calvin Rose
3d40c95e80 Add ability to Janet signal from C functions.
While C functions are not re-entrant, signaling from a C function
can be used to implement async returns. When resuming a fiber that
signalled from within a C function, the fiber is started after the
instruction that emitted the signal. The resume argument is used
as the return result from the c function.
2020-01-10 20:44:16 -06:00
Calvin Rose
ed5027db5d Address #242
Synchronize critical sections in setenv/getenv/environ.
2020-01-06 22:41:18 -06:00
Calvin Rose
c4047f3f88 Merge pull request #247 from andrewchambers/getenvdflt
Optional default value for os/getenv.
2020-01-06 17:27:33 -06:00
Andrew Chambers
ec1a06cfaf Optional default value for os/getenv. 2020-01-07 11:21:05 +13:00
Calvin Rose
17e47a798c Address #244 2020-01-05 09:26:21 -06:00
Calvin Rose
212aceedc6 Fix useless type conversion. 2020-01-02 22:12:07 -06:00
Calvin Rose
e6f897f4ef Merge branch 'master' of github.com:janet-lang/janet 2020-01-02 22:10:13 -06:00
Calvin Rose
6c7f376410 Try to remove potential overflow bugs.
Also make integer to size_t casts explicit rather than relying on
int32_t * sizeof(x) = size_t. This is kind of a personal preference for
this problem.
2020-01-02 22:08:17 -06:00
Calvin Rose
e93e237c67 Merge pull request #236 from andrewchambers/scratch_calloc
Add scratch calloc.
2020-01-02 20:29:10 -06:00
Calvin Rose
a1cd759759 Merge branch 'master' of github.com:janet-lang/janet 2020-01-02 20:28:10 -06:00
Calvin Rose
a2c45a697b Address #234 in array.c 2020-01-02 20:27:38 -06:00
Andrew Chambers
acdbf8911c Add scratch calloc. 2020-01-03 12:10:17 +13:00
Calvin Rose
9269372768 Merge pull request #235 from theosotr/fix
Fix faults in Make build
2020-01-02 15:05:04 -06:00
Thodoris Sotiropoulos
5575e7577a Fix faults in Make build 2020-01-02 22:15:55 +02:00
Calvin Rose
ef02dacdb4 Update changelog. 2019-12-31 12:17:32 -05:00
Calvin Rose
c6b639b939 Add comptime error test. 2019-12-31 12:16:19 -05:00
Calvin Rose
0b0fb18c42 Can we fix NSIS? 2019-12-31 12:10:57 -05:00
Calvin Rose
b872ee024f Add test for issue #232 2019-12-31 11:36:21 -05:00
Calvin Rose
a15d841b5b Address #232
Fix segfault on macro arity mismatch in compile.c by adding missing return statements.
2019-12-31 11:33:03 -05:00
Calvin Rose
bfb638cfc2 Try EnVar_plugin for updating path.
This should be more robust and not fail after upgrading.
2019-12-31 10:26:54 -05:00
Calvin Rose
3a47ad5d99 Remove some NSIS cruft to see if we can fix 3.05 2019-12-31 09:49:50 -05:00
Calvin Rose
e3c88295f2 Update to NSIS 3.05
Lock version in appveyor.yml
2019-12-31 09:40:36 -05:00
Calvin Rose
75bb8fbcd1 Amalg script included janet.h before test macros. 2019-12-30 22:08:12 -05:00
Calvin Rose
9cb25ad7b1 Remove some feature test macros.
_BSD_SOURCE is deprecated and not needed.
2019-12-30 21:30:13 -05:00
Calvin Rose
f361830cb2 Update feature test macro in line.c 2019-12-30 20:24:40 -05:00
Calvin Rose
9dd152dc28 Add features.h for feature test macros.
Because we use an amalgated build, feature
test macros should be set in a single file that
is included before any other headers, and is placed
at the top of the amalgamated build.
2019-12-30 19:06:15 -05:00
Calvin Rose
2ba4337e6f Remove all feature test macros from janet.h
This should help improve compatibility with other C code.
2019-12-30 15:12:17 -05:00
Calvin Rose
48fcd927ab Merge branch 'master' of github.com:janet-lang/janet 2019-12-30 14:26:38 -05:00
Calvin Rose
407d8af026 Address #233
Move _POSIX_C_SOURCE to internal header.
2019-12-30 12:31:26 -05:00
Calvin Rose
d0570b55b1 Merge pull request #231 from andrewchambers/tempfile
Add file/temp.
2019-12-29 20:00:17 -05:00
Calvin Rose
a964a95c1e Fix warnings on BSDs. 2019-12-29 19:53:35 -05:00
Andrew Chambers
c2f8441572 Add file/temp. 2019-12-30 12:00:35 +13:00
Calvin Rose
099a957e6c Update macex1 to properly handle break
Things mostly worked fine, but technically
break should be handled as a special form not a function call.
2019-12-29 16:44:53 -05:00
Calvin Rose
a2e515ab89 Merge pull request #230 from andrewchambers/file_api
Extend file api to allow creating and checking.
2019-12-29 10:22:03 -05:00
Andrew Chambers
2bebace8eb Extend file api to allow creating and checking. 2019-12-30 04:02:46 +13:00
Calvin Rose
5142722da3 Remove aliases for deprectaed functions. 2019-12-28 17:51:05 -05:00
Calvin Rose
52dd0f132a Remove emscripten build.
Prefer using custom toolchain with amalgmated build.
2019-12-28 16:11:15 -05:00
Calvin Rose
022be217a2 Remove ==, not==, and order[<,<=,>,>=].
This unifies equality and comparison checking. Before, we had
separate functions and vm opcodes for comparing general values vs.
for comparing numbers, where the numberic functions were polymorphic and
had special cases for handling NaNs. By unfiying them, abstract types
can now better integrate with other number types and behave as keys.

For now, the old functions are aliased but will eventually be removed.
2019-12-28 16:04:15 -05:00
Calvin Rose
5528bca7a9 Version bump to dev version. 2019-12-28 11:58:40 -05:00
Calvin Rose
ae474bc8d0 Merge pull request #228 from andrewchambers/pclose
Expand docs to explain pclose semantics.
2019-12-28 08:27:16 -05:00
Andrew Chambers
ddc4274314 Expand docs to explain pclose semantics. 2019-12-28 15:24:10 +13:00
Calvin Rose
da93a73dbd Version bump to 1.6.0. 2019-12-22 12:09:56 -05:00
Calvin Rose
31f8778aa3 Fix makensis invocation. 2019-12-19 13:46:59 -05:00
Calvin Rose
0ecd74d01d Echo calculated version. 2019-12-19 13:45:38 -05:00
Calvin Rose
bd20b16a32 Capture typo. 2019-12-19 13:28:17 -05:00
Calvin Rose
933f4b9111 build_win.bat: Parse out smv of janet/version. 2019-12-19 13:25:45 -05:00
Calvin Rose
3492ed6d88 Windows installer pulls version from interpreter.
This should make version updates simpler. Also
try an make installer write to ProgramFiles instead
of ProgramFiles (x86) for 64 bit build.
2019-12-19 13:18:46 -05:00
Calvin Rose
e28262f5ab Add array/fill
This function has similar semantics to buffer/fill.
2019-12-19 12:58:11 -05:00
Calvin Rose
94246f7574 Use infinite timeout to indicate non-blocking.
Makes more sense than negative numbers.
2019-12-18 16:07:06 -05:00
Calvin Rose
07b0ef1648 Throw error on bad thread creation. 2019-12-18 15:49:57 -05:00
Calvin Rose
6a39c4b91d Pass thread body explicitly in thread/new.
Doing it via thread/send make sense, but is a bit
strange. Passing the body explicitly will make more
sense to API users.
2019-12-18 15:07:46 -05:00
Calvin Rose
b9f0f14e31 Add array/new-filled
Similar function signature to buffer/new-filled.
2019-12-18 13:02:50 -05:00
Calvin Rose
4238379552 Use _setjmp/_longjmp on BSDs.
This doesn't save the signal mask so should be a bit faster.
2019-12-18 12:18:31 -05:00
Calvin Rose
8cc43ad2d1 Fix debugger example. 2019-12-17 23:06:41 -06:00
Calvin Rose
94b472df64 Update jpm with show-paths
Update CHANGELOG.md as well.
2019-12-15 22:02:33 -06:00
Calvin Rose
2b2c1ff917 Get rid of warning on BSDs. 2019-12-15 16:04:43 -06:00
Calvin Rose
c7912249b2 Typo in #ifdef. 2019-12-15 15:56:26 -06:00
Calvin Rose
b8004555ea Start cleaning up defines in janet.h 2019-12-15 15:41:58 -06:00
Calvin Rose
58ff7f0788 BSD os.c fix with arc4random. 2019-12-15 12:47:12 -06:00
Calvin Rose
f1afc5b0b4 Address #214
This adds several common patterns, which are defined in
boot.janet. This essentially gives more primitive patterns
to work with out of the box.

Fix build when JANET_REDUCED_OS is defined.
2019-12-14 20:39:14 -06:00
Calvin Rose
bc8ee207d5 Address #219.
Adds several shorthands to the C API.
2019-12-14 11:31:46 -06:00
Calvin Rose
76342540dc Add buffer/fill. Address #221 2019-12-14 10:54:29 -06:00
Calvin Rose
56784a34a1 Address #224 - Exposed file flags in janet.h
A caller can check if a file is closed with
if (flags & JANET_FILE_CLOSED) ...
2019-12-14 09:03:56 -06:00
Calvin Rose
eca42e98f6 Update CHANGELOG.md 2019-12-12 19:39:00 -06:00
Calvin Rose
c3f1b54171 Update jpm path settings.
This will make it easier to use jpm as a per-project
management tool, as well as easier to set up individual
module trees.
2019-12-12 19:35:40 -06:00
Calvin Rose
9b7d642c38 Window x86 needs isnan. 2019-12-12 19:04:13 -06:00
Calvin Rose
f24e2f8706 Update CHANGELOG.md 2019-12-12 17:51:49 -06:00
Calvin Rose
aa7f3411f5 Use JANET_SINGLE_THREADED to disable threads. 2019-12-12 17:39:22 -06:00
Calvin Rose
5b9eda5e87 Add root-env
This makes images smaller without needing to make sure
that no references to the root environment occur in the final
image.
2019-12-12 17:25:04 -06:00
Calvin Rose
7c2ae45809 Fix some merge issues.
Make everything compile, and test-install pass.
2019-12-12 17:14:36 -06:00
Calvin Rose
36b2f27873 Merge branch 'master' into threads-3 2019-12-12 17:07:03 -06:00
Calvin Rose
b8e02afd1a Improve error messages in os.c and jpm
In os/* functions, show failed path name. In jpm, indicate
a permission issue if we can't stat the file.
2019-12-12 03:20:20 -06:00
Calvin Rose
0fc36aa5d0 Signal to pending threads more often. 2019-12-12 02:19:56 -06:00
Calvin Rose
38f7e256d0 Port threads code to Windows API
Can run demo in examples/threads.janet
2019-12-10 20:32:41 -05:00
Calvin Rose
4187c972a3 Switch to multiple buffers per mailbox.
Needs less copying.
2019-12-10 13:26:00 -06:00
Calvin Rose
2d5af32660 Refine typedefs. 2019-12-09 20:12:10 -06:00
Calvin Rose
e592b24333 Added some type aliases to janet.h
This should make it clearer if a pointer is really just a
plain pointer, or a pointer with a header.
2019-12-09 20:05:53 -06:00
Calvin Rose
8700a407ce Update janet_getmethod to better match new get api. 2019-12-09 18:45:05 -06:00
Calvin Rose
8ecf359bbe Merge pull request #226 from andrewchambers/abstractget
Abstract type getters can indicate key absence.
2019-12-09 18:39:40 -06:00
Calvin Rose
eb1988a5ae Update CHANGELOG.md 2019-12-09 18:26:58 -06:00
Calvin Rose
5b6dffe93d Version bump. 2019-12-09 18:04:38 -06:00
Calvin Rose
1a6eb52f11 Add protect macro.
A more functional version of try catch.
2019-12-09 17:32:02 -06:00
Andrew Chambers
57ccfb692c Abstract type getters can indicate key absence.
This change to the c api allows abstract types to indicate
to the runtime if a key was absent, or if it meant to return nil.
2019-12-09 16:50:33 +13:00
Calvin Rose
eb1c21b0da Fix some example issue and warnings under -Os. 2019-12-08 12:40:05 -06:00
Calvin Rose
66d82c4513 Add mailbox capacity for back pressure.
(thread/send thread msg &opt timeout) can now timeout. Also
changed thread/self to thread/current for better consistency with
fibers, and all blocking operations will by default timeout after 1
second. I think its bad to make things block forerver by default.
2019-12-08 12:30:30 -06:00
Calvin Rose
c9c4424261 Add thread/self. 2019-12-07 17:54:08 -06:00
Calvin Rose
131733549d Get mailbox API working. 2019-12-07 16:51:00 -06:00
Calvin Rose
ee646dadf2 Merge branch 'master' into threads-3 2019-12-07 12:14:44 -06:00
Calvin Rose
73f5314141 Work on moving to mailbox abstraction.
Should be more efficient in the common case.
2019-12-07 12:14:16 -06:00
Calvin Rose
4c5734c2ee Update CHANGELOG.md 2019-12-07 10:35:40 -06:00
Calvin Rose
546669082f New unmarshal proposal.
Gives more control over unmarshalling
abstract types. This should also
make it possible/easy to write abstract types that cannot
cause unmarshal to segfault.
2019-12-06 22:12:18 -06:00
Calvin Rose
4a0ee5df7d Address #215
Also update docs for module/expand-path.
2019-12-06 19:54:11 -06:00
Calvin Rose
4de6c2ad61 Address #211
Scripts run from the command line will automatically
call a main function if it exists.
2019-12-06 19:14:12 -06:00
Calvin Rose
1fa7e73c58 Address #218
Quote output to :lfags in meta data.
2019-12-06 18:45:29 -06:00
Calvin Rose
0e690b4fa0 Add timeout to thread/receive.
If provided, throws an error if no message is received before
timeout. Perhaps should return nil?.
2019-12-06 09:21:36 -06:00
Calvin Rose
c804ae9f7c Update threads.c to avoid a deadlock. 2019-12-06 01:46:23 -06:00
Calvin Rose
dbcceefc20 Fix bad merge. 2019-12-04 22:41:30 -06:00
Calvin Rose
1a4035b02c Merge branch 'master' into threads-3 2019-12-04 22:39:30 -06:00
Calvin Rose
e908029392 Work on thread/receive doubling as select. 2019-12-04 22:31:01 -06:00
Calvin Rose
fd4220f254 Keep single global pthread_cond_t per thread.
This will allow thread/select to be implemented.
Also add thread/close and close method to threads.
2019-12-04 21:44:53 -06:00
Calvin Rose
de6c3d6d70 Simplify structure JanetThread and JanetChannel.
Remove JanetThreadShared.
2019-12-04 21:04:43 -06:00
Calvin Rose
77cb823719 Update CHANGELOG.md 2019-12-04 20:02:15 -06:00
Calvin Rose
49954c7a30 Remove top-level unquote for comptime macro
True top level unquote currently requires basically double compilation
as it currently stands. Also, implementing such double compilation
looses all source mapping information. This is a compromise
implementation that makes it clear that this works differently than
a true top-level unquote.
2019-12-04 19:53:13 -06:00
Calvin Rose
11a7a7069a Update CHANGELOG.md 2019-12-04 18:46:36 -06:00
Calvin Rose
2487162ccf Add top level unquote and macro envs.
This improves macros that eval their arguments and
makes them easier to write.
2019-12-04 18:39:13 -06:00
Calvin Rose
8ca10f37bd Update CHANGELOG.md 2019-12-04 16:51:34 -06:00
Calvin Rose
4199c42fe2 Add support for nested quasiquotation.
This brings Janet more in line with Scheme,
Common Lisp, and Clojure.
2019-12-04 16:40:53 -06:00
Calvin Rose
f39cf702db Address #212 - don't include janet args in script args. 2019-12-04 08:30:36 -06:00
Calvin Rose
db9e431bf7 Address #213 - disallow non-indexed ds for loop range. 2019-12-04 08:18:54 -06:00
Calvin Rose
328454729e Add nan? 2019-12-03 21:24:22 -06:00
Calvin Rose
73a4c395d2 Address #190
We don't ever invoke ld directly, so ignore --linker on non-windows.
For --compiler and --archiver, default to $CC and $AR. These are
overshadowed by CLI flags or settings in project.janet.
2019-12-03 21:00:59 -06:00
Calvin Rose
70328437f1 Add math/rng-buffer.
Allow math/seedrandom to use buffer as seed.
2019-12-03 20:33:21 -06:00
Calvin Rose
600bed9f6d Merge pull request #209 from andrewchambers/cryptorand2
Add os/cryptorand.
2019-12-03 19:12:32 -06:00
Calvin Rose
55eca44c54 Merge pull request #210 from andrewchambers/unhandled_buffer_get
Handle missing get case.
2019-12-03 19:07:44 -06:00
Andrew Chambers
0ac5b243c7 Add os/cryptorand. 2019-12-04 14:02:37 +13:00
Andrew Chambers
9911c90b1d Handle missing get case. 2019-12-04 13:58:21 +13:00
Calvin Rose
a1f35e21c7 Merge branch 'master' into threads-3 2019-12-03 18:11:32 -06:00
Calvin Rose
9ccdab0bc7 Merge pull request #208 from andrewchambers/explain_why
Explain the logic behind negative slice indices.
2019-12-03 10:42:46 -05:00
Andrew Chambers
a20e956f6d Explain the logic behind negative slice indices. 2019-12-03 22:05:43 +13:00
Calvin Rose
59668133a2 Merge pull request #206 from andrewchambers/unkown
Fix typo.
2019-12-03 03:34:46 -05:00
Andrew Chambers
73db8584e0 Fix typo. 2019-12-03 21:14:00 +13:00
Calvin Rose
cecc7e6b9d Rename 'get' opcode to 'in', add new 'get' opcode.
This makes the names of the opcodes match their implied functionality.
We also rename the C functions to match the opcodes and source level
functionality.
2019-12-02 21:26:28 -06:00
Calvin Rose
3a14aad615 Address issue #205. 2019-12-02 18:34:08 -06:00
Calvin Rose
8368e55151 Merge branch 'master' into threads-3 2019-12-02 17:49:39 -06:00
Calvin Rose
ac85fca8a1 Fix warnings for appveyor. 2019-12-02 09:07:49 -06:00
Calvin Rose
e5fbe5c557 Change printf to add trailing newlines.
Also add prinf and eprinf for old behavior. This
is consistent with the naming of print and prin.
2019-12-02 04:45:03 -06:00
Calvin Rose
474bcd50a1 Add methods to threads. 2019-12-02 04:39:13 -06:00
Calvin Rose
70c8b6838d Use make-image-dict and load-image-dict in thread/new
Rather than messing with janet_core_dictionary, we
instead cache the core enevironment, and pull out the
needed tables from there. This is more flexible, more correct, and
also exposes janet_resolve_core, which can be easily used from the C
API.
2019-12-02 04:15:22 -06:00
Calvin Rose
212479188a Have separate encode and decode dicts for threads
This is more correct and mirrors the way marshal -> unmarshal works.
2019-12-01 21:53:39 -06:00
Calvin Rose
5b1e59b535 Merge branch 'master' of github.com:janet-lang/janet into threads-3 2019-12-01 21:26:22 -06:00
Calvin Rose
779d788efa Merge pull request #204 from andrewchambers/get_permissive
New capi janet_get_permissive
2019-12-01 22:06:44 -05:00
Andrew Chambers
6233d804c8 New capi janet_get_permissive
The janet_get_permissive function implements the core semantics
of the 'get' function. The original janet_get implements the semantics of
the 'in' function and also the OP_GET opcode. This slight oddity is
to avoid a backwards incompatible change.
2019-12-02 15:49:51 +13:00
Calvin Rose
8f31a53276 Add thread example.
Also remove reference to pthread_t in the JanetThread structure.
2019-12-01 20:47:22 -06:00
Calvin Rose
6a763aac95 Work on threads.
Add send and receive.
2019-12-01 20:28:12 -06:00
Calvin Rose
5cd6580c2d Merge branch 'threads-3' of github.com:janet-lang/janet into threads-3 2019-12-01 20:25:57 -06:00
Calvin Rose
81a2af700a Merge pull request #201 from andrewchambers/in_docs
Update documentation for in and get builtins.
2019-12-01 20:49:47 -05:00
Andrew Chambers
8a58be81ba Update documentation for in and get builtins.
Try to clarify documentation and teach users the correct
way to read the 'in' so it is less likely to be confused
with python's usage of the keyword.
2019-12-02 12:35:54 +13:00
Calvin Rose
fc53445d08 Merge pull request #198 from andrewchambers/intprint
Integers convert to plain number strings.
2019-12-01 13:00:09 -05:00
Calvin Rose
db261aabf4 Fix bad integer printing range. 2019-12-01 09:46:20 -05:00
Calvin Rose
36ef1c4749 Print proper integers as integers. 2019-12-01 09:40:34 -05:00
Andrew Chambers
5ae520a2c9 Integers convert to plain number strings.
A user can use (type n) to find the true type, the old behavior did not
seem useful for most uses of the string function.
2019-12-01 23:10:52 +13:00
Calvin Rose
8e31bda8f6 Fix issue #189 2019-11-30 21:54:23 -05:00
Calvin Rose
474aed8cfe Merge branch 'master' of github.com:janet-lang/janet 2019-11-30 21:34:38 -05:00
Calvin Rose
0509376aea Merge pull request #193 from andrewchambers/truthy
Add truthy? to core.
2019-11-30 21:32:14 -05:00
Calvin Rose
570f04ca05 Fix typo. 2019-11-30 21:27:36 -05:00
Andrew Chambers
ded08b6e1e Add truthy? to core. 2019-12-01 14:34:41 +13:00
Calvin Rose
f3c0d9115f Fix calling jpm quickbin binary with no arguments. 2019-11-30 15:11:34 -05:00
Calvin Rose
bf609445c1 Merge pull request #186 from quexxon/fix-array-ensure-documentation
Add missing documentation for array/ensure's growth parameter
2019-11-29 22:39:04 -05:00
Calvin Rose
13ef2bd905 Merge pull request #185 from andrewchambers/afl
Add afl fuzzing helpers.
2019-11-29 22:36:47 -05:00
Calvin Rose
4e4cdb6356 Run formatter. 2019-11-28 23:26:11 -05:00
Calvin Rose
688d297a18 Address Issue #184.
Fix strtod.c with better range checking to prevent DOS.
2019-11-28 23:23:37 -05:00
Will Clardy
9e1c3e0f41 Add missing documentation for array/ensure's growth parameter 2019-11-28 23:16:32 -05:00
Andrew Chambers
4acc63e325 Add afl fuzzing helpers. 2019-11-29 16:43:14 +13:00
Calvin Rose
967a8b5a70 Merge pull request #183 from andrewchambers/environ
Add os/environ.
2019-11-28 21:33:43 -05:00
Calvin Rose
92b7d91697 Merge pull request #182 from andrewchambers/scratch_finalizer
Add an optional finalizer to scratch resources.
2019-11-28 21:07:42 -05:00
Andrew Chambers
07db4c530e Add os/environ. 2019-11-28 19:00:52 +13:00
Andrew Chambers
a3fb2d6e0a Add an optional finalizer to scratch resources.
A finalizer can be attached to scratch allocations efficiently at any point in
it's lifecycle via janet_sfinalizer. Care was taken to keep allocations aligned
with  platform alignment requirements.

A big drawbacks to this approach is the waste of up to 16 bytes per scratch
allocation in the case the scratch memory does not require a finalizer.
2019-11-28 17:32:12 +13:00
Calvin Rose
5b9e37e2cc Merge pull request #181 from andrewchambers/fileno
Add missing fileno method to file, sort method list.
2019-11-27 21:06:30 -05:00
Andrew Chambers
88f28773da Add missing fileno method to file, sort method list. 2019-11-28 14:47:16 +13:00
Calvin Rose
66e6979812 Add thread flags to standalone executables. 2019-11-27 15:06:31 -06:00
Calvin Rose
8a91c52fa2 Change pthreads linking with jpm, make, and meson.
Try to add pthread deps when compiling programs with jpm.
2019-11-27 14:52:20 -06:00
Calvin Rose
e542ba7e4d Fix amalg build. 2019-11-27 12:43:45 -06:00
Calvin Rose
bca0392738 First work on threading.
Posix only, needs to be disabled on windows. Also
the Makefile needs to be configurable, and meson.build
needs to take pthreads into account.
2019-11-26 23:13:53 -06:00
Calvin Rose
74d51ab08b Address issue #180 - string/check-set
Fix the function and add test to further clarify that
implementation is correct. Also fix empty string case.
2019-11-25 20:33:16 -06:00
Calvin Rose
6bc400eb8c Update CHANGELOG.md 2019-11-25 20:11:10 -06:00
Calvin Rose
7df0ec6aed Fix up debug/step and janet_step.
Also allow debugging on all signals, including errors.
This is gated behind (setdyn :debug true) in the repl.
2019-11-25 20:00:13 -06:00
Calvin Rose
a0a980e0ef Update sample debugger.
Add .break and .step.
2019-11-25 18:21:53 -06:00
Calvin Rose
6988fd3cab Add debug/step to single step a fiber.
Very useful for implementing debuggers.
2019-11-25 18:14:34 -06:00
Calvin Rose
c3273e8751 Merge branch 'master' of github.com:janet-lang/janet 2019-11-24 17:54:14 -06:00
Calvin Rose
d37c43716a Lots of work on improving debugging.
doc macro can take no arguments and print out
all bindings. Fix an issues with the vm skipping
over a breakpoint in some situations.

Add examples/debugger.janet for proof of concept
debugger.
2019-11-24 17:45:53 -06:00
Calvin Rose
1bf751367b Merge pull request #177 from andrewchambers/parse_review
Minor fixes for parser.
2019-11-23 14:23:57 -05:00
Andrew Chambers
976dfc7195 Minor fixes for parser
Check length before dereferencing buffer in tokenchar.
Check keywords are valid utf-8.
Fix minor typos.
2019-11-24 08:19:04 +13:00
Calvin Rose
8372d1e499 uint32_t -> uint8_t 2019-11-21 23:31:35 -06:00
Calvin Rose
e65716f6ee Add janet_rng_longseed to janet.h 2019-11-21 23:26:31 -06:00
Calvin Rose
4b24d77b2c Switch back to well tested RNG. 2019-11-21 23:22:21 -06:00
Calvin Rose
02fc4ae27b Allow seeding RNG with a byte sequence. 2019-11-21 22:53:39 -06:00
Calvin Rose
624f5f428e Add a number of math functions.
Most of these functions are wrappers around math.h.
2019-11-17 10:54:44 -06:00
Calvin Rose
5171dfd2a8 Fix docstring. 2019-11-16 20:43:21 -06:00
Calvin Rose
8ff5e49d1f Merge pull request #176 from staab/repl-delete
Add support for delete key in repl
2019-11-16 21:42:38 -05:00
Jon Staab
134163708a Fix formatting 2019-11-16 16:07:15 -08:00
Jon Staab
40e6616df0 Add support for delete key in repl 2019-11-16 16:01:52 -08:00
Calvin Rose
bcd2089f71 Version 1.5.1 2019-11-16 17:17:13 -06:00
Calvin Rose
7553b277db Fix return value of update. 2019-11-16 15:50:21 -06:00
Calvin Rose
d71cf093bb Add /i switch to xcopy in jpm 2019-11-12 02:51:37 -05:00
Calvin Rose
86d21816b6 Fix jpm mendoza install on windows. 2019-11-12 02:45:20 -05:00
Calvin Rose
c9521e093e Fix windows issue with (file/read file :all)
When file was created with file/popen, the current optimization
of using fseek on windows fails due to windows not properly returning
and error code and just returning 0. Windows :(.
2019-11-11 20:05:00 -05:00
Calvin Rose
16f6261b44 Improve randomness of numbers from new rng.
First few numbers are very biased.
2019-11-10 17:44:59 -06:00
Calvin Rose
6b76ac3d18 Fix bug when appending buffer to self.
janet_to_string_b had a bug when printing buffers.
2019-11-10 14:57:09 -06:00
Calvin Rose
5681e02e0f Update deployment and fix changelog. 2019-11-10 11:30:31 -06:00
Calvin Rose
41a22f258e Fix appveyor.yml to build windows installer. 2019-11-10 11:12:28 -06:00
Calvin Rose
0d2844b7c9 Update to 1.5.0 2019-11-10 10:57:18 -06:00
Calvin Rose
719f7ba0c4 Default to UTC for date. 2019-11-09 16:57:21 -06:00
Calvin Rose
44ed2c6b47 Tag artifacts with platform name. 2019-11-09 16:20:52 -05:00
Calvin Rose
c9292ef648 Use /MD on windows.
Just makes things easier. Assume machines have msvcrt.dll
on them. If not, we can add msvcrt.dll to the dist folder and add to
installer.
2019-11-09 16:05:07 -05:00
Calvin Rose
135abff100 Try again with vcvarsall.bat 2019-11-09 13:29:01 -05:00
Calvin Rose
7252db1e63 Try 32 bit and 64 bit builds for windows. 2019-11-09 13:25:57 -05:00
Calvin Rose
05e3fd3cc6 Fix build_win. 2019-11-09 13:22:07 -05:00
Calvin Rose
6f1b03b67e Fix build_win test-install.
On failure, cd back to original directory.
2019-11-09 11:28:40 -05:00
Calvin Rose
dca247f01d Fix MSVC build warnings. 2019-11-09 10:12:40 -06:00
Calvin Rose
63e7ca4623 Fix warning on travis CI with Clang. 2019-11-09 10:10:07 -06:00
Calvin Rose
75d21d9f45 Update CHANGELOG.md 2019-11-09 10:05:29 -06:00
Calvin Rose
8911daaf6c Add --test flag to jpm.
Also test some select packages when testing installation.
This is used in CI to make sure that versions of Janet work with
the most libraries.
2019-11-09 10:03:56 -06:00
Calvin Rose
1f55d40a10 Fix janet_opt* api.
Inverted conditional made behavior incorrect. These
were not used in the core library, so were not tested.
2019-11-09 09:39:14 -06:00
Calvin Rose
6591e7636d Copy janetconf to build for amalg target.
This makes testing the amalg easier.
2019-11-08 20:36:16 -06:00
Calvin Rose
c12eaa926a Make sure $prefix/lib/janet is created
After we removed cook.janet, jpm didn't work well out of the box
with a meson install.
2019-11-08 18:43:53 -06:00
Calvin Rose
0e464ded3d Fix meson.build typo. 2019-11-08 18:26:43 -06:00
Calvin Rose
aee1687215 Add RNG functionality to the math/ module.
The new RNG wraps up state for random number generation, so
one can have many rngs and even marshal and unmarshal them.
Adds math/rng, math/rng-uniform, and math/rng-int.

Also introduce `in` and change semantics for
indexing out of range. This commit enforces stricter
invariants on keys when indexing via a function call
on the data structure, or the new `in` function.

The `get` function is now more lax about keys, and will
not throw an error when a bad key is used for a data structure, instead
returning the default value.
2019-11-08 17:40:04 -06:00
Calvin Rose
58e3e63a89 Add jpm to release bundle. 2019-11-08 11:00:12 -06:00
Calvin Rose
9b605b27bd Address #174 - fix string/trim 2019-11-08 08:47:37 -06:00
Calvin Rose
c5010dffb4 Print error message on bad CLI usage.
This was a small regression when bundling cli-main
into boot.janet.
2019-11-05 12:51:15 -06:00
Calvin Rose
026f26f05f Improve error message in slice functions.
Check the first argument before trying to do range
checks.
2019-11-05 09:41:30 -06:00
Calvin Rose
cf2d3861d6 Make slice a c function.
This will allow future integration into the compiler
for more general destructuring.
2019-11-05 09:29:32 -06:00
Calvin Rose
6ceaf9d28d Add with-vars
This helps for temporarily setting vars in a safe
manner that is guaranteed not to leave vars in a bad state
(assuming that a fiber does not emit debug or use signal and
 is never resumed).
2019-10-31 21:58:43 -05:00
Calvin Rose
25a9804d91 Fix build_win test-install 2019-10-29 20:40:09 -05:00
Calvin Rose
cf19cd5292 Add the quickbin command to jpm.
This is useful for making one off executable scripts
without needing to set up a project.janet file.
2019-10-29 20:33:18 -05:00
Calvin Rose
03824dd9f7 Update CHANGELOG.md 2019-10-29 19:41:48 -05:00
Calvin Rose
280dca3998 Add shell.c to the amalgamation.
This allows easy builds of the full interpreter with no
build system.

  1. Get janet.c, janet.h, janetconf.h, and shell.c in a directory. Edit
     janetconf.h as desired.
  2. gcc shell.c janet.c -lm -ldl -O2 -o janet (on GNU-Linux for example)
  3. ./janet -h (Yay!)
2019-10-29 19:18:44 -05:00
Calvin Rose
46e09e4c71 Fix tools/removecr.janet 2019-10-29 18:56:32 -05:00
Calvin Rose
427b2638e0 Fix startup environment. 2019-10-29 18:47:54 -05:00
Calvin Rose
2541806dc1 Fix suite7 failing when run with no docstrings. 2019-10-29 18:28:41 -05:00
Calvin Rose
0d16b9e1a1 Move init.janet into cli-main in boot.janet
This makes it easier to get the CLI functionality when
embedding Janet, although the main reason is the init script
is now pre-compiled to bytecode when generating the boot image.
2019-10-29 18:16:32 -05:00
Calvin Rose
b2263ed5b5 Update CHANGELOG.md 2019-10-29 17:52:41 -05:00
Calvin Rose
45c2819068 Improve flychecking.
Flychecking will now work correctly with arity checking, and
will better handle imports. Well structured modules should interact
cleanly with the flychecker in a mostly safe manner, but maliciously
crafted modules can execute arbitrary code. As such, the flychecker is
not a good way to validate completely untrusted modules.

We also extend run-context with an :evaluator option to replace
:compile-only. This is more flexible and allows users to create their
own flychecker like functionality.
2019-10-27 16:15:41 -05:00
Calvin Rose
d28925fdab Relax type checking when fuction position is nil
This lets the flychecker work as expected.
2019-10-24 15:17:19 -05:00
Calvin Rose
9097e36ea0 [] should evaluate to ()
This is consistent with most bracket tuples.
2019-10-20 14:06:28 -05:00
Calvin Rose
99ef4c7510 Fix an issue with the removecr script 2019-10-19 19:11:13 -04:00
Calvin Rose
b9e05d06fe Update amalg step. 2019-10-19 18:00:29 -05:00
Calvin Rose
423b6db855 Fix memory leak with some string/ functions.
kmp_init leaked memory when called with an empty string.
2019-10-19 15:14:19 -05:00
Calvin Rose
bb54b940c0 Don't call fwrite with size = 0 2019-10-19 10:51:11 -05:00
Calvin Rose
4149df1fca Update CHANGELOG.md 2019-10-19 10:35:56 -05:00
Calvin Rose
8dd8af742a Add eprintf and make printf a C function.
This allows some more optimizations when printing to
buffers or when output is disabled. It also makes printf
more consistent with print and prin (Same with eprintf).
2019-10-19 10:30:29 -05:00
Calvin Rose
d47804d222 Add prin, eprint, and eprin functions.
The print family of functions now writes output
to an optional buffer instead of a file bound to :out.
This means output can be more easily captured an redirected.
2019-10-19 09:44:27 -05:00
Calvin Rose
8dd322c0be Fix webclient. 2019-10-14 20:55:04 -05:00
Calvin Rose
7fd0748c19 Update to 1.4.0 2019-10-14 20:35:13 -05:00
Calvin Rose
655d4b3aad Fix test. 2019-10-13 08:00:43 -05:00
Calvin Rose
5f51476526 Remove a git attribute for linguist. 2019-10-12 22:03:34 -05:00
Calvin Rose
d47b5f8c6a Update CHANGELOG.md 2019-10-11 00:11:19 -05:00
Calvin Rose
a18a251d16 Address some issues found in lgtm
Caught a few potentially issues with overflows, as well as use of
unsafe function localtime.
2019-10-10 22:59:43 -05:00
Calvin Rose
8ee54e887f Update changelog. 2019-10-10 19:06:16 -05:00
Calvin Rose
088c926196 Add update-pkgs to jpm.
This allows for periodically updating the package listing.
2019-10-10 18:46:24 -05:00
Calvin Rose
54b66a4199 Add shorthand package name support in jpm.
Package installation checks in the package listing if
the package name is not a url. The package listsing can be specified
via switch or env variable.
2019-10-10 18:11:45 -05:00
Calvin Rose
f9d57103f4 Improve peg error on unknown rule.
This helps a lot when debugging large, failing grammars.
2019-10-09 17:59:48 -05:00
Calvin Rose
f780df0aa6 Fix single threaded build option with meson.
By default, was building with the opposite of what was provided.
2019-10-05 20:35:11 -05:00
Calvin Rose
fede40f279 Relax requirement minimum arity of fn
A valid `fn` special could have only a parameter list, as
recommended by R. DuPlain.
2019-10-05 11:53:30 -05:00
Calvin Rose
6ae5a9be60 Add -fvisibility in Makefile, provide meson example commands.
Shaves off 10 kb in binary. Also -fpic -> -fPIC in Makefile and jpm.
2019-10-05 10:38:58 -05:00
Calvin Rose
e9f3dc7d5c Add varfn. 2019-10-03 20:20:42 -05:00
Calvin Rose
841b58042f Merge pull request #168 from Crestwave/haiku
Fix installation on Haiku
2019-10-02 13:54:03 -04:00
Crestwave
63e3e02a39 Fix installation on Haiku 2019-10-02 05:52:55 +00:00
Calvin Rose
944347e828 Fix formatting.
Run make format.
2019-09-30 20:00:29 -05:00
Calvin Rose
7910a5feef Add compile time arity checking.
This should help catch a number of errors, but it
is a very shallow implementation of type checking. It will
catch some common misuses of functions at compile time
rather than runtime.
2019-09-30 19:50:42 -05:00
Calvin Rose
2becd196dd Fix incomplete error message. 2019-09-25 09:29:29 -05:00
Calvin Rose
bcb45157a8 Update CHANGELOG.md 2019-09-24 21:25:21 -05:00
Calvin Rose
70ffe3b6bd Add slice function to core.
Returns immutable slices.
2019-09-24 19:44:36 -05:00
Calvin Rose
339dea9390 Add optional argument functions to c api.
These are just helpers to make parameters than can be nil with a
default value easier to handle in a consitent way.
2019-09-24 19:40:49 -05:00
Calvin Rose
b26a7bb22a Disallow the empty string for some string fns.
This will prevent these functions from being run
with empty strings, which usually produces useless
output, as the internal string search algorithm will
never "find" empty strings. This is by design, as it is
not always obvious which empty strings should be found in
the search text.
2019-09-24 13:23:18 -05:00
Calvin Rose
45dfc7cc96 Fix debug/break search algorithm. 2019-09-22 18:08:38 -05:00
Calvin Rose
9d020c3ec5 Update CHANGELOG.md 2019-09-22 18:00:53 -05:00
Calvin Rose
8cda06b995 GCC seemed to not fill array of computed gotos.
This is expected as per the C standard, but segfaulted
unless all 255 labels were added.
2019-09-22 17:56:33 -05:00
Calvin Rose
a8afc5b81f Sourcemapping uses line, column instead of offsets.
This should be friendlier to most users. It does, however, mean
we lose range information. However, range information could be
recovered by re-parsing, as janet's grammar is simple enough to do this.
2019-09-22 17:18:28 -05:00
Calvin Rose
228d045a06 Fix formatting. 2019-09-22 15:17:06 -05:00
Calvin Rose
c447e7b3a5 Update changelog. 2019-09-22 15:15:28 -05:00
Calvin Rose
803c3fc235 Add line, col to error messages when available. 2019-09-22 15:13:21 -05:00
Calvin Rose
a032529437 Let jpm projects work better on windows.
Handle paths with normal, forward slashes better.
2019-09-22 14:01:14 -04:00
Calvin Rose
7bee204390 Fix installer. 2019-09-22 13:29:34 -04:00
Calvin Rose
064a700edd Merge branch 'master' of github.com:janet-lang/janet 2019-09-22 12:54:50 -04:00
Calvin Rose
7809f89dfc 1.3.1 Release
Small changes, mostly just fixing minor bugs.
2019-09-21 19:15:02 -05:00
Calvin Rose
940860755c jpm: Read :lflags from meta file when linking.
Let us link in native code that itself neads to be linked
to native code when creating standalone executables.
2019-09-21 18:57:04 -05:00
Calvin Rose
1b283c47b4 Remove macos update_dyld_shared_cache
This just doesn't work well for a non global install.
It is better packages that need this to run it themselves.
2019-09-20 13:13:05 -05:00
Calvin Rose
8e427317cd Add mean function to boot.janet
Update changelog.
2019-09-19 21:21:14 -05:00
Calvin Rose
908a3b6f5c Address #160: Use ldconfig alternative on macos.
update_dyld_shared_cache seems to work on macos.
2019-09-18 12:20:59 -05:00
Calvin Rose
f2ba91899f jpm test now starts a new interpreter per test.
This should help with setup/teardown semantics, especially
with native modules.
2019-09-16 00:48:35 -05:00
Calvin Rose
16127fc55c Remove printf in regalloc.c
This should never be hit unless there is a
bug in the compiler, but should be removed.
2019-09-15 18:17:43 -05:00
Calvin Rose
97d874f16b Fix small compiler bug (not freeing temp register). 2019-09-15 13:27:49 -05:00
Calvin Rose
8aba5e76ae Sort files when running tests. 2019-09-14 19:39:14 -05:00
Calvin Rose
0e7144f2dc Add :headers option to build recipes
This lets recipes do better change detection.
2019-09-14 12:40:01 -05:00
Calvin Rose
9f48c3e2db Remove :r from amalg.janet 2019-09-12 23:34:14 -05:00
Calvin Rose
e6306ea188 Add script for removing <CR> on windows.
This caused bad stuff to be generated on windows, specifically
the amalg file. We cause totally strip <CR> from files on windows
using this script.
2019-09-12 23:18:52 -05:00
Calvin Rose
0e99d8d80f Merge pull request #167 from ato/patch-1
Correct old name all-symbols to all-bindings in README
2019-09-10 23:21:58 -04:00
Alex Osborne
de5cd73cd7 Correct old name all-symbols to all-bindings 2019-09-11 12:05:41 +09:00
Calvin Rose
b585d19519 Merge pull request #164 from AlbertoGP/master
Defuse tarbomb: wrap tar file contents in directory, fix #163
2019-09-09 19:16:43 -04:00
Alberto González Palomo
8753d2dcb8 Defuse tarbomb: wrap tar file contents in directory
https://en.wikipedia.org/wiki/Tar_(computing)#Tarbomb
http://www.linfo.org/tarbomb.html
2019-09-09 18:59:29 +02:00
Calvin Rose
39f1d81fd4 Use :length method for (length abstract)
Also adds the janet_lengthv API call. This is
needed because janet_length returns a 32 bit integer, where
as lengthv lets us return larger values (useful for typed arrays).

janet_mcall is an api function that should make it easier to call
a janet method from C code. It shares a similar signature with
janet_call.
2019-09-08 19:26:16 -05:00
Calvin Rose
fcd203c646 Merge branch 'master' of github.com:janet-lang/janet 2019-09-05 21:10:50 -04:00
Calvin Rose
4ebb749131 Update appveyor configuration. 2019-09-05 19:43:06 -05:00
Calvin Rose
37a943d9b5 1.3.0 Release 2019-09-05 19:33:08 -05:00
Calvin Rose
2f2b875c2a Update CHANGELOG.md 2019-09-05 13:21:17 -05:00
Calvin Rose
99f147219a Add put-in. 2019-09-05 13:19:25 -05:00
Calvin Rose
7a13d24e6f Add get-in, update-in, and freeze to core. 2019-09-05 13:11:53 -05:00
Calvin Rose
8dc91755f7 Work on makefile and build for jpm.1 2019-09-05 12:28:11 -05:00
Calvin Rose
96a3104fe2 Update to 1.3.0, add jpm.1 2019-09-04 23:44:23 -05:00
Calvin Rose
97f525d069 Update CHANGELOG.md 2019-09-01 11:37:43 -05:00
Calvin Rose
4ad1bdec15 Add jpm run and jpm rules 2019-09-01 11:26:48 -05:00
Calvin Rose
530d94a4b9 Allow relative paths for jpm commands (deps)
Also default headerpath, libpath, and binpath of
of (dyn :syspath) instead of $JANET_MODPATH. This
allows setting $JANET_MODPATH without needing to
mess with the other settings.
2019-09-01 11:08:39 -05:00
Calvin Rose
141d3e9588 Add option for using tags in jpm deps. 2019-08-30 18:23:13 -05:00
Calvin Rose
98eaadf2d1 Simplify peg caching further.
Remove the multiple caching tables we were using
and use the grammar table for caching. This works
well because we can use raw_get for checking the local cache, and normal
get fro checking the global cache.
2019-08-30 08:57:45 -05:00
Calvin Rose
54a04b5894 Fix some more recursion issues with pegs.
A keyword reference only counts as visited if we have
it as cached in the memoized->table, and we know it was
originally referenced from the same grammar table. If these
two conditions are true, then compilation must work correctly.

Also add janet_table_get_ex.
2019-08-29 19:56:04 -05:00
Calvin Rose
8bc8709d0e Try to address memoization problem in pegs. 2019-08-29 19:09:43 -05:00
Calvin Rose
730080e6fd Get rid of robocopy nonsense.
xcopy works fine, just need /s flag.
2019-08-29 02:57:47 -04:00
Calvin Rose
d4b49cd622 Windows fixes for jpm. 2019-08-29 02:02:05 -04:00
Calvin Rose
7e0586cb55 Fix test-install on windows. 2019-08-28 23:50:15 -04:00
Calvin Rose
05695a35c7 Fix test-install after removing cook. 2019-08-28 21:05:34 -05:00
Calvin Rose
58ffb9d7a5 Remove cook and path from default install
Instead, combine cook into jpm so we can manipulate
JANET_PATH without messing with jpm. path was moved to
and external repository, https://github.com/janet-lang/path.git
2019-08-28 20:54:31 -05:00
Calvin Rose
7eb487d998 Merge branch 'master' of github.com:janet-lang/janet 2019-08-27 18:11:22 -05:00
Calvin Rose
f903ee8acc Add quotes and remove input path as make target.
Make doesn't handle that or auto escape that very well, so
we only put known paths as Make targets.
2019-08-27 18:10:03 -05:00
Calvin Rose
91cbe2e22c Add quotes to shim if install-dir has spaces. 2019-08-25 17:18:01 -04:00
Calvin Rose
c45bad9437 Better shim for scripts on windows.
Arguments should be passed in properly.
2019-08-25 17:16:44 -04:00
Calvin Rose
4aa6afbf47 Fix binscripts on windows. 2019-08-25 16:54:54 -04:00
Calvin Rose
29054e8072 Update changelog. 2019-08-24 23:43:51 -04:00
Calvin Rose
060d11e4c2 Add Q and q formatters to buffer/format.
These are similar to P and p, but print values
on a single line for a much more compact version.
2019-08-24 22:53:45 -04:00
Calvin Rose
77870508de Update CHANGELOG.md 2019-08-24 19:06:02 -04:00
Calvin Rose
133ad0d355 Add test for longstring matcher using backmatches. 2019-08-24 19:02:55 -04:00
Calvin Rose
711fe64a51 Add backmatch operator to pegs.
(backmatch [tag?]) is similar to a back reference in regular expressions
(NOT to backwards capture in a peg). It only matches a pattern if
it exactly matches the text of the last capture. It does not consume
or push any captures to the capture stack.
2019-08-24 18:57:01 -04:00
Calvin Rose
78b5c94cb0 jpm updates.
Add better error message if no c compiler detected on windows.
2019-08-24 17:36:50 -04:00
Calvin Rose
95266bdcf8 fix git submodule update command with :p flag 2019-08-23 08:57:41 -05:00
Calvin Rose
b78879dc18 missing closing paren 2019-08-23 08:40:11 -05:00
Calvin Rose
5d29079393 Merge branch 'master' of github.com:janet-lang/janet 2019-08-23 08:35:37 -05:00
Calvin Rose
b052a57fc8 Add error message when dep fails to build. 2019-08-23 08:35:18 -05:00
Calvin Rose
292be33b9d Fix some stack overflow bugs. 2019-08-19 01:19:51 -04:00
Calvin Rose
0360942942 Add build commit hash to windows build from appveyor. 2019-08-18 21:01:47 -04:00
Calvin Rose
c35d6d2396 More batch syntax issues. 2019-08-18 20:27:26 -04:00
Calvin Rose
1c73d8ce2b Remove some parens 2019-08-18 20:19:50 -04:00
Calvin Rose
6a539df480 Make sure all appveyor artifacts get deployed 2019-08-18 20:07:12 -04:00
Calvin Rose
1de09ec149 release test 5 2019-08-18 20:02:06 -04:00
Calvin Rose
a1f785038d release-test4 2019-08-18 19:53:18 -04:00
Calvin Rose
5d475848a6 Fix appveyor.yml 2019-08-18 19:35:17 -04:00
Calvin Rose
2695f2da46 Update installer with appveyor commands. 2019-08-18 19:16:15 -04:00
Calvin Rose
3cdbf5753d Add some more artifacts to automate release. 2019-08-18 18:02:28 -04:00
Calvin Rose
daf92be5bc Better deploy test. 2019-08-18 17:54:52 -04:00
Calvin Rose
79bbb0ee1c Appveyor test2. 2019-08-18 17:05:53 -04:00
Calvin Rose
826bb1abbe Update appveyor deployment. 2019-08-18 16:54:43 -04:00
Calvin Rose
81789a6930 Add wasm to architectures returned by os/arch. 2019-08-18 10:08:52 -05:00
Calvin Rose
28fb2403d9 Add os/arch to core.
Also allow setting custom keywords for compiled
os name and architecture name.
2019-08-18 10:00:04 -05:00
Calvin Rose
1872bd344f Address #158
Use string/join to prevent stack overflow.
2019-08-18 08:41:22 -05:00
Calvin Rose
54170d92db Add some color to stacktraces in repl. 2019-08-12 19:20:01 -05:00
Calvin Rose
ec62e871dd Update to version 1.2.0. 2019-08-08 18:51:24 -05:00
Calvin Rose
4ba912cd57 Switch to 32 bit build. 2019-08-07 22:51:58 -04:00
Calvin Rose
7713674ff6 Fix appveyor.yml 2019-08-07 22:23:19 -04:00
Calvin Rose
0fce440455 See if we can use a different build of NSIS. 2019-08-07 22:19:49 -04:00
Calvin Rose
ab782d8896 Add optional default value to get.
Also update CHANGELOG.md
2019-08-06 18:12:00 -05:00
Calvin Rose
c84ddefc53 Merge pull request #156 from curist/take-and-drop
Take and drop
2019-08-06 17:35:55 -05:00
curist
5802155882 Update take/drop - while/until.
to be more consistent with take/drop
2019-08-06 15:33:55 +08:00
curist
ee8a68f7b2 Fix take/drop comments. 2019-08-06 14:25:09 +08:00
curist
61bbeebfba Update take/drop implementation.
No more preserves input type.
2019-08-06 14:19:22 +08:00
curist
18da183ef7 Add take/drop. 2019-08-06 14:00:05 +08:00
Calvin Rose
19c6714f06 Fix MSVC warnings and errors. 2019-08-05 20:19:46 -05:00
Calvin Rose
2193193b12 Improve error message on bad method calls. 2019-08-05 19:06:58 -05:00
Calvin Rose
850a2d7f79 Allow method calls on typed arrays. 2019-08-05 18:51:53 -05:00
Calvin Rose
ca5dce5d9f Address #155.
Fix bug in janet_table_clone that leaked memory.
2019-08-05 17:52:05 -05:00
Calvin Rose
40eff3e4a3 Merge pull request #153 from curist/docstring-fix
Update several docstrings.
2019-08-05 10:20:11 -05:00
curist
d334f070a3 Update several docstrings. 2019-08-05 19:58:51 +08:00
Calvin Rose
44e752d737 Add shorthand function literals to janet.
These are similar to the function literals from Clojure
(also Fennel), and should make short functions for maps, filters, etc.
easier to write.
2019-08-04 12:25:52 -05:00
Calvin Rose
5c83ebd75d Update test suites. 2019-08-03 14:56:02 -05:00
Calvin Rose
02ce3031e9 Fix comp case with arity of exactly 5. 2019-08-03 14:53:14 -05:00
Calvin Rose
2b295a5459 Exit janet if import-rules fails. 2019-08-03 14:15:45 -05:00
Calvin Rose
6caf8d3d56 Make comp create variadic functions. 2019-08-03 13:57:11 -05:00
Calvin Rose
b18f1e8127 Keep count fo allocated memory via malloc.
We normally only track memory allocated with janet_gcalloc, but
if only a few very large normal memory blocks are allocated, the GC
will never run. Se simply need to increment a count when we allocate
memory so that the next time we enter the VM, we will be able to
run a collection if needed.
2019-07-31 00:24:13 -05:00
Calvin Rose
3e67916971 Fix MSVC warning. 2019-07-28 18:44:00 -05:00
Calvin Rose
21cccc00d7 Change link order once more. 2019-07-28 18:06:55 -05:00
Calvin Rose
4809867b33 Changes to let circlet test app work.
Change cook tool linking for executables, disable
GC while constructing marhsalling codebook (mdict).
2019-07-28 17:55:37 -05:00
Calvin Rose
8bbe518696 Executables linking to natives working on linux.
This involves a bunch of machinery in cook.janet
and even a little bit in the janet C API.
2019-07-28 13:27:20 -05:00
Calvin Rose
17b4dc1fc6 Tweak man page. 2019-07-28 11:11:31 -05:00
Calvin Rose
cca19e921e Merge pull request #147 from curist/master
Update documentation
2019-07-28 12:10:34 -04:00
curist
de50a38bb1 Update man page 2019-07-28 22:19:50 +08:00
curist
c2ef58d880 Update math/log docstring 2019-07-28 22:18:36 +08:00
Calvin Rose
eafcb548ce Fix file mode. 2019-07-28 00:19:01 -05:00
Calvin Rose
ec32d11b76 Update installer and make things build on windows.
We can now build windows executables with jpm.
2019-07-28 01:05:15 -04:00
Calvin Rose
7e97687c9e Update windows installation and automation. 2019-07-27 21:44:44 -04:00
Calvin Rose
da5a64131f Progress towards making windows work again. 2019-07-27 16:16:28 -04:00
Calvin Rose
71e5278364 Remove bsd check in cook.janet. 2019-07-27 11:45:10 -05:00
Calvin Rose
d6a1faa380 Typos. 2019-07-27 11:36:48 -05:00
Calvin Rose
166862ecff Hold off on adding file associations on windows. 2019-07-27 11:34:47 -05:00
Calvin Rose
3c133bd677 Add more values for (os/which)
Some bsd flavors.
2019-07-27 11:29:40 -05:00
Calvin Rose
b0b1024f8a Try to fix some tests for CI. 2019-07-27 11:05:53 -05:00
Calvin Rose
cc07ff987d Fix normal native building and make test-install.
Add executable generation testing to make test-install.
2019-07-27 09:53:28 -05:00
Calvin Rose
efc38b87de Preemptive version bump. 2019-07-27 09:40:35 -05:00
Calvin Rose
a3a3e4c0dc Add (dyn :executable).
Also remove process/args.
2019-07-27 09:31:03 -05:00
Calvin Rose
d46bcd5b8f Update CHANGELOG.md 2019-07-26 22:47:42 -05:00
Calvin Rose
dfe00fee94 Building standalone binaries on linux working.
Mostly changes to cook and jpm. Also some
code for file associations in the windows installer, and
adding the :linux value from os/which (instead of just :posix).
2019-07-26 22:43:54 -05:00
Calvin Rose
9118f2ce08 Update CHANGELOG.md 2019-07-20 16:59:11 -05:00
Calvin Rose
a0e98b9aa8 Deprecate process/args and add use macro.
Use is a shorthand for (import module :prefix "").
process/args has been replaced by (dyn :args) at
the top level.
2019-07-20 16:57:07 -05:00
Calvin Rose
0d3986abbb Update cook and add an install test. 2019-07-19 19:40:51 -05:00
Calvin Rose
529b34d84e Fix jpm stupid bug. 2019-07-19 17:01:50 -05:00
Calvin Rose
e0fe8476aa Address issue #143
Fix some logic in module/expand-path.
2019-07-15 17:39:50 -05:00
Calvin Rose
0ca0180f27 More "correct" emscripten support. 2019-07-14 16:11:00 -05:00
Calvin Rose
21a355c89f Small changes to help with latest emscripten. 2019-07-14 09:58:11 -05:00
Calvin Rose
e528b86a2a Ensure no carriage returns end up in doc strings. 2019-07-12 09:14:37 -04:00
Calvin Rose
2e6ee39506 Fix windows build issues. 2019-07-12 08:47:11 -04:00
Calvin Rose
894877a0e3 Address issue #142
Also add janet_wrap_number_safe to API.
2019-07-12 07:23:24 -05:00
Calvin Rose
6887dd05f6 Merge pull request #139 from Barakat/master
Remove amalg.janet dependency on os/date
2019-07-09 07:39:27 -05:00
Barakat
95dbad6ec1 Remove amalg.janet dependency on os/date
When compiling Janet with `JANET_REDUCED_OS`, `os/date` will not be available which breaks the tool amalg.janet. One can check file modification time on the filesystem instead.
2019-07-09 13:49:37 +03:00
Calvin Rose
ea88ae1a5b Use paths in cache for jpm that will work on windows. 2019-07-08 21:45:51 -04:00
Calvin Rose
e8e4d637ef Fix jpm.bat on a normal install
The path to jpm.janet will likely have spaces.
2019-07-08 19:54:14 -04:00
Calvin Rose
3928136670 Begin update to 1.1.0. 2019-07-08 18:16:17 -05:00
Calvin Rose
0dcae6c3d6 Update regression test. 2019-07-07 23:23:45 -05:00
Calvin Rose
b639ccdad1 Merge branch 'master' of github.com:janet-lang/janet 2019-07-07 23:20:20 -05:00
Calvin Rose
affcb5b459 Address #137
Fix compiler bug when compiling desturctured bindings in a top-level
def or var. Also introduce janet_table_clone API call to make this
easier.
2019-07-07 23:18:39 -05:00
Calvin Rose
70c80d7899 Merge branch 'master' of github.com:janet-lang/janet 2019-07-05 14:08:58 -04:00
Calvin Rose
fb7914a3c8 Merge pull request #135 from krysros/master
Fix typo in jpm.bat
2019-07-05 12:56:10 -05:00
Krystian Rosiński
6099d2a45d Fix typo in jpm.bat 2019-07-05 19:49:55 +02:00
Calvin Rose
044fc7c461 Update jpm tool.
The jpm tool can now use git to download dependencies, install
packages from urls, and use a manifest file for better uninstalls.
2019-07-05 11:00:46 -05:00
Calvin Rose
7c4670c3de Change semantics of -l flag to be more useful. 2019-07-04 12:42:54 -05:00
Calvin Rose
c1113d61d6 Make installer correctly versioned. 2019-07-02 07:33:30 -05:00
Calvin Rose
2c4366dd71 Update some verion stuff. 2019-07-01 16:45:50 -04:00
Calvin Rose
d66f8333c1 Prepare for 1.0.0 2019-07-01 14:47:03 -05:00
Calvin Rose
1588359ebc Fix memory leak caused by casting error.
janet_abstract_end improperly modified a gc tag.
2019-06-30 10:32:52 -05:00
Calvin Rose
a861399ecb Indicate better support for Meson. 2019-06-30 09:57:49 -05:00
Calvin Rose
a7f3d3436f Update CHANGELOG.md
Also change `with-resource` to `with`.
2019-06-24 22:02:37 -04:00
Calvin Rose
75f1bb6a7c Fix up webclient. 2019-06-24 17:27:03 -04:00
Calvin Rose
0384b83c31 Update emscripten makefile. 2019-06-24 17:23:01 -04:00
Calvin Rose
c68361a03f to the top 2019-06-24 17:11:36 -04:00
Calvin Rose
0bda455cad donate 2019-06-24 17:10:27 -04:00
Calvin Rose
bb7bef7188 Add Donate link in README.md 2019-06-24 17:09:40 -04:00
Calvin Rose
b8032ec61d Add propagate function and opcode
This allows better stacktraces when manually intercepting
signals to clean up resources. Also allows functionality
from Common Lisp's unwind-protect, such as calling cleanup code
while unwindinding the stack, restarting on certain signals, and
just in general having more control over signal and signal propagation.

Also fix a bug encountered while implementing with-resource in the
compiler. Desturcturing arguments that were not the last argument
would often result in bad code generation, as slots used to destructure
the earlier arguments would invalidate the later parameters. This is
fixed by allocating all named parameters before doing any destructuring.
2019-06-24 12:44:13 -04:00
Calvin Rose
8d1e6ddffc Add reduced_os option functionality. 2019-06-24 09:40:19 -04:00
Calvin Rose
f7f2f5e84f Address #129.
Don't rm -rf the wrong directory on uninstall.
2019-06-24 08:28:40 -04:00
Calvin Rose
bedd9ccaa1 Verify working meson build on windows.
Using MSVC, no need for GNU tools.
2019-06-20 17:28:22 -04:00
Calvin Rose
a29e717fd7 Start working to a full meson build.
One build system instead of three for Make + Meson + build_win.bat.
2019-06-20 16:33:28 -04:00
Calvin Rose
522545287e Add janet_abstract_begin and janet_abstract_end
This will allow some one constructing an abstract to
only make it visible to the garbage collector after it
is in a valid state. If code in the constructing cfunction
panics before janet_abstract_end is called, the GC will not try
to mark the incomplete abstract type. This is often not needed through
careful programming, but should work well.
2019-06-20 12:37:57 -04:00
Calvin Rose
4b4fe80404 Be more complete with JANET_NO_SOURCEMAPS
This actually removed sourcemaps, not just
the top level annotation in bindings.
2019-06-20 11:55:52 -04:00
Calvin Rose
cf05ff610f Add some fixes for serializing complex grammars. 2019-06-19 23:23:27 -04:00
Calvin Rose
300124961f Change -c option to use dofile instead of require 2019-06-19 22:05:13 -04:00
Calvin Rose
7eb78c8028 Load jimage files before janet source files.
This should allow precompiled files to be placed
right next to the source files in the file system with
the expected behavior.
2019-06-19 20:18:44 -04:00
Calvin Rose
1a7691dade Flatten environment binding tables.
For some reason, these tables used prototypes. There
seems to be no need for this.
2019-06-19 20:07:40 -04:00
Calvin Rose
3b51501847 Update CHANGELOG.md 2019-06-19 19:52:41 -04:00
Calvin Rose
fc46030e7d Add options to not include docstrings in binary.
This lets us build a smaller binary. The minimal tested
binary on x86-64 (with -Os, -s, and all options that shrink binary size
        turned on) is about 240 kB.
2019-06-19 19:43:38 -04:00
Calvin Rose
ff3bb66272 Add some test cases for module/expand-path 2019-06-19 12:48:29 -04:00
Calvin Rose
1ceaceada4 Fix doc generation. 2019-06-19 09:48:33 -04:00
Calvin Rose
19a0444f41 Appease MSVC 2019-06-19 09:45:56 -04:00
Calvin Rose
0102a72538 Update module/paths for saner defaults.
Relative imports will only check the paths
directly concerning relative imports.
2019-06-19 09:01:21 -04:00
Calvin Rose
9943bdd907 Update cook.janet and jpm
They should throw better error messages when project.janet
not found.
2019-06-19 00:48:57 -04:00
Calvin Rose
264c5bc02b Change default module/path.
Disallow loading directly with extension to be more
consistent and keep things simpler.
2019-06-19 00:34:15 -04:00
Calvin Rose
9ba8728176 Update module system.
Add relative imports and path normalization. This should
help towards a more composable build/dependency system.
2019-06-18 22:10:13 -04:00
Calvin Rose
8839731951 Update changelog. 2019-06-18 15:41:48 -04:00
Calvin Rose
e88a9af2f6 Add bytecode verification for peg unmarshaling. 2019-06-18 13:01:49 -04:00
Calvin Rose
a5e50a0f65 Fix windows getline. 2019-06-18 00:04:29 -04:00
Calvin Rose
7c35acca75 One more MSVC warning. 2019-06-17 23:53:38 -04:00
Calvin Rose
4bb57550c8 Silence some windows build warnings. 2019-06-17 23:50:39 -04:00
Calvin Rose
446ab037b0 Allow marshaling pegs. 2019-06-17 23:40:02 -04:00
Calvin Rose
4adfb9f2d3 Update changelog. 2019-06-17 22:46:38 -04:00
Calvin Rose
9c89d1c658 Inline yield when called with no arguments.
It was already inline when called with one argument.
2019-06-15 12:21:08 -04:00
Calvin Rose
3598f056bb Reformat capi.c 2019-06-15 11:04:24 -04:00
Calvin Rose
779fcf2d54 Merge pull request #124 from ALSchwalm/parse-state
Add support for getting more detailed parser state
2019-06-15 11:00:06 -04:00
Adam Schwalm
3bbc121c6a Add support for getting more detailed parser state 2019-06-15 07:37:01 -05:00
Calvin Rose
82edc19137 Update cook to take headers for natives.
This should help incremental building.
2019-06-13 00:41:20 -04:00
Calvin Rose
5689ef1af1 Add keyword flag utility for modules. 2019-06-12 12:05:48 -04:00
Calvin Rose
b4e25e5597 Add some string/check-set tests. 2019-06-10 14:11:07 -04:00
Calvin Rose
647139cdf9 Fix string/check-set.
Also change external unification identifier in match macro
to @. This means we can more easily match symbol literals.
2019-06-10 14:00:51 -04:00
Calvin Rose
6225f8d334 Fix defn docstring typo. 2019-06-09 09:18:16 -04:00
Calvin Rose
95eb54045f Update changelog. 2019-06-08 17:22:42 -04:00
Calvin Rose
43520ac67d Add parser/clone. (#120) 2019-06-08 17:16:36 -04:00
Calvin Rose
802a2d6b71 Add more dynamic bindings for printing. 2019-06-08 15:27:13 -04:00
Calvin Rose
d9a4ef05ac Update docstring format.
Also add :p flag to fiber/new, change implemntation of with-dyns, and
make meson build install static library by default.
2019-06-08 10:30:43 -04:00
Calvin Rose
f00a2770ef Follow meson guidlines for static/shared libs
Use only one library definition for faster builds.
2019-06-08 09:05:38 -04:00
Calvin Rose
b83fe146fa Add static library to meson build. 2019-06-07 23:11:34 -04:00
Calvin Rose
6249f03367 Add janet_dep to meson build file. 2019-06-07 22:42:09 -04:00
Calvin Rose
bfc00b67bd Merge pull request #123 from andrewchambers/stdlibfd
Add file/{fdopen,fileno} functions.
2019-06-07 19:31:41 -04:00
Andrew Chambers
2b7428ed2b Add file/{fdopen,fileno} functions. 2019-06-08 10:33:29 +12:00
Calvin Rose
64a80c57e3 Tables created via table_init cannot leak memory.
Before, if Janet paniced without calling table_deinit
on a table created via table_init, Janet leaked memory.
This changes tables so that tables created via table_init
us scratch memory for auto cleanup instead of normal
malloc/free.
2019-06-05 17:08:49 -04:00
Calvin Rose
efb2ab06cb Remove array_init and array_deinit
These functions made it very easy to create memory
leaks, and are better replaced with functions in vector.h or
simply using non-stack allocated arrays.
2019-06-05 16:19:51 -04:00
Calvin Rose
b082c8123e Update tm_language_gen. 2019-06-05 11:07:08 -04:00
Calvin Rose
cc1ff9125a Add b_lundef=false for meson build. 2019-06-04 23:58:04 -04:00
Calvin Rose
5734e02034 Update CHANGELOG.md 2019-06-03 10:55:26 -04:00
Calvin Rose
6e8beff0a0 Add optional argument to parser/where to set index.
DSLs that use the parser API can use this to more accurately
report source location.
2019-06-03 10:48:16 -04:00
Calvin Rose
c21eaa5474 Fix redefinition. 2019-06-02 20:09:16 -04:00
Calvin Rose
13667292c6 Expose signal, type, and status name arrays.
Makes it easier to print status stuff.
2019-06-02 20:05:17 -04:00
Calvin Rose
22eb8372dd Make meson build file do cross compilation. 2019-06-02 17:05:17 -04:00
Calvin Rose
1b7a9def25 Fix path separators. 2019-06-02 14:10:12 -04:00
Calvin Rose
d7954e6fe3 Update installers for path.janet 2019-06-02 13:30:52 -04:00
Calvin Rose
c20c9cd5d7 Merge branch 'master' of github.com:janet-lang/janet 2019-06-02 13:28:48 -04:00
Calvin Rose
46531d9a60 Add path.janet. 2019-06-02 13:26:51 -04:00
Calvin Rose
d9a366fbed Merge pull request #118 from ALSchwalm/all-bindings-env
Allow all-bindings and dynamics to search specific env
2019-06-02 12:08:38 -04:00
Adam Schwalm
64bf52372a Allow all-bindings and dynamics to search specific env 2019-06-02 10:12:46 -05:00
Calvin Rose
0a9715a94c Bump version to 1.0.0 2019-06-01 23:52:01 -04:00
Calvin Rose
c82aac1365 Refer to @ as atsign not ampersand. 2019-06-01 23:40:59 -04:00
Calvin Rose
e697cc3811 Make os/execute not leak memory on panics.
Since many calls can panic, it's best
to only use scratch memory for temporary values.
2019-06-01 23:38:10 -04:00
Calvin Rose
c150f2f2c1 Add scratch memory API.
This should make it easier to write
code that does not leak memory on panics.
2019-06-01 23:31:39 -04:00
Calvin Rose
0a54e1ed62 Fix installer. 2019-06-01 11:34:28 -04:00
Calvin Rose
b9daf41327 NSIS installer fix. 2019-06-01 10:43:40 -04:00
Calvin Rose
2d2bc436e6 Quick fix. 2019-06-01 10:40:59 -04:00
Calvin Rose
3d76d988c3 More work on installation and moving files around.
Move all installed libraries into auxlib.
Move all installed executable scripts into auxbin.
2019-06-01 10:38:28 -04:00
Calvin Rose
bea6dbbf3d Hint utf8 output on windows console. 2019-05-31 15:30:23 -04:00
Calvin Rose
e1bd24c2ab Make os/execute on windows closer to posix version 2019-05-31 15:02:44 -04:00
Calvin Rose
1f30ea66e9 Windows quick fix. 2019-05-31 13:45:39 -04:00
Calvin Rose
c43aaf8986 More work to os/execute.
Use environ when eflag not given. Also try to escape windows
command line strings correctly.
2019-05-31 13:44:14 -04:00
Calvin Rose
2acc81d1c5 Add noreturn attribute to panic functions. 2019-05-31 10:10:20 -04:00
Calvin Rose
26513a7a16 Update changelog 2019-05-30 19:33:09 -04:00
Calvin Rose
d005ac6888 Appease MSVC. 2019-05-30 19:21:11 -04:00
Calvin Rose
7fdb098a20 Add process.h. 2019-05-30 19:14:54 -04:00
Calvin Rose
a4a200e037 Spawn.h not found in windows. 2019-05-30 19:13:13 -04:00
Calvin Rose
15d95d8803 Windows include issue. 2019-05-30 18:50:52 -04:00
Calvin Rose
46950a8cb3 Convert os/execute to use posix_spawn. 2019-05-30 18:40:10 -04:00
Calvin Rose
4867cab569 Correct changelog date. 2019-05-29 22:21:06 -04:00
Calvin Rose
c8cf7c2445 Appease MSVC. 2019-05-29 22:12:24 -04:00
Calvin Rose
1b63215aad Remove extra functions. 2019-05-29 22:00:47 -04:00
Calvin Rose
bcbe42ab23 Add API version checking for modules.
Checking now actively implemented for dynamic modules
in a fully backwards compatible way.
2019-05-29 21:58:20 -04:00
Calvin Rose
c8c6419013 Update installer again. 2019-05-29 19:48:31 -04:00
Calvin Rose
e8516c29e0 Update installer and jpm to work better on windows. 2019-05-29 19:01:12 -04:00
Calvin Rose
12247bd958 Update installer. 2019-05-29 17:48:46 -04:00
Calvin Rose
9d30d5f6e3 Update installer. 2019-05-29 13:02:15 -04:00
Calvin Rose
ba0956488d Prepare for 0.6.0 release 2019-05-29 12:19:39 -04:00
Calvin Rose
31f502b508 Add more to util.h to help with amalg build. 2019-05-29 12:07:53 -04:00
Calvin Rose
efaaead378 Update changelog 2019-05-29 11:58:41 -04:00
Calvin Rose
4d47d92a4a Windows WEXITSTATUS fix? 2019-05-29 11:53:57 -04:00
Calvin Rose
b39ad97a87 Fix up close to return proper exit code. 2019-05-29 11:50:46 -04:00
Calvin Rose
af23040d9c file/close returns an integer.
If opened with popen, returns the exit code. Otherwise
returns nil.
2019-05-29 11:40:58 -04:00
Calvin Rose
fd2d706e33 Add os/remove. 2019-05-29 11:31:19 -04:00
Calvin Rose
178d175bcf Update options for jpm and path stuff. 2019-05-29 11:04:38 -04:00
Calvin Rose
7a7f586094 Merge branch 'master' of github.com:janet-lang/janet 2019-05-28 23:03:08 -04:00
Calvin Rose
5124587c96 Merge pull request #114 from andrewchambers/configcheck
Add api for checking build compatibilty.
2019-05-28 23:02:08 -04:00
Calvin Rose
6c897b1a37 Add default for bindir. 2019-05-28 22:41:47 -04:00
Calvin Rose
c6ac53f4be Try distributing only the installer. 2019-05-28 21:05:47 -04:00
Calvin Rose
2d7812a06c Update appveyor.yml 2019-05-28 20:52:36 -04:00
Calvin Rose
db55277b58 Work on windows installer.
We will probably shift to NSIS as the default
installation method for windows. Shipping around a
single binary just doesn't cut it if we want to be able
to reliably use tools like `jpm` to build things.
2019-05-28 20:45:39 -04:00
Calvin Rose
75818217a6 Update CI tasks. 2019-05-28 14:02:45 -04:00
Calvin Rose
486b80fa7b Update changelog, change version to 0.6.0 2019-05-28 13:59:12 -04:00
Calvin Rose
873054d055 Update CI test-install. 2019-05-28 13:03:47 -04:00
Calvin Rose
f12f896020 Change test-install 2019-05-28 12:59:21 -04:00
Calvin Rose
09ab391d13 Add import-rules to cook.
First steps to recursive rules. Just needs normalized paths
relative to the directory of the imported file.
2019-05-28 09:49:10 -04:00
Calvin Rose
7569930b0c More work on cook and jpm. 2019-05-28 08:48:35 -04:00
Calvin Rose
e7189438dd More work on jpm
Switch to rea dependency graph for a rake-like tool.
This model is more powerful for writing build scripts.
2019-05-27 22:14:24 -04:00
Andrew Chambers
3c304ddc35 Add api for checking build compatibilty. 2019-05-28 13:51:40 +12:00
Calvin Rose
1696de233c Add jpm tool, based on cook.
Modify cook as well.
2019-05-27 16:50:57 -04:00
Calvin Rose
ce9cd4fcef Issue #113 Color console support for windows 10
Use SetConsoleMode winapi function to enable ANSI
escape codes if we can.
2019-05-26 22:31:30 -04:00
Calvin Rose
698e89aba4 Fix comment macro arity #110 2019-05-25 22:50:15 -04:00
Calvin Rose
4c8dd4b96c Fix shell like scripts. 2019-05-25 19:28:00 -04:00
Calvin Rose
11998b3913 Remove resolver element in path tuple.
Try to simplify module/paths back to how it used to be.
2019-05-25 17:27:56 -04:00
Calvin Rose
840610facf Add urlloader example.
Demonstrate loading files from URL.
2019-05-25 17:10:25 -04:00
Calvin Rose
0280deccae Allow filters on templates in module/paths
This lets us make loaders depend on file suffixes, which
lets us more efficiently use full paths.
2019-05-25 16:13:02 -04:00
Calvin Rose
4d5a95784a Add LDFLAGS to Lflags in generated janet.pc 2019-05-24 19:58:52 -04:00
Calvin Rose
b43d93cf55 Add pkg-config to install. 2019-05-24 19:38:13 -04:00
Calvin Rose
3f137ed0b1 Add keyword argument tests 2019-05-24 17:53:34 -04:00
Calvin Rose
5deb13d73e Update version 1.0.0 instead of 1.0.0-dev 2019-05-24 17:49:33 -04:00
Calvin Rose
82a1c8635e Update changelog. 2019-05-24 17:14:05 -04:00
Calvin Rose
010e2e4652 Add keyword arguments via &keys.
This makes it easier to document functions that
take keyword arguments and also prevents some allocations
with these functions. Before, this was possible via normal
variadic functions but created an intermediate tuple, and
the generated docstrings did not document the keys.
2019-05-24 17:03:22 -04:00
Calvin Rose
ddedae6831 Reenable computed gotos - they were disabled. 2019-05-24 13:54:23 -04:00
Calvin Rose
6c63c4f129 Disable faulty embed test.
This needs more work on windows. However, the initial
goal of fixing the amalgamated build on windows should be ok
for now.
2019-05-23 20:32:51 -04:00
Calvin Rose
802686e3df Apply patch from Dave Cottlehuber for bsd.
Update the install instructions.
2019-05-23 20:31:12 -04:00
Calvin Rose
3be79e8735 Link freebsd build.
Also begin work on CI amalg test for windows.
2019-05-23 11:15:58 -04:00
Calvin Rose
a303704a7d Add some tests for the amalgamated source/
Adds tests to Makefile and CI on Poisx platforms.
2019-05-23 10:34:01 -04:00
Calvin Rose
b5e6c0b8fc Address #109
Make repl work when default chunks not supplied.
2019-05-22 23:56:59 -04:00
Calvin Rose
98c46fcfb1 Update 2019-05-21 15:35:39 -04:00
Calvin Rose
409da697dd Update JANET_TFLAG_CALLABLE.
Most datatypes in Janet are callable.
2019-05-21 15:33:35 -04:00
Calvin Rose
91c3685705 Remove JANET_WALIGN
It was not used anywhere in the source after some
refactoring to make better use of structs and unions for automatic
alignment.
2019-05-21 11:12:56 -04:00
Calvin Rose
411fc77ecf Make env optional for compile. 2019-05-20 11:34:07 -04:00
Calvin Rose
0378ba78cc Add regression test. 2019-05-20 09:20:50 -04:00
Calvin Rose
55d8e8b56b Fix issue with compilation with source name.
Also add tuple/sourcemap and tuple/setmap.
2019-05-20 04:02:38 -04:00
Calvin Rose
97ad4c4f89 Update manpage and make -k mode not exit on error. 2019-05-19 15:20:59 -04:00
Calvin Rose
8de999c8f7 Merge pull request #107 from ALSchwalm/compile-only
Add a 'compile-only' flag to the command line
2019-05-19 15:06:35 -04:00
Adam Schwalm
f444bd25ef Add a 'compile-only' flag to the command line
This allows syntax checkers like the emacs 'flycheck-mode' to check
the source without side effects.
2019-05-19 12:55:28 -05:00
Calvin Rose
43c0db4b0e Add FAQ to readme for color terminal issues. 2019-05-17 09:48:08 -04:00
Calvin Rose
8f168c600d Merge pull request #105 from andrewchambers/doc
Minor documentation fixes.
2019-05-17 07:59:08 -04:00
Andrew Chambers
ec43afb426 Minor documentation fixes. 2019-05-17 20:58:06 +12:00
Calvin Rose
880049c0ee Merge pull request #104 from andrewchambers/openbsd
Add openbsd build file.
2019-05-16 22:13:26 -04:00
Andrew Chambers
2b7ac16784 Add openbsd build file. 2019-05-17 10:54:58 +12:00
Calvin Rose
56d903d75b Remove extra closing paren. 2019-05-16 12:12:55 -04:00
Calvin Rose
7054e878fb Add module/loaders for custom file types.
This will allow other languages/DSLs to very easily
integrate with Janet.
2019-05-16 12:05:40 -04:00
Calvin Rose
dde5351d11 Small changes to some doc strings. 2019-05-16 11:43:21 -04:00
Calvin Rose
7d49e3e6f1 Add unification to match macro.
Using a quote on a symbol prevents the match
macro from trying to create a binding to it, and
instead tells it that we are binding to a symbol
that is already in scope.
2019-05-16 10:05:54 -04:00
Calvin Rose
30cb01e2f0 Merge pull request #102 from PaulBatchelor/master
Add static library
2019-05-16 07:30:42 -04:00
Calvin Rose
018e836ef5 Merge branch 'master' of github.com:janet-lang/janet 2019-05-16 07:19:54 -04:00
Calvin Rose
7b25125431 Merge pull request #103 from VedVid/master
Primes example fixed
2019-05-16 06:15:05 -04:00
Vedor Vidurakis
0aa2f68793 Primes example fixed
It was failing due to unknown symbol "string/pretty"; (pp (primes 100)) works properly.
2019-05-16 12:03:54 +02:00
Paul Batchelor
516e031f67 Add static library 2019-05-15 22:38:18 -04:00
Calvin Rose
3331f2fa02 Update soname. 2019-05-15 11:39:18 -04:00
Calvin Rose
dd1a199ebd Don't copy headers to JANET_PATH 2019-05-15 10:53:26 -04:00
Calvin Rose
f35b5765d6 Set module/*headerpath* during bootstrap
Cook also uses module/*headerpath* for finding headers
rather than using module/*syspath*.
2019-05-15 10:49:16 -04:00
Calvin Rose
8359044408 Don't symlink into $(PREFIX)/lib/janet
Using the AUR installer, this seems to result in
symlinks into the cache, which may be an issue and looks
strange. Instead, we can just copy the file once for
the cook module.
2019-05-15 08:46:12 -04:00
Calvin Rose
9f3dde3cc7 Update meson build for #98 2019-05-15 08:20:39 -04:00
Calvin Rose
ad0f7d9b0d Merge branch 'master' of github.com:janet-lang/janet 2019-05-15 00:05:00 -04:00
Calvin Rose
f647ac5631 Address #95
A very minimal code change made partition take strings.
2019-05-15 00:04:25 -04:00
Calvin Rose
e4c5eb4c76 Merge pull request #97 from Crestwave/haiku
Add support for Haiku
2019-05-14 21:53:40 -04:00
Crestwave
dc9fc9c3f5 Add 32-bit Haiku build instructions 2019-05-15 01:27:55 +00:00
Crestwave
3b6a51df24 Add support for Haiku 2019-05-15 01:03:17 +00:00
Calvin Rose
f2313b9959 file/read on eof will return nil.
Also add documentation for :exit in import.
Address issue #91
Partially adress issue #93
2019-05-14 11:05:19 -04:00
Calvin Rose
805b3bbb88 Numbers require at least 1 significant digit.
Address issue #96
2019-05-14 08:44:38 -04:00
Calvin Rose
232ea22dc5 Add string/triml, string/trimr, and string/trim. 2019-05-10 16:09:49 -04:00
Calvin Rose
3388acd2db Add dofile function.
Abstracts the actually running of a file from
the require function, so a file can be easily
evaluated without being cached.
2019-05-10 10:19:51 -04:00
Calvin Rose
52ab9fb475 Update cook tool and headers. 2019-05-09 17:37:46 -04:00
Calvin Rose
c7dc3611bc Prepare for 0.5.0 release 2019-05-09 13:45:19 -04:00
Calvin Rose
7a313f6038 Update CHANGELOG, string/has-suffix?|prefix?
string/has-suffix? and string/has-prefix? can now accept
all byte data types for both arguments.
2019-05-09 13:42:14 -04:00
Calvin Rose
bbcfaf1289 Fix use after free bug in buffer/format when printing self. 2019-05-08 15:25:25 -04:00
Calvin Rose
bfb0cb331e No temporary buffer in PR #87 2019-05-08 10:53:23 -04:00
Andrew Chambers
1759252071 Fix use after free in buffer/push-string. 2019-05-08 10:49:25 -04:00
Calvin Rose
fff60b053b Use memmove in buffer/blit when needed. 2019-05-08 09:29:21 -04:00
Calvin Rose
65ac17986a Address similar issue to #86
buffer/blit could trigger a use after free if a buffer is
blitted with itself and modifies its length.
2019-05-08 08:55:43 -04:00
Calvin Rose
ff720f1320 Expose current fiber via janet_current_fiber(). 2019-05-04 19:07:04 -04:00
Calvin Rose
5a28d8d1fa fix cook error. 2019-05-04 18:55:36 -04:00
Calvin Rose
ea25766374 fix cook. 2019-05-04 17:59:48 -04:00
Calvin Rose
88b8418253 Add simple tracing functionality to VM.
Also disable debugger for normal errors.
2019-05-04 15:05:00 -04:00
Calvin Rose
4fa1b28cad Update changelog (string module)
Also run `make format` on code.
2019-05-04 10:11:52 -04:00
Andrew Chambers
c70d59edee Add string/has-prefix? and string/has-suffix?. 2019-05-04 10:05:58 -04:00
Calvin Rose
5694998382 Update changelog 2019-05-02 18:05:06 -04:00
Calvin Rose
1cfc7b3b0d Add preliminary debugger to default repl.
Also upddate colors, and fix formatting.
2019-05-02 17:11:30 -04:00
Calvin Rose
03e3ecb0a1 Update cook tool. 2019-05-02 13:10:14 -04:00
Calvin Rose
f8935b0692 test your links before committing 2019-05-01 11:06:20 -04:00
Calvin Rose
702b50b7a1 Indicate that the source is on sourcehut as well. 2019-05-01 11:04:41 -04:00
Calvin Rose
e7baa2ae3d Update broken links in README.md 2019-04-29 18:35:09 -04:00
Calvin Rose
bfb354b469 Fix 32 bit platforms. 2019-04-28 16:22:24 -04:00
Calvin Rose
3c0f12ea4d Add library installation during make install
Got removed a while ago for some reason, I forgot why.
2019-04-28 16:02:05 -04:00
Calvin Rose
25a93ac4a6 Fix loop :iterate. 2019-04-28 00:34:32 -04:00
Calvin Rose
0bad523913 Fix wrap functions. 2019-04-27 19:47:32 -04:00
Calvin Rose
5b36199aea Fix MSVC warning. 2019-04-27 16:50:40 -04:00
Calvin Rose
a474a640be Merge branch 'master' of github.com:janet-lang/janet 2019-04-27 15:48:28 -04:00
Calvin Rose
f10028d41a Add function versions of macro API bindings.
This should help address #81. Also hide janet_exit
and janet_assert, as they are really meant for internal usage.
I have not verified that this yet actually works with Rust's
bindgen.
2019-04-27 15:47:12 -04:00
Michael Forney
eb4684a64d Remove spurious ';' after function definitions
The function definition is complete after the last '}', so the ';' is
a separate empty declaration, which is not actually valid in C99.
2019-04-25 16:24:27 -04:00
Calvin Rose
73b81e0253 Fix os/date doc typo. 2019-04-23 22:43:51 -04:00
Calvin Rose
027f106a56 Update CHANGELOG.md
Indicate support for longstrings with non semantic newlines.
2019-04-21 15:45:55 -04:00
Calvin Rose
20e94adb61 Update documentation for update function. 2019-04-21 15:44:03 -04:00
Calvin Rose
9100794cea Drop leading and trailing newlines in longstrings.
Long, heredoc style strings can now have
a non semantic leading newline character. This makes it
easier to define large columns of text.
2019-04-21 13:34:41 -04:00
Calvin Rose
4ddf90e301 Make nanboxing on 64 bit platforms not the default.
64 bit nanboxing is kind of sketchy on non x86 architectures.
32 bit architectures seem to work better as the 32 implementation
doesn't rely on the format of the address space and layout of
double's in memory.
2019-04-18 12:52:28 -04:00
Calvin Rose
d1eca1cf52 Add all-dynamics to list current dynamic bindings. 2019-04-17 09:47:33 -04:00
Calvin Rose
7918add47d Allow dynamically setting output for printers
Some functions like print and debug/stacktrace print
to a file, usually stdout. This file can now be optionally set
via a dynamic variable.
2019-04-16 21:44:19 -04:00
Calvin Rose
513d551df6 Move print in source code to io module.
print now reads the dynamic binding for :out
when choosing where to write to.
2019-04-16 19:10:01 -04:00
Calvin Rose
ddaa5e34e6 Fix web versinon repl colors. 2019-04-16 16:06:52 -04:00
Calvin Rose
208eb7520a Update CHANGELOG.md and bump version. 2019-04-16 15:48:53 -04:00
Calvin Rose
2d7df6b78e Many changes for adding dynamic (fiber-level) scope.
- Allow passing a table to fibers, which make fiber level scope easier.
- Add fiber/getenv, fiber/setenv, dyn, and setdyn
- Remove meta, *env*, and *doc-width*
- Some functions changed dignatures, and no longer take an env
2019-04-16 15:41:45 -04:00
Calvin Rose
7527142549 Prepare for 0.4.1 release 2019-04-14 11:42:41 -04:00
Calvin Rose
4e6193b67e Fix parse insert bug. 2019-04-13 14:38:30 -04:00
Calvin Rose
4ded5e10a2 Update cook tool to export shell function. 2019-04-12 13:48:45 -04:00
Calvin Rose
1596511175 Fix undefined behavior bug with errors.
janet_vm_return_reg should only be set when janet_continue
is called. Otherwise, a panic may dump it's error message in
the wrong place, resulting in undefined behavior (often showing
the last return value or worse, segfaulting).
2019-04-10 23:29:40 -04:00
Calvin Rose
d514eab627 Add regression test for #78 2019-04-09 09:14:40 -04:00
Calvin Rose
5287007cd6 Fix typo in comment. 2019-04-09 09:05:47 -04:00
Calvin Rose
e5a56174e2 Switch fexists to use os/stat when available.
When os/stat is not available, we first
try to read one byte from the file before
saying it is good. If that fails, it is not
a file that we can read from so it counts as not found.
2019-04-09 09:01:52 -04:00
Calvin Rose
6c68c7a35f Address issue #78
(file/open path :r+) should help. On windows, result
is unknown as of now.
2019-04-09 08:38:56 -04:00
Calvin Rose
675c1030fd Fix error message on an arity mismatch.
janet_call had a bad janet_printf.
2019-04-07 23:53:50 -04:00
Calvin Rose
ed65d04b81 Fix peg bug with arguments.
By holding on a reference to argv for a long time, we
may trigger a use after free bug if the stack is resized. In
janet c function, argv is only vvalid up until the next stack operation
on the fiber. We could say that this is the dynamic lifetime of
argv.

To fix this, we copy extra arguments into a tuple, which is properly
garbage collected.
2019-04-07 15:14:54 -04:00
Calvin Rose
fa1c5c85b5 Remove no-capture mode in pegs.
Some peg grammars could not capture values based on their position in a
larger grammar. This is a design limitation inheritted from LPeg, but no
longer needed as the replace mode is superseded by the accumulator mode,
which is more general if slightly harder to use.
2019-04-06 11:38:00 -04:00
Calvin Rose
59c69e6896 Update cook cleaning up directory. 2019-04-05 20:01:03 -04:00
Calvin Rose
ee35786c8f semicolon 2019-04-05 14:45:45 -04:00
Calvin Rose
ec6e2cfd62 os/stat returns nil if file does not exist. 2019-04-05 14:45:04 -04:00
Calvin Rose
7d48e7fd1f Remove some extra search paths. 2019-04-01 14:07:13 -04:00
Calvin Rose
0063e3a69d Fix module path typo. 2019-04-01 13:48:30 -04:00
Calvin Rose
cd6c009c03 Reformat and use new os/stat capabilities. 2019-04-01 11:21:45 -04:00
Calvin Rose
b15cf193a0 Update os/stat
os/stat can now take a keyword as the second argument
to avoid creating a table if one only wants on value
from stat.
2019-04-01 11:11:15 -04:00
Calvin Rose
429dc70374 Update cook tool to use os/stat for file age. 2019-03-31 21:35:44 -04:00
Calvin Rose
e50e77e5f9 Add build instructions back to README.md 2019-03-31 20:24:56 -04:00
Calvin Rose
2fdd6aa0f7 <br> 2019-03-31 18:15:28 -04:00
Calvin Rose
cc55364b21 Remove some more info from README. 2019-03-31 18:13:59 -04:00
Calvin Rose
71526d1d9b Update README.md
Redirect to janet-lang.org to avoid repeating
prose or leaving outdated prose.
2019-03-31 18:11:29 -04:00
Calvin Rose
e239980da7 Quasiquoting bracketed tuples. 2019-03-31 14:15:26 -04:00
Calvin Rose
1709bce77e Add os/rm and os/rmdir 2019-03-30 15:39:24 -04:00
Calvin Rose
d6ba2de888 Fix os/dir on windows. 2019-03-30 13:46:52 -04:00
Calvin Rose
61c0a4bc87 Windows has different defines for file modes. 2019-03-30 13:09:35 -04:00
Calvin Rose
8af28d3fa5 Windows bump. 2019-03-30 13:06:24 -04:00
Calvin Rose
970923d0e5 Update os/dir for windows. 2019-03-30 13:01:57 -04:00
Calvin Rose
5d7dc0a57c Add os/dir support for linux/posix. 2019-03-30 12:36:27 -04:00
Calvin Rose
c5090606a4 Add os/stat function.
Allows getting more information about files. This
is really useful for writing software that needs to inspect
the file system (like a static site generator). We still need
a way to iterate directories though.
2019-03-30 12:06:14 -04:00
Calvin Rose
bf2d9ae634 Mess with includes for os.c 2019-03-28 23:34:24 -04:00
Calvin Rose
871a58e1db Remove extreneous source reference on sr.ht build 2019-03-28 23:25:11 -04:00
Calvin Rose
53c7f2eedd Add more os module functions. 2019-03-28 23:23:58 -04:00
Calvin Rose
bfd3845218 Fix cfunction debugging issue
Cfunction were not describing themselves very well, as
their names were not be added to the registry.
2019-03-27 00:14:51 -04:00
J.-F. Cap
22d75d017f fix AbstractType get/set error message 2019-03-26 21:47:12 -04:00
Calvin Rose
37e6ea0a23 Update changelog 2019-03-24 15:11:00 -04:00
Calvin Rose
10769f6f2e Appveyor build issues
Revert some externeous changes in build_win.bat to
see what happens.
2019-03-24 15:04:47 -04:00
Calvin Rose
082639319e Add colors to repl and string/format.
This makes the repl look nicer using ANSI
color codes, which are widely supported. The codes
can also be turned off via the -m flag.
2019-03-24 15:00:22 -04:00
Calvin Rose
f20ad34c76 Add instructions for Scoop installation. 2019-03-23 23:27:13 -04:00
Calvin Rose
c045eadefa Update changelog. 2019-03-23 22:16:12 -04:00
Calvin Rose
e2337b2ec4 Update build_win.bat to handle new amalg script. 2019-03-23 19:59:54 -04:00
Calvin Rose
90c5d12613 Add include_directories to meson
Before, a local build would only work if system
headers were installed.
2019-03-23 15:02:59 -04:00
Calvin Rose
6016662807 Ignore eclipse files. 2019-03-23 14:05:38 -04:00
Calvin Rose
2c9195b507 More updates to meson
Redo amalg script so we can more easily run
it from Meson.
2019-03-23 13:50:50 -04:00
Calvin Rose
b47c48b59a Add Meson build setup to README.md 2019-03-22 18:47:16 -04:00
Calvin Rose
98758b68ab Boot executable invocation has changed. 2019-03-22 18:37:46 -04:00
Calvin Rose
7f1b5d4d70 Merge core.janet into boot.janet
This simplifies the build machinery a bit.
core.janet is never actually included in the final
binary, it is just used to generate an image file.
2019-03-22 18:34:50 -04:00
Calvin Rose
25aa7a26c5 Add experimental meson build.
Should help with IDE integration.
2019-03-22 18:07:10 -04:00
Calvin Rose
cb2caecbb3 Add janetconf.h for configuring builds.
Rather than edit the Makefile or the janet.h header yourself, use
janetconf.h to configure builds. This has the benefit of making it
easier to configure janet in a persitent but easy way.
2019-03-22 14:33:30 -04:00
Calvin Rose
1e299632e4 Fix example. 2019-03-21 14:32:08 -04:00
Calvin Rose
94a2084723 Add tostring method for abstract types.
This lets abstract types customize how they
print for debugging.
2019-03-19 13:36:26 -04:00
Calvin Rose
22e24fb47b Remove some dead code in bigint. 2019-03-19 12:30:44 -04:00
Calvin Rose
93f0d5f626 Quiet appveyor warnings. 2019-03-18 22:00:20 -04:00
Calvin Rose
bad040665f Renamed bigint -> inttypes / int
A lot of refactoring larger integer types. Fix a number
of casting errors, but mostly rename things. Also try to
limit use of template-like macros as they bloat the binary
if not used in moderation. We were able to reduce the size of
typed array code as well by using a single view types.
2019-03-18 18:36:53 -07:00
J.-F. Cap
a07d76b264 use custom string to bigint reader in place of strtol
for better compatibility with default janet number reader
2019-03-18 18:36:53 -07:00
J.-F. Cap
1db6d0e0bc Trap INT64_MIN / -1 exception 2019-03-18 18:36:53 -07:00
J.-F. Cap
34849ea7b3 added (u)int64 typed arrays back 2019-03-18 18:36:53 -07:00
J.-F. Cap
5a9f7c3a85 added in place op! operators 2019-03-18 18:36:53 -07:00
J.-F. Cap
15c6300608 added bitwise operators and guard for division by zero 2019-03-18 18:36:53 -07:00
J.-F. Cap
c6a4485623 code cleanup 2019-03-18 18:36:53 -07:00
J.-F. Cap
090c6ac975 added marshal/unmarshal 2019-03-18 18:36:53 -07:00
J.-F. Cap
319575c864 bigint operators and some tests 2019-03-18 18:36:53 -07:00
J.-F. Cap
42a0af3b1b bigint pretty printing 2019-03-18 18:36:53 -07:00
J.-F. Cap
9bc899ccf2 added core/bigint.c 2019-03-18 18:36:53 -07:00
J.-F. Cap
d29e3a1199 first experiment with bigint 2019-03-18 18:36:53 -07:00
rncar
41bb6a9833 Added a getter to the new pointer type. 2019-03-14 14:21:44 -04:00
Calvin Rose
95e54c66b6 Use one tag type true and false
We moved the literals true and false into one tag
type, so we an extra tag for raw pointer types
(light userdata). These can be used from the C API via
janet_wrap_pointer and janet_unwrap_pointer.
2019-03-13 14:50:25 -04:00
Calvin Rose
31e2415bbb Fix some indentation problems. 2019-03-12 20:56:16 -04:00
Calvin Rose
2a5234b390 Properly bail on parse and compile errors
If -p flag is not set, we should bail on all three kinds
of errors, not just runtime errors. This includes
parse and compile errors. Before, parse and compile errors
were not properly affected by the :exit parameter to require, which
in turn caused scripts to not bail on parse or compile errors.
2019-03-12 20:41:17 -04:00
Calvin Rose
ad5b0a371e Optional param in bars.janet 2019-03-12 11:35:27 -04:00
Calvin Rose
ba4dd9b5bb Fix splice -> unquote splice 2019-03-12 11:16:27 -04:00
Calvin Rose
d42bdf2443 Add proper optional arguments.
Use &opt in the parameter list to get optional arguments.
2019-03-12 00:23:14 -04:00
Calvin Rose
a246877c1e Remove iterate-template from exported core symbols. 2019-03-11 01:01:59 -04:00
Calvin Rose
98e68a5cb4 Update special form lists to include break. 2019-03-11 00:58:26 -04:00
Calvin Rose
e12aace02c Update web build. 2019-03-10 23:06:10 -04:00
Calvin Rose
51a9c7104d Hide each-template 2019-03-10 13:31:42 -04:00
Quan Nguyen
75dc08ff21 Fix nil error on drop-until fn 2019-03-10 12:39:55 -04:00
Calvin Rose
6fa60820a3 Merge pull request #64 from quan-nh/master
Correct doc for drop-until fn
2019-03-09 23:47:00 -05:00
Quan Nguyen
609a9621af Correct doc for drop-until fn 2019-03-10 11:36:27 +07:00
Calvin Rose
8ba1121161 Add early returns via break.
Inside a while loop, the argument to
break does nothing as while loops always
return nil.
2019-03-09 22:01:10 -05:00
Calvin Rose
9a080197e7 Switch some instances of loop in core
Several instances of loop in the core library are
switched over to the simpler each and for macros.
2019-03-09 21:01:47 -05:00
Calvin Rose
e65375277a Update the loop macro.
Using the new break special form, the loop
macro was cleaned up. Loop bindings are also
able to be used immediately after declaration, so
forms like (loop [x :range [0 10] :while (< x 5)] (print x)) will
now compile correctly.
2019-03-09 20:47:07 -05:00
Calvin Rose
4a111b38b1 Add break special.
The break special form can break out of both loops
and functions with an early (nil) return. Mainly useful
for generated code in macros, and should probably be discouraged
in user written code.
2019-03-09 17:15:50 -05:00
Calvin Rose
a363dce943 Allow proper overriding of cfunctions in the core.
Allow overriding functions in the core libray to provide better
functionality on startup. Used to include our getline function in
the repl but use a simpler version in the core library.
2019-03-08 11:39:18 -05:00
Calvin Rose
687a3c91f5 Add array/remove and update CHANGELOG. 2019-03-08 10:24:21 -05:00
Calvin Rose
951aa0d8cd Add typed array code to amalg. 2019-03-08 10:02:09 -05:00
Calvin Rose
a61b59be87 Mark release for 0.4.0 2019-03-08 00:56:19 -05:00
Calvin Rose
91f3c17a5b Update CHANGELOG.md 2019-03-08 00:54:53 -05:00
Calvin Rose
0382dc976b More code to better integrate with size_t
Typed arrays use proper size_t support in more
places now.
2019-03-08 00:44:26 -05:00
Calvin Rose
69dcab2b55 Silence some casting size_t to double errors. 2019-03-07 22:44:17 -05:00
Calvin Rose
c4f6f1d256 janet_marshal_bytes, janet_unmarshal_bytes size_t
Instead of a int32_t as the length argument, use
size_t to match up better with typearray.c and probably
most idiomatic C libraries.

Janet uses int32_t for length internally for consistency, space
efficiency, ability to fit int32_t in double, and various
other reasons.
2019-03-07 22:23:46 -05:00
Calvin Rose
b57e530553 Some more small changes to typedarray.c.
We want to compile janet with MSVC warning free.
2019-03-07 22:12:06 -05:00
Calvin Rose
021b71ad62 Allow proper serialization of size_t in marsh.c
Typed arrays used size_t in serialization: C APIs will
also often use it, so it makes sense to add first class support
for it rather than assume it will will fint into an integer.

These changes should quiet some visual studio warnings.

Also make some spacing more consistent.
2019-03-07 22:08:44 -05:00
Calvin Rose
0ee2ff1b05 Add :fiber-flags options to run-context.
This also improves eval-string error behavior.
2019-03-07 18:55:19 -05:00
Calvin Rose
adaa014d7c No div by 0 - will fix later. 2019-03-07 16:20:36 -05:00
Calvin Rose
dc9dc98e80 Update for issue #62 2019-03-07 16:17:18 -05:00
Calvin Rose
4a2d4f52b5 Allow inverted ranges with negative steps. 2019-03-04 15:44:56 -05:00
Calvin Rose
8d37e544ab Fix BSD builds.
Try to silence some more undefined C warnings
with -fsanitize=undefined.
2019-03-04 12:16:49 -05:00
Calvin Rose
b07adce2b9 Fix some issues found with -fsanitize=undefined
Leave in issues with calling memcpy with size=0. If these
become a problem, will probably add a janet_memcpy as memcpy
is used so much in the code without 0 checks.
2019-03-04 11:17:34 -05:00
Calvin Rose
624be87c97 Add test for :down verb. 2019-03-03 23:55:38 -05:00
Calvin Rose
1b9591b5e3 Add :down verb to loop macro.
Also remove with-idemp from core, which was both confusing
(to the author) and not generally useful.
2019-03-03 23:52:20 -05:00
Calvin Rose
a4cc23971f Only use -rdyanmic at link time
Before, we were using -rdynamic as a compiler flag, but
it is only needed at link time. This also gets rid of some
annoying warnings in clang.
2019-03-03 18:55:10 -05:00
Calvin Rose
9ed1c35d30 Add sudo permissions to freebsd build.
'sudo gmake install'.
2019-03-03 15:21:40 -05:00
Calvin Rose
6158ec0ce5 Add -undefined dynamic_lookup on mac. 2019-03-03 15:18:17 -05:00
Calvin Rose
009bed158b Travis add sudo. 2019-03-03 14:54:01 -05:00
Calvin Rose
402dc2a767 Test installation on sourcehut free bsd as well. 2019-03-03 14:52:11 -05:00
Calvin Rose
b5eb888af6 Add test-install to travis CI.
Users have been reporting installation trouble on
platforms like OSX and BSDs, so we need to make sure
that the cook module is more portable.
2019-03-03 14:50:17 -05:00
Calvin Rose
172261b89f Add a test-install target to the Makefile
This target will be used to check if an installation
of Janet is on the PATH, if native modules can be built
and used via the cook module, etc.
2019-03-03 14:48:17 -05:00
Calvin Rose
8cc2c964c1 Add :export option to import
Also allow NULL ptr to janet_getfile for flags.
2019-03-02 11:46:31 -05:00
Calvin Rose
efbb704247 Merge pull request #56 from jfcap/register-corefile
Register core/file abstract type
2019-03-02 11:40:05 -05:00
J.-F. Cap
7fef5be3af Merge remote-tracking branch 'upstream/master' into register-corefile 2019-03-02 15:38:31 +01:00
J.-F. Cap
1753f8bc18 Added janet_getfile C API function and revert core/file AT registering 2019-03-02 15:36:34 +01:00
Calvin Rose
235019ec39 Merge branch 'master' of github.com:janet-lang/janet 2019-02-27 16:30:04 -05:00
Calvin Rose
7d17159ae4 Make JANET_STACK_MAX configurable option.
Also double default value from 8192 to 16384
2019-02-27 16:28:43 -05:00
Calvin Rose
56d7d4ef39 Merge pull request #57 from tekknolagi/patch-1
Fix typo in README
2019-02-27 15:43:29 -05:00
Max Bernstein
77c379faa8 Fix typo in README 2019-02-27 11:39:00 -08:00
Calvin Rose
3014a59c3e Fix parse error with comment on last line.
If a comment is not followed by a newline character, then
we got a false parse error. This is because the comment
state is left on the parse stack when we finished parsing, and
since the parse stack was not emtpy, we assumed an error.

This commit adds the parser/eof function, which lets the parser know
that an eof was reached. Before, we simply added a fake newline
character in some cases, and in the case of reading a file, we did
nothing, hence the bug.
2019-02-27 13:59:25 -05:00
J.-F. Cap
d70049dbb1 Register core/file abstract type 2019-02-27 10:54:10 +01:00
Calvin Rose
4713219317 Update whitespace and some doc strings. 2019-02-25 23:48:04 -05:00
Calvin Rose
36f92db61e Merge pull request #55 from jfcap/typed-array
Binary Typed Array  for Janet
2019-02-25 23:40:19 -05:00
J.-F. Cap
59393fc73b Added some guards in ta_view unmarshalling
to protect against bad marshalled data.
2019-02-26 02:28:24 +01:00
J.-F. Cap
3eb44f1f79 Fix buffer allocation 2019-02-26 00:21:03 +01:00
J.-F. Cap
fb5119bf43 Added some tests (suite 5) 2019-02-25 18:49:04 +01:00
J.-F. Cap
febfefa4b2 Added tarray/slice and fix buffer size 2019-02-25 02:21:10 +01:00
J.-F. Cap
632b920e97 fix C format 2019-02-24 22:36:35 +01:00
J.-F. Cap
c81bf42f6b Merge remote-tracking branch 'upstream/master' into typed-array-work 2019-02-24 22:25:33 +01:00
J.-F. Cap
4147c0ce1f Added typed array C API 2019-02-24 22:24:18 +01:00
Calvin Rose
602e30a421 Add "\v" string esca[e sequence. 2019-02-24 14:46:16 -05:00
Calvin Rose
92a5567b4a Remove some makefile crust from older scripts. 2019-02-24 14:25:04 -05:00
Calvin Rose
9495be328c Be more careful about data alignment
Alingment issues can happen anywhere we do casting
on pointer types. Be more careful in the peg module about
ensuring that pointers are aligned well.
2019-02-24 13:43:38 -05:00
J.-F. Cap
0eae75a5c2 added MARSH_EOS check 2019-02-24 18:45:14 +01:00
J.-F. Cap
8e0d7f2539 Merge remote-tracking branch 'upstream/master' into typed-array 2019-02-24 03:06:26 +01:00
J.-F. Cap
9c1c7fb384 Remove AT id use name as tag 2019-02-24 02:51:34 +01:00
J.-F. Cap
af48912f11 Simplify Abstract type introspection 2019-02-24 02:02:54 +01:00
Calvin Rose
327d2ed849 Remove extra "compile error: " string. 2019-02-23 15:38:49 -05:00
J.-F. Cap
db64a682be fix incompatibilities with upstream/master changes in marsh.c 2019-02-23 17:54:09 +01:00
J.-F. Cap
4d3c655058 Merge remote-tracking branch 'upstream/master' into typed-array 2019-02-23 17:36:38 +01:00
J.-F. Cap
2becebce92 fix C source format 2019-02-23 17:13:43 +01:00
J.-F. Cap
0cc6c6ff33 implement typed array marshal/unmarshal and
generic marshaling capabilities to abstract types.
2019-02-23 16:58:47 +01:00
Calvin Rose
115bc6140b Fix NULL ptr issue. 2019-02-22 17:12:34 -05:00
Calvin Rose
b14fcb068b Update janet_pcall interface
The programmer can now not only get the used fiber, but
provide a fiber to reuse if many calls are made in succession.
2019-02-22 17:10:24 -05:00
Calvin Rose
2ea28f29b0 Shut up some warnings from clang's static analyzer.
Not particularly useful actually, by and large false positives.
2019-02-22 12:10:27 -05:00
J.-F. Cap
7cb1c7cef2 added ta marshalling 2019-02-22 17:41:27 +01:00
Calvin Rose
9d60e8b343 Address issue #54
Bug when marshalling function environments that were still on a fiber
stack.
2019-02-22 10:16:32 -05:00
Calvin Rose
340a6c4d8d Update marsh.c to use janet_panic for errors.
Before, we used a local setjmp/longjmp for error handling.
Using janet_panic means errors can be more easily expressive and
code can be smaller.

However, we still need to make vector memory get gc collected, as
panics can cause the runtime to skip janet_v_frees.
2019-02-22 10:12:25 -05:00
J.-F. Cap
e5a4c6fc2b Merge remote-tracking branch 'upstream/master' into ta-with-marshal 2019-02-22 15:58:47 +01:00
J.-F. Cap
db9ac6dba5 marshal buffer ok 2019-02-22 15:57:48 +01:00
J.-F. Cap
d570aae817 Merge branch 'ta-marshal' into ta-with-marshal 2019-02-22 11:13:12 +01:00
J.-F. Cap
59e4b15fad added some abstract type instrospection capabilities
registering abstract type in vm_register table
2019-02-22 10:54:22 +01:00
Calvin Rose
b3401381fa Update CHANGELOG.md 2019-02-21 20:40:13 -05:00
Calvin Rose
beed839d12 Remove the callable? predicate.
Many times are callable now in some circumstances, so
the predicate is not that useful.
2019-02-21 20:38:22 -05:00
Calvin Rose
f4908ebc41 Update issue 53 regression test.
Some tests did not call assert so did not show up on report.
2019-02-21 19:19:47 -05:00
Calvin Rose
1147482e62 Address #53 - marshalling fiber strangeness
The unmarshaller was not tracking fibers in references.
2019-02-21 19:11:28 -05:00
J.-F. Cap
4d07176f1c work in progress 2019-02-21 20:52:39 +01:00
Calvin Rose
8c67bf82f6 Remove restriction on variable length arrays. 2019-02-21 11:54:06 -05:00
Calvin Rose
0823eb7327 Change order of directory creation. 2019-02-21 11:50:48 -05:00
Calvin Rose
8cff3dd2c3 Fix one more warning. 2019-02-21 11:46:39 -05:00
Calvin Rose
df550efb6b Fix MSVC compiler warnings. 2019-02-21 11:34:04 -05:00
Calvin Rose
00a47dc0cb Begin work on new memory layout for all objects and GC.
The layout should actually be very similar to the old layout, but
the code will be much easier to change and should be more portable.
2019-02-21 11:22:29 -05:00
Calvin Rose
811b1825cb Remove tuple/append and tuple/prepend.
Use the splice special instead.
2019-02-20 21:08:54 -05:00
J.-F. Cap
2ca252bc0e Merge remote-tracking branch 'upstream/master' into typed-array 2019-02-21 01:43:22 +01:00
J.-F. Cap
6054858359 fix C format 2019-02-21 00:20:54 +01:00
J.-F. Cap
1d50fd9485 First exeperiments with JS style Binary Typed Arrays 2019-02-21 00:15:48 +01:00
Calvin Rose
a982f351d7 Address #50
Issues with range when called with 3 arguments.
2019-02-20 12:07:20 -05:00
Calvin Rose
27a274b686 Update some corelib functions.
Some corelib functions that were created via janet_quickasm
were missing some flags for arity checking, so they were marked as
accepting any arity.
2019-02-19 23:41:16 -05:00
Calvin Rose
cb002e7b84 Update generating tools to produce stylish code.
Really small whitespace changes in generated code.
2019-02-19 21:28:22 -05:00
Calvin Rose
c022a1cf1a Add astyle guidelines to the contributing document. 2019-02-19 20:59:34 -05:00
Calvin Rose
9d4effc02e Add make format to format code.
A consistent style should help with contributors and
readability. We use astyle as the formatter as can make a pretty
good approximation of the current style and my preferred style.

Astyle can be found at http://astyle.sourceforge.net/astyle.html
2019-02-19 20:51:34 -05:00
Calvin Rose
7c19ed8a48 Merge pull request #49 from boardwalk/fix_indentation
Fix indentation, converting some tabs to spaces.
2019-02-19 19:08:18 -05:00
Dan Skorupski
ef5f80ad38 Fix indentation, converting some tabs to spaces. 2019-02-19 17:54:13 -06:00
Calvin Rose
dbcbb4466d We don't need to add module/\*headerpath\*.
We can just dump janet.h into the lib folder as well.
2019-02-18 22:25:40 -05:00
Calvin Rose
7927078b49 Include header path when building modules. 2019-02-18 20:27:00 -05:00
Calvin Rose
b61c9eb991 Update build script for windows. 2019-02-18 20:15:20 -05:00
Calvin Rose
ed72dcf82d Rename the header <janet/janet.h> to <janet.h>
Makes it easier to use and remember, and makes the
variable `module/*headerpath*` make more sense.
2019-02-18 20:13:35 -05:00
Calvin Rose
9480ad24cc Merge pull request #46 from tssva/remove_mandb
Don't call mandb during install
2019-02-18 19:01:22 -05:00
Tim Sedlmeyer
a9574b692f Don't call mandb during install
mandb is used on many but not all linux distributions and infrequently outside of linux to maintain the man page index files, so it should not be called as part of the install process.
2019-02-18 18:29:35 -05:00
Calvin Rose
8d9a88e759 Add JANET_PATH back in. 2019-02-18 15:31:15 -05:00
Calvin Rose
732de8f88d Update man page. 2019-02-18 15:26:53 -05:00
Calvin Rose
6af5800d21 Add -m option to command line
The -m option set the default system path for finding libraries
for that invocation of Janet.
2019-02-18 15:11:59 -05:00
Calvin Rose
540b326c54 Simpler way to set JANET_PATH at compile time. 2019-02-18 14:48:29 -05:00
Calvin Rose
660a2b41ae Set module/*syspath* to JANET_PATH at build time
The takes out the hardcoded reference to /usr/local/
2019-02-18 14:31:23 -05:00
Calvin Rose
d2d502b9ae Remove ldconfig stuff. 2019-02-18 13:49:43 -05:00
Calvin Rose
3aae524964 Try to respect PREFIX more.
Remove automatic installation of shared library.
2019-02-18 13:46:35 -05:00
Calvin Rose
07912f5ab2 Update comments in strtod.c 2019-02-17 21:44:58 -05:00
Calvin Rose
ffc14f6019 Oops, peg option issue fixed. 2019-02-17 21:25:30 -05:00
Calvin Rose
1e70c97ef0 Allow enabling/disabling of peg module.
Use compiler define -DJANET_NO_PEG to turn off the peg module.
2019-02-17 21:22:03 -05:00
Calvin Rose
54227ebff1 Update README.md 2019-02-17 14:00:15 -05:00
Calvin Rose
33087fe9de Update game of life example. 2019-02-17 11:20:24 -05:00
Calvin Rose
6d5ff43de7 Make amalg build cleaner.
Don't pull in a global header <janet/janet.h> unless we need to.
2019-02-16 23:33:24 -05:00
Calvin Rose
c715912ea3 Update changelog. 2019-02-16 21:57:47 -05:00
Calvin Rose
3b6ff3c09a Add -c option to main client
This allows compile janet source modules to images.
2019-02-16 21:55:53 -05:00
Calvin Rose
efab484fff Remove some more extra text in core api doc. 2019-02-16 18:39:44 -05:00
Calvin Rose
4ba7fbb8bb Remove extra 'at' in generated doc. 2019-02-16 18:38:34 -05:00
Calvin Rose
53cc7ebd29 Fix gendoc. 2019-02-16 18:37:15 -05:00
Calvin Rose
c6f032340a Update CHANGELOG.md 2019-02-16 17:55:08 -05:00
Calvin Rose
0ce5acec89 Begin cleaning up string API.
Remove string/pretty in favor of buffer/format and string/format. Also
drop string/number, which is more verbose and less flexible than
string/format.
2019-02-16 15:12:34 -05:00
Calvin Rose
44e31cac5d Merge pull request #40 from jfcap/string-format
string/format
2019-02-16 15:02:47 -05:00
Calvin Rose
029394db31 Add buffer/format as well as string/format.
buffer/format uses the old string/format behavior. `string/format` no
longer requires a buffer, and returns a string.
2019-02-16 13:59:38 -05:00
Calvin Rose
00020ba8ab Whitspace and style changes. 2019-02-16 13:40:51 -05:00
Calvin Rose
1f91ee30fe Make require simpler and module/find more useful.
This replaces a lot of the functionality in require by moving
it to module/find. module/native-paths and module/image-paths are also
merged into the one module/paths to make it easier to extend. This of
course breaks some of the less important API - module/native-paths no
longer exists.
2019-02-16 13:21:29 -05:00
J.-F. Cap
0f0c415bcf Adde some tests for string/format 2019-02-16 16:28:10 +01:00
J.-F. Cap
a6f022a73d Added string/format function (snprintf like) 2019-02-16 03:29:04 +01:00
Calvin Rose
ec02d55145 Update README to show sourcehut build. 2019-02-15 19:58:25 -05:00
Calvin Rose
cb1a773ca8 Update sr.ht build. 2019-02-15 19:43:30 -05:00
Calvin Rose
0dc1217d69 Merge pull request #36 from charles-l/master
Update makefile for OpenBSD
2019-02-15 19:07:10 -05:00
charles
06f38d3380 Update makefile for OpenBSD 2019-02-15 19:02:14 -05:00
Calvin Rose
2e1ec3700d Fix compilier warning on -Os, gcc. 2019-02-15 19:01:47 -05:00
Calvin Rose
9e6b1d1b16 Add images.
Images are precompiled libraries. They can be created programmatically
via the `write-image` function and then loaded with `require` or
`import`. They can also be run by the command line tool - you must
specify the path to the image without the .jimage extension.
2019-02-15 18:56:41 -05:00
Calvin Rose
bdf03b4706 Fix unmarshalling integers directly, not through readint. 2019-02-15 14:01:32 -05:00
Calvin Rose
4d96ba3ba9 Merge branch 'master' of github.com:janet-lang/janet 2019-02-15 13:21:00 -05:00
Calvin Rose
f161002390 Address #35 2019-02-15 13:20:20 -05:00
Calvin Rose
eb576d6caf Merge pull request #33 from jfcap/master
Fix buffer (and string) used as callee for indexing.
2019-02-12 20:21:44 -05:00
J.-F. Cap
e0d26629e0 Fix buffer (and string) used as callee for indexing. 2019-02-12 23:40:59 +01:00
Calvin Rose
17783c3c3e Add tuple/brackets
Fix macro expansion via macex for bracketed tuples.
2019-02-11 18:37:59 -05:00
Calvin Rose
c64e92a5de Add some unused math functions.
Several functions from the C math library were
forgotten in the math module. These have been
added to the core library.
2019-02-10 12:03:22 -05:00
Calvin Rose
291c13bafc Merge pull request #32 from jfcap/master
Added math/abs binding
2019-02-10 11:57:28 -05:00
J.-F. Cap
c6672e62ac Added math/abs binding 2019-02-10 14:06:10 +01:00
Calvin Rose
eb9bd38256 Merge branch 'master' of github.com:janet-lang/janet 2019-02-09 12:24:20 -05:00
Calvin Rose
3ac6b2335a Merge pull request #31 from jfcap/crazy-brackets
Crazy brackets
2019-02-09 12:23:41 -05:00
Calvin Rose
c6edf03ae8 Fix some code style, add tuple/type function.
We need to be able to detect tuple type from janet code, otherwise
tuples will contain hidden state. The tuple/type function is able
to detect the flags in the tuple so the programmer can access them
if needed.
2019-02-09 12:21:11 -05:00
J.-F. Cap
5020a1bae9 Added marshalling code to save tuple_flag 2019-02-09 17:00:35 +01:00
J.-F. Cap
86ba69c16b Merge remote-tracking branch 'upstream/master' into crazy-brackets 2019-02-08 23:45:55 +01:00
J.-F. Cap
5f70024f87 Experimental stuffs with bracket syntax 2019-02-08 21:49:28 +01:00
Calvin Rose
9ff819a4a1 Fix build_win.bat 2019-02-08 15:02:36 -05:00
Calvin Rose
1244e2e93b Update changelog 2019-02-08 13:45:04 -05:00
Calvin Rose
b61d1a0a0e Try to update windows build for core image. 2019-02-08 13:37:14 -05:00
Calvin Rose
89ef4eb634 Update emscripten build. 2019-02-08 11:04:33 -05:00
Calvin Rose
114a45306d Add more specialization for marshaling integers.
This decreases the core image size by about 16.5k.
2019-02-08 10:14:36 -05:00
Calvin Rose
fe27df528c Boot core library from image rather than source
This should speed up start time and reduce malloc/free
usage to about 15% of what is what previously for startup.
The current cost is slightly larger binary as the representaion
of the image is currently less compact than source code.
2019-02-08 00:44:30 -05:00
J.-F. Cap
8ab60e475a typo in janet_indexed_view
(no consequence but look strange)
2019-02-08 01:10:07 +01:00
Calvin Rose
6321c30cb1 Add methods for file io. 2019-02-06 17:58:27 -05:00
Calvin Rose
8343c9edd1 Update example to use API. 2019-02-05 19:49:10 -05:00
Calvin Rose
74e1a3273f Add method syntax to parser. 2019-02-05 19:43:41 -05:00
Calvin Rose
1394dbbd57 Update license to include contributors.
Use 4 spaces for indentation.
2019-02-05 19:11:43 -05:00
Calvin Rose
f6a3853131 Merge pull request #30 from jfcap/get-set-abstract
Get set abstract
2019-02-05 19:09:56 -05:00
J.-F. Cap
49465f71f3 Added a simple C module to test getter/setter. 2019-02-05 18:45:04 +01:00
J.-F. Cap
960cf76eb5 Experimental getter/setter for abstract types 2019-02-05 17:14:13 +01:00
Calvin Rose
1b735564fa Update copyright. 2019-02-03 15:34:41 -05:00
Calvin Rose
7ae01d25dd Merge branch 'master' of github.com:janet-lang/janet 2019-02-03 15:32:53 -05:00
Calvin Rose
cb5263d2d8 Remove extra comment. 2019-02-03 15:32:39 -05:00
Calvin Rose
602092f6d5 Merge pull request #29 from honix/master
Gitter badge added
2019-02-02 18:06:06 -05:00
Fyodor Shchukin
d3a067a665 Gitter badge added 2019-02-02 10:30:15 +03:00
J.-F. Cap
98a26f5ce3 Merge remote-tracking branch 'upstream/master' 2019-02-02 00:38:29 +01:00
Calvin Rose
09d9dca5f5 Add Gitter channel to README.md 2019-02-01 13:43:16 -05:00
Calvin Rose
8a3f512746 Experimental changes to janet_call to make it faster.
Remove setjmp and fiber creationg from janet_call. This
adds the constraint to janet_call can only be called when there
is already a current fiber.
2019-02-01 11:56:25 -05:00
Calvin Rose
19e59705b9 Main rule in peg is always 0
After we changed peg bytecode emission to
preallocate space for an instruction before
emitting sub rules, the rules are numbered
in the order that they are compiled. This means
that the main rule is always 0.
We can remove the explicitly stored main rule in
the peg structure.
2019-01-31 23:39:33 -05:00
Calvin Rose
367c9da856 Fix some typos and update style.
Add bars.janet tool for templating arbitrary
strings, especially HTML.
2019-01-31 22:38:59 -05:00
Calvin Rose
4bcf6565cd Add parser/insert and bump to 0.4.0 2019-01-31 14:48:28 -05:00
Calvin Rose
0c950d0846 Fix emscripten build. 2019-01-31 13:02:09 -05:00
Calvin Rose
7ba925c50a Make getline more useful. 2019-01-31 12:34:22 -05:00
Calvin Rose
cb3b9dd76f Update changelog an fix typos. 2019-01-31 10:09:34 -05:00
Calvin Rose
f4fa55027b Merge pull request #27 from jfcap/master
Added :lflags option to cook/make-native
2019-01-31 09:39:59 -05:00
J.-F. Cap
0fe11adb9c typo in REAME.md 2019-01-31 13:52:57 +01:00
J.-F. Cap
b138ee6e8e Added :lflags option to cook/make-native 2019-01-31 13:30:37 +01:00
Calvin Rose
a66f19f636 Merge branch 'master' of github.com:janet-lang/janet 2019-01-30 23:11:42 -05:00
Calvin Rose
c76f4e89d8 Remove redundancies in stacktraces.
There was an implementation for stacktraces in both
run.c and in core.janet, status-pp. The commit removes
the one in core.janet in favor of the C based stacktrace, which
is exposed via debug/stacktrace. Lots of reshuffling of run-context
ensued as well, which resulted in an api that is a bit cleaner.
2019-01-30 23:11:12 -05:00
Calvin Rose
85a211b26b Remove extra vector function. 2019-01-30 21:22:40 -05:00
Calvin Rose
fe3620529f Merge pull request #26 from honix/master
Cooking on windows
2019-01-30 10:13:35 -05:00
Fyodor Shchukin
a7551e9b4e Cooking on windows 2019-01-30 17:31:53 +03:00
Calvin Rose
46c540b93e Add math headers for emscripten
We now check for NaN in table.c and struct.c
as we disallow NaN keys.
2019-01-29 18:18:14 -05:00
Calvin Rose
32c209ede9 Address #25 2019-01-29 13:59:08 -05:00
Calvin Rose
0d293cd3f5 Update require to use real path name rather than module name. 2019-01-28 21:48:13 -05:00
Calvin Rose
f284776490 Address #24 2019-01-28 20:30:45 -05:00
Calvin Rose
38a7e4faf1 Disallow NaN as table/struct key.
Fix bugs and add tests for denormalized tables
and structs.
2019-01-28 11:50:33 -05:00
Calvin Rose
c333cbfa55 0.3.0 2019-01-26 21:40:04 -05:00
Calvin Rose
f72aa64f41 0.3.2 2019-01-26 21:36:29 -05:00
Calvin Rose
d85892edc8 0.3.1 2019-01-26 21:34:08 -05:00
Calvin Rose
56383b2ecc Remove all traces of 'bakpakin/janet' from repo. 2019-01-26 21:26:40 -05:00
Calvin Rose
0d729eaab1 Appveyor is annoying. 2019-01-26 21:14:04 -05:00
Calvin Rose
17ab654ccb Messing with appveyor, trying travis. 2019-01-26 21:00:13 -05:00
Calvin Rose
872d03ae1d Update for version 0.4.0.
Version 0.3.0 never really happened, as no release
binaries were ever generated.
2019-01-26 20:46:40 -05:00
Calvin Rose
ee5fa54134 Generated files go to the same location on win32. 2019-01-26 17:33:30 -05:00
Calvin Rose
68e00cdb7a Update slurp and spit error handler. 2019-01-26 17:27:05 -05:00
Calvin Rose
5bf9e4fc89 Make amalg tool windows friendly
Convert / to \ in file paths for windows.
2019-01-26 17:17:56 -05:00
Calvin Rose
7350bf5dd9 Add anchors in generated docs
This allows us to link to specific functions.
2019-01-26 10:12:33 -05:00
Calvin Rose
e755f98300 Address #23 2019-01-25 20:31:08 -05:00
Calvin Rose
8ee2f0a1d6 Add amalgamation to windows distribution 2019-01-24 10:19:48 -05:00
Calvin Rose
0726de34ff Add description of embedding to README.md 2019-01-24 10:16:24 -05:00
Calvin Rose
00301ad26b Add build number to amalg build. 2019-01-24 00:26:57 -05:00
Calvin Rose
611543c48b Add source amalgamation
The amalgamated source concatenates all sources
to a file janet.c which can be used for
embedding janet, much in the same way as sqlite
or mongoose.
2019-01-24 00:15:58 -05:00
Calvin Rose
4d81fbc238 Add a changelog. 2019-01-22 15:23:42 -05:00
Calvin Rose
c5012ca4c1 Update man page. 2019-01-21 16:04:47 -05:00
Calvin Rose
e68a889fa9 Remove doc markdown and move it to website. 2019-01-21 13:49:44 -05:00
Calvin Rose
795e7a9de8 Make os/date results more consistent. 2019-01-20 16:49:39 -05:00
Calvin Rose
090a6a8c5c Add optional env arguments to eval functions. 2019-01-20 16:06:30 -05:00
Calvin Rose
2bbf9fdcc5 Add os/date to core library. 2019-01-20 14:34:33 -05:00
Calvin Rose
0025f6ac87 Export html-escape from highlight tool. 2019-01-20 13:31:26 -05:00
Calvin Rose
737b2449f0 Update highlight and the mainclient. 2019-01-20 10:05:51 -05:00
Calvin Rose
f7a0133eb1 Update highlight.janet (allow ! in symbols). 2019-01-20 08:53:34 -05:00
Calvin Rose
48b179d67e Add slurp and spit to the core library. 2019-01-19 22:00:33 -05:00
Calvin Rose
d1a075b2a6 Switch order of some text in the README.md 2019-01-19 13:03:42 -05:00
Calvin Rose
2bad24371d Add IRC location to README.md 2019-01-19 12:42:33 -05:00
Calvin Rose
bf8d5da3dc Fix possible memory leak on buffer overflow.
(All buffer push functions can panic (longjmp), skipping
 deinit. Instead, we should use the garbage collected api).
2019-01-19 12:32:52 -05:00
Calvin Rose
4a6fcb5e23 Address issue #21
Add some github highlighting to janet files (clojure is pretty close)
2019-01-19 12:11:54 -05:00
Calvin Rose
5ba969f91d Make match macro prettier. 2019-01-18 15:24:58 -05:00
Calvin Rose
26818a5e5c Fix doc generation. 2019-01-18 12:26:04 -05:00
Calvin Rose
b84b0e4828 Expose more of the module system.
The system path can more easily modified at runtime,
and the module/cache and module/loading tables are now exposed.
Properly cache native modules as well.
2019-01-18 12:04:34 -05:00
Calvin Rose
b4934ceddc Make parser errors a bit better for files with no closing
delimiters.
2019-01-17 23:43:46 -05:00
Calvin Rose
c4114fbcdb Add quote special to peg syntax to make captures terser. 2019-01-17 19:28:42 -05:00
Calvin Rose
95f2bbe0a0 Add highlight.janet tool which can highlight
janet source code and output html or terminal escaped code.
Also made re entrant calls into the vm provide better
error messages.
2019-01-17 18:12:26 -05:00
Calvin Rose
63137b8107 Fix parsing bug for numbers. 2019-01-17 12:32:51 -05:00
Calvin Rose
2c1b506213 Add tagged captures for a better (more correct) form of look behind. 2019-01-16 22:38:11 -05:00
Calvin Rose
612a245961 More work on peg. Disable indexed backrefs and replace substitution
with accumulation.
2019-01-16 21:11:55 -05:00
Calvin Rose
4b8edef58c Typo. 2019-01-16 12:34:01 -05:00
Calvin Rose
82cddef5bb Update man page and add early exit to number scanning for parser. 2019-01-16 12:32:33 -05:00
Calvin Rose
d0fc29338c Add error special form in Peg to allow construction of grammar errors
for more useful grammars that could eventually be used in a compiler.
2019-01-15 16:04:47 -05:00
Calvin Rose
4eeadd7463 Add optional form to peg (shorthand for (between 0 1 patt)). 2019-01-15 14:08:03 -05:00
Calvin Rose
f0fcdf6bc5 Update Peg.md text 2019-01-15 11:09:22 -05:00
Calvin Rose
2a333f8359 Add simple pattern examples to peg doc. 2019-01-15 11:05:51 -05:00
Calvin Rose
0dd867d508 Fix markup. 2019-01-14 22:33:33 -05:00
Calvin Rose
e3f902cb8a Update docs. 2019-01-14 22:31:57 -05:00
Calvin Rose
c651b6f67c Fix peg doc table. 2019-01-14 22:18:51 -05:00
Calvin Rose
3a9b50ea4a Update peg doc and remame some peg specials. 2019-01-14 22:17:13 -05:00
Calvin Rose
1304f9263b Update peg docs and make bad backrefs not error the whole pattern, but just cause the current match attempt to fail. 2019-01-14 21:47:55 -05:00
Calvin Rose
90313afd40 Update PEG documentation and peg syntax.
Disable tail calls in the root scope for better
stacktraces, as the root scope may contain a single call
to a failing function, as in the case of the test suite.
2019-01-14 20:41:32 -05:00
Calvin Rose
99f176f37b Fix windows build warnings. 2019-01-14 17:48:32 -05:00
Calvin Rose
d0ec89c7c1 Update Matchtime captures to not include all of the
matched text automatically, and fix pattern recursion
in grammars.
2019-01-14 17:44:21 -05:00
Calvin Rose
170e785b72 Fix recursion in grammars. 2019-01-14 15:06:35 -05:00
Calvin Rose
e53778d5d8 Remove annoying (fiber) text from stacktrace. 2019-01-14 12:08:36 -05:00
Calvin Rose
192705113e Add Matchtime captures to peg (Equivalent to LPegs lpeg.Cmt).
This allows that pattern to call an external function to
check if some text should match or not. This allows for
matching any possible language a computer can recognize.
2019-01-14 11:45:45 -05:00
Calvin Rose
97a42ea17b Address some windows issues in buffer.c 2019-01-14 00:12:25 -05:00
Calvin Rose
2cd489b9d4 Address windows build warnings. 2019-01-14 00:09:27 -05:00
Calvin Rose
ff0d3a0081 Compile pegs to bytecode with (peg/compile). Peg
performance is improved, and peg syntax has been expanded with a few
more keywords.
2019-01-13 23:54:41 -05:00
Calvin Rose
282c02c475 Update comments and text. 2019-01-12 20:22:03 -05:00
Calvin Rose
798c88b4c8 Update peg to allow functions over captures. Update C API
to make janet function calls easier and faster from C (still
needs an object pool for fibers, though). Fix bug in scan-number
and add many more peg tests.
2019-01-12 17:31:15 -05:00
Calvin Rose
83f4a11bf3 Add some more tests, add parameterized captures to patterns,
and fix some bugs.
2019-01-12 11:04:47 -05:00
Calvin Rose
d7626f8c57 Add more capturing capabilities including substitutions, as well
as back references for PEGs. More documentation is needed for PEG
syntax, but the amount required will need an external document, not
just a docstring.
2019-01-12 10:16:25 -05:00
Calvin Rose
1efca2ebe7 Add some preliminary capturing ability to PEGs. 2019-01-11 21:09:49 -05:00
Calvin Rose
40845b5c1b Initial peg implementation. Tree walk interpretted with
no captures, so not yet ready.
2019-01-11 19:22:24 -05:00
Calvin Rose
84fb07dd5a Add quiet option to main client. 2019-01-10 17:10:12 -05:00
Calvin Rose
62cb3f81fe Fix sorting in asm.c. Add README text. 2019-01-09 17:09:16 -05:00
Calvin Rose
16ebb11181 Add buffer/bit functions and buffer/blit. Expose janet_gethalfrange
in the C api for less duplicated range checking code.
2019-01-09 13:25:51 -05:00
Calvin Rose
115ed9cbb9 Move pretty printing to separate file pp.c
Simplify string.c and remove janet_puts.
2019-01-09 11:47:29 -05:00
Calvin Rose
3ae6f64de5 Fix popen bug. 2019-01-08 21:42:16 -05:00
Calvin Rose
ff3f7487a4 Add splice special form to grammar. 2019-01-08 20:05:36 -05:00
Calvin Rose
f0afb3c311 Update README to indicate how to get latest grammar file. 2019-01-08 20:02:01 -05:00
Calvin Rose
5b1a3b8208 Make grammar tool completely generate grammar from scratch.
Remove grammar from source tree.
2019-01-08 19:59:54 -05:00
Calvin Rose
b1e0849a2f Restore old status logic - (status checks in run_vm should be using
the previous status, not the current which is always JANET_STATUS_ALIVE)
2019-01-08 13:42:29 -05:00
Calvin Rose
67f26b7d72 Fix = should have been ==. Add some tests for vm type asserts. 2019-01-08 12:26:01 -05:00
Calvin Rose
d5bab72620 Add a test for making method calls 2019-01-07 14:54:39 -05:00
Calvin Rose
aa079e3145 Fix parser regression. 2019-01-07 14:49:38 -05:00
Calvin Rose
d64a57297d Update examples, add method like semantics to calling keywords. 2019-01-07 14:47:47 -05:00
Calvin Rose
be85196de8 Add callgrind task to Makefile.
Unify some parser states.
2019-01-06 21:49:24 -05:00
Calvin Rose
eae4e0dede Add functionality that allows the set macro to
take a tuple as an l-value. Remove the old
multi-sym report in anticipation of a different
mechanism.
2019-01-06 19:33:27 -05:00
Calvin Rose
92e9e64945 Update CONTRIBUTING.md and make valtest 2019-01-06 12:32:44 -05:00
Calvin Rose
63dd6d03f4 Fix english 2019-01-06 12:05:40 -05:00
Calvin Rose
2a79d2e749 Remove check for function calls to enable all types,
even nil. Now any value can be called as a function, usually
looking itself up in an associative data structure.
2019-01-06 11:56:40 -05:00
Calvin Rose
6f3bc3d577 Update copyright date, fix types, remove trailing whitespace. 2019-01-06 03:23:03 -05:00
Calvin Rose
ef5eed2c21 Add source location to doc macro. 2019-01-06 02:10:56 -05:00
Calvin Rose
5865692401 Surround embedded documentation with a macro so it
can be disabled in a future build.
2019-01-06 01:49:56 -05:00
Calvin Rose
b626e73d19 Add extra argument to (native) to allow for passing
in custom environment to add stuff to.
2019-01-05 23:37:10 -05:00
Calvin Rose
b535c91ee1 Fix native module issue. 2019-01-05 22:52:28 -05:00
Calvin Rose
7b28032f5c More explicit casts to please Microsoft compiler. 2019-01-05 21:58:39 -05:00
Calvin Rose
0fdd404a71 Remove duplicate functionality in string.c 2019-01-05 21:23:44 -05:00
Calvin Rose
1f98eff33a Fix compiler warnings on emscripten. 2019-01-05 20:52:32 -05:00
Calvin Rose
338b31f5a2 Add janet_fixarity. Update emscripten source. 2019-01-05 20:45:24 -05:00
Calvin Rose
b60e3e302a Update C API to use friendlier functions rather than macros.
Error handling is implemented with setjmp/longjmp so code
can be more concise. This required a very large but straight forward refactor for all
of the libraries.
2019-01-05 20:09:03 -05:00
Calvin Rose
5b62c8e6db Better working panic implementation and more cleanup in main vm loop. 2019-01-05 00:33:20 -05:00
Calvin Rose
cd6a7793e8 WIP panic functionality. 2019-01-04 23:20:34 -05:00
Calvin Rose
5afb00859a More cleanup in vm.c 2019-01-04 21:15:37 -05:00
Calvin Rose
001917f8d9 Begin clean up of vm.c
Replace the oparg macro with 5 named virtual registers, combine
pc++ with vm_next() macro to be more terse, and move setup and
teardown logic of janet_continue into a separate function.

These changes are preparation for using setjmp/longjmp to do
error handling in the VM. Introducing longjmp for error handling in
the VM would allow it to be used in the C API, which could result in
simpler, more compact code.
2019-01-04 20:08:43 -05:00
Calvin Rose
b9c0fc8201 Allow calling keywords and symbols as functions to look
themselves up in a data structure. Allow calling  a data
structure to look up the argument.
2019-01-03 22:48:43 -05:00
Calvin Rose
d8b0a5ed01 Make parser API more robust - the value queue is now
distinct from the parse state, and is queried separately.
2019-01-03 20:48:54 -05:00
Calvin Rose
5fa96a6f8c Add documentation on all of the special forms. 2019-01-03 17:16:34 -05:00
Calvin Rose
dd3fc24a1e Make number syntax a bit stricter - no leading underscores
and no underscores in exponent.
2019-01-03 12:13:14 -05:00
Calvin Rose
ddba0010b0 Make test output less verbose. 2019-01-02 23:06:23 -05:00
Calvin Rose
337a498edb Fix some keyword related issues. 2019-01-02 22:08:51 -05:00
Calvin Rose
5fff36d047 Remove janet_symbol_from_string api function. 2019-01-02 20:50:31 -05:00
Calvin Rose
a679f60e07 Add assembly test. 2019-01-02 19:58:27 -05:00
Calvin Rose
58d480539c Fix assembler labels after keyword update. 2019-01-02 19:55:42 -05:00
Calvin Rose
6afaacf2af Update documentation on keywords. 2019-01-02 19:46:24 -05:00
Calvin Rose
e9c94598e6 Add native keyword type to replace symbols with leading ':'
character.
2019-01-02 19:41:07 -05:00
Calvin Rose
29ec30c79f Fix number parsing for bases between 2 and 9.
Allow multisyms to have number keys.
2019-01-02 16:39:24 -05:00
Calvin Rose
122312dbf6 Fix some typos and update comments. 2019-01-02 12:21:59 -05:00
Calvin Rose
618f8d6818 Add with-syms and combine bignat_add and bignatr mul
into a single operation for strtod.c
2019-01-02 10:23:11 -05:00
Calvin Rose
0d4ab7dee0 Add some more test cases for bad arities. 2018-12-30 18:44:00 -05:00
Calvin Rose
6b4824c2ab Fix error behavior when calling functions with incorrect arities. 2018-12-30 18:41:44 -05:00
Calvin Rose
8dde89126e Fix -s flag in janet binary. 2018-12-30 18:23:29 -05:00
Calvin Rose
56927e1b81 Fix -e option. 2018-12-30 17:51:15 -05:00
Calvin Rose
9e6254bf56 Rename pre-walk and post-walk to prewalk and postwalk. 2018-12-30 15:34:01 -05:00
Calvin Rose
fe22a8db39 Fix 32 bit platforms janet number handling. 2018-12-30 14:23:52 -05:00
Calvin Rose
d724c5b959 Update number representation so that wrapping numbers isn't
doesn't need to check for NaNs. Change ordering of types.
2018-12-30 12:37:50 -05:00
Calvin Rose
ca9c017ec4 Remove some unnecessary bounds checks. 2018-12-29 20:07:56 -05:00
Calvin Rose
65be318306 Update grammar. 2018-12-29 18:04:23 -05:00
Calvin Rose
7c4671d98f Update loop documentation. 2018-12-29 17:42:44 -05:00
Calvin Rose
7880d73201 Add some documentation for looping and the loop macro.
Also add :pairs verb to the loop macro and some more tests.
2018-12-29 17:23:31 -05:00
Calvin Rose
00f0f628e8 Shrink gif some more. 2018-12-29 13:21:13 -05:00
Calvin Rose
21b7583a7c Shrink image in README 2018-12-29 13:20:13 -05:00
Calvin Rose
42c6aca526 Shrink gif. 2018-12-29 13:17:45 -05:00
Calvin Rose
52b8781684 .. 2018-12-29 13:14:59 -05:00
Calvin Rose
5d39570ec9 Update README.md 2018-12-29 13:13:57 -05:00
Calvin Rose
28331ad6ab Update buffer/push-integer to buffer/push-word. 2018-12-29 13:07:18 -05:00
Calvin Rose
129ec1e3c5 Don't use initialization syntax {0}. 2018-12-29 12:02:51 -05:00
Calvin Rose
bdcd3a3dbf Update strtod.c, cleaning up code.
Rename Mant -> BigNat, fix multiply code
so we can use 31 bits per digit.
2018-12-29 11:29:20 -05:00
Calvin Rose
6c8f49206d Add some more number tests. Crossing fingers
hoping windows will work.
2018-12-29 01:31:01 -05:00
Calvin Rose
b06f7226c4 Add number test. 2018-12-29 01:16:54 -05:00
Calvin Rose
2bcedd5920 Remove indexing with numeric constants from janet. 2018-12-28 23:44:39 -05:00
Calvin Rose
5c84f0f5d9 Work on number code for more expected behavior and better rounding.
Still needs work and testing.
2018-12-28 23:32:09 -05:00
Calvin Rose
424073bbb8 Update cook tool to not rebuild files unless it needs to. 2018-12-27 14:13:10 -05:00
Calvin Rose
e9a80d4e4a Bump version, fix doc and typos, update grammar. 2018-12-27 13:36:27 -05:00
Calvin Rose
1ec7f04642 Avoid warning in asm.c on windows. 2018-12-27 13:19:16 -05:00
Calvin Rose
59f6c335ad Update documentation to remove references of integers and real numbers.
Now there is only one kind of number.
2018-12-27 13:13:02 -05:00
Calvin Rose
6b95326d7c First commit removing the integer number type. This should
remove some complexity and unexpected behavior around numbers in
general as all numbers are the same number type, IEEE 754 double
precision numbers. Also update examples and tests, some of which were
out of date.

Some more testing may be needed for new changes to numbers.
2018-12-27 13:05:29 -05:00
Calvin Rose
5a3190d471 Update cook tool to allow embedding sources. 2018-12-26 22:40:19 -05:00
Calvin Rose
e7a8958c63 Move grammar helper to tools directory. 2018-12-25 17:38:54 -05:00
Calvin Rose
017ee2b0d1 Move gendoc.janet script. 2018-12-25 17:37:52 -05:00
Calvin Rose
a7933f5f08 Move janet natives to new repos. 2018-12-25 17:33:35 -05:00
Calvin Rose
be7fc79b6f Update README to refer to janet-lang/janet repository. 2018-12-25 15:45:18 -05:00
Calvin Rose
6c8da9fe5c Install cook tool when installing janet. 2018-12-25 15:39:24 -05:00
Calvin Rose
17283241ab Fix bug in compiler with if form under certain conditions.
Begin bundled 'cook' tool for managing janet projects.
2018-12-25 15:32:42 -05:00
168 changed files with 30421 additions and 14085 deletions

View File

@@ -1,11 +0,0 @@
image: freebsd
packages:
- gmake
- gcc
sources:
- https://github.com/bakpakin/janet.git
tasks:
- build: |
cd janet
gmake CC=gcc
gmake test CC=gcc

12
.builds/freebsd.yml Normal file
View File

@@ -0,0 +1,12 @@
image: freebsd/12.x
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- gmake
tasks:
- build: |
cd janet
gmake
gmake test
sudo gmake install
gmake test-install

14
.builds/meson.yml Normal file
View File

@@ -0,0 +1,14 @@
image: openbsd/latest
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- meson
tasks:
- build: |
cd janet
meson setup build --buildtype=release
cd build
ninja
ninja test
doas ninja install
doas jpm --verbose install circlet

15
.builds/meson2.yml Normal file
View File

@@ -0,0 +1,15 @@
image: openbsd/latest
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- meson
tasks:
- build: |
cd janet
meson setup build --buildtype=release
cd build
meson configure -Dprf=true
ninja
ninja test
doas ninja install
doas jpm --verbose install circlet

22
.builds/meson_min.yml Normal file
View File

@@ -0,0 +1,22 @@
image: openbsd/latest
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- meson
tasks:
- build: |
cd janet
meson setup build --buildtype=release
cd build
meson configure -Dsingle_threaded=true
meson configure -Dnanbox=false
meson configure -Ddynamic_modules=false
meson configure -Ddocstrings=false
meson configure -Dnet=false
meson configure -Dsourcemaps=false
meson configure -Dpeg=false
meson configure -Dassembler=false
meson configure -Dint_types=false
meson configure -Dtyped_array=false
meson configure -Dreduced_os=true
ninja # will not pass tests but should build

12
.builds/openbsd.yml Normal file
View File

@@ -0,0 +1,12 @@
image: openbsd/latest
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- gmake
tasks:
- build: |
cd janet
gmake
gmake test
doas gmake install
gmake test-install

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.janet linguist-language=Clojure

25
.gitignore vendored
View File

@@ -4,6 +4,7 @@ dst
janet
!*/**/janet
/build
/builddir
/Build
/Release
/Debug
@@ -12,6 +13,25 @@ janet
janet-*.tar.gz
dist
# jpm lockfile
lockfile.janet
# Kakoune (fzf via fd)
.fdignore
# VSCode
.vscode
# Eclipse
.project
.cproject
# Gnome Builder
.buildconfig
# Local directory for testing
local
# Emscripten
*.bc
janet.js
@@ -39,6 +59,11 @@ tags
# Valgrind files
vgcore.*
*.out.*
# Wix artifacts
*.msi
*.wixpdb
# Created by https://www.gitignore.io/api/c

View File

@@ -2,6 +2,8 @@ language: c
script:
- make
- make test
- sudo make install
- make test-install
- make build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
compiler:
- clang
@@ -19,5 +21,5 @@ deploy:
skip_cleanup: true
on:
tags: true
repo: bakpakin/janet
repo: janet-lang/janet
condition: "$CC = clang"

464
CHANGELOG.md Normal file
View File

@@ -0,0 +1,464 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.12.1 - 2020-09-07
- Make `zero?`, `one?`, `pos?`, and `neg?` polymorphic.
- Add C++ support to jpm and improve C++ interop in janet.h.
- Add `%t` formatter to `printf`, `string/format`, and other formatter functions.
- Expose `janet_cfuns_prefix` in C API.
- Add `os/proc-wait` and `os/proc-kill` for interacting with processes.
- Add `janet_getjfile` to C API.
- Allow redirection of stdin, stdout, and stderr by passing keywords in the env table in `os/spawn` and `os/execute`.
- Add `os/spawn` to get a core/process back instead of an exit code as in `os/execute`.
When called like this, `os/execute` returns immediately.
- Add `:x` flag to os/execute to raise error when exit code is non-zero.
- Don't run `main` when flychecking.
- Add `:n` flag to `file/open` to raise an error if file cannot be opened.
- Fix import macro to not try and coerce everything to a string.
- Allow passing a second argument to `disasm`.
- Add `cancel`. Resumes a fiber but makes it immediately error at the yield point.
- Allow multi-line paste into built in repl.
- Add `(curenv)`.
- Change `net/read`, `net/chunk`, and `net/write` to raise errors in the case of failures.
- Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop
to raise errors or other signals.
- Update meson build script to fix bug on Debian's version of meson
- Add `xprint`, `xprin`, `xprintf`, and `xprinf`.
- `net/write` now raises an error message if write fails.
- Fix issue with SIGPIPE on macOS and BSDs.
## 1.11.3 - 2020-08-03
- Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled.
- Expose `janet_cryptorand` in C API.
- Properly initialize PRF in default janet program
- Add `index-of` to core library.
- Add `-fPIC` back to core CFLAGS (non-optional when compiling default client with Makefile)
- Fix defaults on Windows for ARM
- Fix defaults on NetBSD.
## 1.11.1 - 2020-07-25
- Fix jpm and git with multiple git installs on Windows
- Fix importing a .so file in the current directory
- Allow passing byte sequence types directly to typed-array constructors.
- Fix bug sending files between threads.
- Disable PRF by default.
- Update the soname.
## 1.11.0 - 2020-07-18
- Add `forever` macro.
- Add `any?` predicate to core.
- Add `jpm list-pkgs` subcommand to see which package aliases are in the listing.
- Add `jpm list-installed` subcommand to see which packages are installed.
- Add `math/int-min`, `math/int-max`, `math/int32-min`, and `math/int32-max` for getting integer limits.
- The gc interval is now autotuned, to prevent very bad gc behavior.
- Improvements to the bytecode compiler, Janet will now generate more efficient bytecode.
- Add `peg/find`, `peg/find-all`, `peg/replace`, and `peg/replace-all`
- Add `math/nan`
- Add `forv` macro
- Add `symbol/slice`
- Add `keyword/slice`
- Allow cross compilation with Makefile.
- Change `compare-primitve` to `cmp` and make it more efficient.
- Add `reverse!` for reversing an array or buffer in place.
- `janet_dobytes` and `janet_dostring` return parse errors in \*out
- Add `repeat` macro for iterating something n times.
- Add `eachy` (each yield) macro for iterating a fiber.
- Fix `:generate` verb in loop macro to accept non symbols as bindings.
- Add `:h`, `:h+`, and `:h*` in `default-peg-grammar` for hexidecimal digits.
- Fix `%j` formatter to print numbers precisely (using the `%.17g` format string to printf).
## 1.10.1 - 2020-06-18
- Expose `janet_table_clear` in API.
- Respect `JANET_NO_PROCESSES` define when building
- Fix `jpm` rules having multiple copies of the same dependency.
- Fix `jpm` install in some cases.
- Add `array/trim` and `buffer/trim` to shrink the backing capacity of these types
to their current length.
## 1.10.0 - 2020-06-14
- Hardcode default jpm paths on install so env variables are needed in fewer cases.
- Add `:no-compile` to `create-executable` option for jpm.
- Fix bug with the `trace` function.
- Add `:h`, `:a`, and `:c` flags to `thread/new` for creating new kinds of threads.
By default, threads will now consume much less memory per thread, but sending data between
threads may cost more.
- Fix flychecking when using the `use` macro.
- CTRL-C no longer exits the repl, and instead cancels the current form.
- Various small bug fixes
- New MSI installer instead of NSIS based installer.
- Make `os/realpath` work on windows.
- Add polymorphic `compare` functions for comparing numbers.
- Add `to` and `thru` peg combinators.
- Add `JANET_GIT` environment variable to jpm to use a specific git binary (useful mainly on windows).
- `asm` and `disasm` functions now use keywords instead of macros for keys. Also
some slight changes to the way constants are encoded (remove wrapping `quote` in some cases).
- Expose current macro form inside macros as (dyn :macro-form)
- Add `tracev` macro.
- Fix compiler bug that emitted incorrect code in some cases for while loops that create closures.
- Add `:fresh` option to `(import ...)` to overwrite the module cache.
- `(range x y 0)` will return an empty array instead of hanging forever.
- Rename `jpm repl` to `jpm debug-repl`.
## 1.9.1 - 2020-05-12
- Add :prefix option to declare-source
- Re-enable minimal builds with the debugger.
- Add several flags for configuring Janet on different platforms.
- Fix broken meson build from 1.9.0 and add meson to CI.
- Fix compilation issue when nanboxing is disabled.
## 1.9.0 - 2020-05-10
- Add `:ldflags` option to many jpm declare functions.
- Add `errorf` to core.
- Add `lenprefix` combinator to PEGs.
- Add `%M`, `%m`, `%N`, and `%n` formatters to formatting functions. These are the
same as `%Q`, `%q`, `%P`, and `%p`, but will not truncate long values.
- Add `fiber/root`.
- Add beta `net/` module to core for socket based networking.
- Add the `parse` function to parse strings of source code more conveniently.
- Add `jpm rule-tree` subcommand.
- Add `--offline` flag to jpm to force use of the cache.
- Allow sending pointers and C functions across threads via `thread/send`.
- Fix bug in `getline`.
- Add `sh-rule` and `sh-phony` to jpm's dialect of Janet.
- Change C api's `janet_formatb` -> `janet_formatbv`, and add new function `janet_formatb` to C api.
- Add `edefer` macro to core.
- A struct/table literal/constructor with duplicate keys will use the last value given.
Previously, this was inconsistent between tables and structs, literals and constructor functions.
- Add debugger to core. The debugger functions are only available
in a debug repl, and are prefixed by a `.`.
- Add `sort-by` and `sorted-by` to core.
- Support UTF-8 escapes in strings via `\uXXXX` or `\UXXXXXX`.
- Add `math/erf`
- Add `math/erfc`
- Add `math/log1p`
- Add `math/next`
- Add os/umask
- Add os/perm-int
- Add os/perm-string
- Add :int-permissions option for os/stat.
- Add `jpm repl` subcommand, as well as `post-deps` macro in project.janet files.
- Various bug fixes.
## 1.8.1 - 2020-03-31
- Fix bugs for big endian systems
- Fix 1.8.0 regression on BSDs
## 1.8.0 - 2020-03-29
- Add `reduce2`, `accumulate`, and `accumulate2`.
- Add lockfiles to `jpm` via `jpm make-lockfile` and `jpm load-lockfile`.
- Add `os/realpath` (Not supported on windows).
- Add `os/chmod`.
- Add `chr` macro.
- Allow `_` in the `match` macro to match anything without creating a binding
or doing unification. Also change behavior of matching nil.
- Add `:range-to` and `:down-to` verbs in the `loop` macro.
- Fix `and` and `or` macros returning nil instead of false in some cases.
- Allow matching successfully against nil values in the `match` macro.
- Improve `janet_formatc` and `janet_panicf` formatters to be more like `string/format`.
This makes it easier to make nice error messages from C.
- Add `signal`
- Add `fiber/can-resume?`
- Allow fiber functions to accept arguments that are passed in via `resume`.
- Make flychecking slightly less strict but more useful
- Correct arity for `next`
- Correct arity for `marshal`
- Add `flush` and `eflush`
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
- Fix bug in buffer/blit when using the offset-src argument.
- Fix segfault with malformed pegs.
## 1.7.0 - 2020-02-01
- Remove `file/fileno` and `file/fdopen`.
- Remove `==`, `not==`, `order<`, `order>`, `order<=`, and `order>=`. Instead, use the normal
comparison and equality functions.
- Let abstract types define a hash function and comparison/equality semantics. This lets
abstract types much better represent value types. This adds more fields to abstract types, which
will generate warnings when compiled against other versions.
- Remove Emscripten build. Instead, use the amalgamated source code with a custom toolchain.
- Update documentation.
- Add `var-`
- Add `module/add-paths`
- Add `file/temp`
- Add `mod` function to core.
- Small bug fixes
- Allow signaling from C functions (yielding) via janet\_signalv. This
makes it easy to write C functions that work with event loops, such as
in libuv or embedded in a game.
- Add '%j' formatting option to the format family of functions.
- Add `defer`
- Add `assert`
- Add `when-with`
- Add `if-with`
- Add completion to the default repl based on currently defined bindings. Also generally improve
the repl keybindings.
- Add `eachk`
- Add `eachp`
- Improve functionality of the `next` function. `next` now works on many different
types, not just tables and structs. This allows for more generic data processing.
- Fix thread module issue where sometimes decoding a message failed.
- Fix segfault regression when macros are called with bad arity.
## 1.6.0 - 2019-12-22
- Add `thread/` module to the core.
- Allow seeding RNGs with any sequence of bytes. This provides
a wider key space for the RNG. Exposed in C as `janet_rng_longseed`.
- Fix issue in `resume` and similar functions that could cause breakpoints to be skipped.
- Add a number of new math functions.
- Improve debugger experience and capabilities. See examples/debugger.janet
for what an interactive debugger could look like.
- Add `debug/step` (janet\_step in the C API) for single stepping Janet bytecode.
- The built in repl now can enter the debugger on any signal (errors, yields,
user signals, and debug signals). To enable this, type (setdyn :debug true)
in the repl environment.
- When exiting the debugger, the fiber being debugged is resumed with the exit value
of the debug session (the value returned by `(quit return-value)`, or nil if user typed Ctrl-D).
- `(quit)` can take an optional argument that is the return value. If a module
contains `(quit some-value)`, the value of that module returned to `(require "somemod")`
is the return value. This lets module writers completely customize a module without writing
a loader.
- Add nested quasiquotation.
- Add `os/cryptorand`
- Add `prinf` and `eprinf` to be have like `printf` and `eprintf`. The latter two functions
now including a trailing newline, like the other print functions.
- Add nan?
- Add `janet_in` to C API.
- Add `truthy?`
- Add `os/environ`
- Add `buffer/fill` and `array/fill`
- Add `array/new-filled`
- Use `(doc)` with no arguments to see available bindings and dynamic bindings.
- `jpm` will use `CC` and `AR` environment variables when compiling programs.
- Add `comptime` macro for compile time evaluation.
- Run `main` functions in scripts if they exist, just like jpm standalone binaries.
- Add `protect` macro.
- Add `root-env` to get the root environment table.
- Change marshalling protocol with regard to abstract types.
- Add `show-paths` to `jpm`.
- Add several default patterns, like `:d` and `:s+`, to PEGs.
- Update `jpm` path settings to make using `jpm` easier on non-global module trees.
- Numerous small bug fixes and usability improvements.
### 1.5.1 - 2019-11-16
- Fix bug when printing buffer to self in some edge cases.
- Fix bug with `jpm` on windows.
- Fix `update` return value.
## 1.5.0 - 2019-11-10
- `os/date` now defaults to UTC.
- Add `--test` flag to jpm to test libraries on installation.
- Add `math/rng`, `math/rng-int`, and `math/rng-uniform`.
- Add `in` function to index in a stricter manner. Conversely, `get` will
now not throw errors on bad keys.
- Indexed types and byte sequences will now error when indexed out of range or
with bad keys.
- Add rng functions to Janet. This also replaces the RNG behind `math/random`
and `math/seedrandom` with a consistent, platform independent RNG.
- Add `with-vars` macro.
- Add the `quickbin` command to jpm.
- Create shell.c when making the amalgamated source. This can be compiled with
janet.c to make the janet interpreter.
- Add `cli-main` function to the core, which invokes Janet's CLI interface.
This basically moves what was init.janet into boot.janet.
- Improve flychecking, and fix flychecking bugs introduced in 1.4.0.
- Add `prin`, `eprint`, `eprintf` and `eprin` functions. The
functions prefix with e print to `(dyn :err stderr)`
- Print family of functions can now also print to buffers
(before, they could only print to files.) Output can also
be completely disabled with `(setdyn :out false)`.
- `printf` is now a c function for optimizations in the case
of printing to buffers.
## 1.4.0 - 2019-10-14
- Add `quit` function to exit from a repl, but not always exit the entire
application.
- Add `update-pkgs` to jpm.
- Integrate jpm with https://github.com/janet-lang/pkgs.git. jpm can now
install packages based on their short names in the package listing, which
can be customized via an env variable.
- Add `varfn` macro
- Add compile time arity checking when function in function call is known.
- Added `slice` to the core library.
- The `*/slice` family of functions now can take nil as start or end to get
the same behavior as the defaults (0 and -1) for those parameters.
- `string/` functions that take a pattern to search for will throw an error
when receiving the empty string.
- Replace (start:end) style stacktrace source position information with
line, column. This should be more readable for humans. Also, range information
can be recovered by re-parsing source.
## 1.3.1 - 2019-09-21
- Fix some linking issues when creating executables with native dependencies.
- jpm now runs each test script in a new interpreter.
- Fix an issue that prevent some valid programs from compiling.
- Add `mean` to core.
- Abstract types that implement the `:+`, `:-`, `:*`, `:/`, `:>`, `:==`, `:<`,
`:<=`, and `:>=` methods will work with the corresponding built-in
arithmetic functions. This means built-in integer types can now be used as
normal number values in many contexts.
- Allow (length x) on typed arrays an other abstract types that implement
the :length method.
## 1.3.0 - 2019-09-05
- Add `get-in`, `put-in`, `update-in`, and `freeze` to core.
- Add `jpm run rule` and `jpm rules` to jpm to improve utility and discoverability of jpm.
- Remove `cook` module and move `path` module to https://github.com/janet-lang/path.git.
The functionality in `cook` is now bundled directly in the `jpm` script.
- Add `buffer/format` and `string/format` format flags `Q` and `q` to print colored and
non-colored single-line values, similar to `P` and `p`.
- Change default repl to print long sequences on one line and color stacktraces if color is enabled.
- Add `backmatch` pattern for PEGs.
- jpm detects if not in a Developer Command prompt on windows for a better error message.
- jpm install git submodules in dependencies
- Change default fiber stack limit to the maximum value of a 32 bit signed integer.
- Some bug fixes with `jpm`
- Fix bugs with pegs.
- Add `os/arch` to get ISA that janet was compiled for
- Add color to stacktraces via `(dyn :err-color)`
## 1.2.0 - 2019-08-08
- Add `take` and `drop` functions that are easier to use compared to the
existing slice functions.
- Add optional default value to `get`.
- Add function literal short-hand via `|` reader macro, which maps to the
`short-fn` macro.
- Add `int?` and `nat?` functions to the core.
- Add `(dyn :executable)` at top level to get what used to be
`(process/args 0)`.
- Add `:linux` to platforms returned by `(os/which)`.
- Update jpm to build standalone executables. Use `declare-executable` for this.
- Add `use` macro.
- Remove `process/args` in favor of `(dyn :args)`.
- Fix bug with Nanbox implementation allowing users to created
custom values of any type with typed array and marshal modules, which
was unsafe.
- Add `janet_wrap_number_safe` to API, for converting numbers to Janets
where the number could be any 64 bit, user provided bit pattern. Certain
NaN values (which a machine will never generate as a result of a floating
point operation) are guarded against and converted to a default NaN value.
## 1.1.0 - 2019-07-08
- Change semantics of `-l` flag to be import rather than dofile.
- Fix compiler regression in top level defs with destructuring.
- Add `table/clone`.
- Improve `jpm` tool with git and dependency capabilities, as well as better
module uninstalls.
## 1.0.0 - 2019-07-01
- Add `with` macro for resource handling.
- Add `propagate` function so we can "rethrow" signals after they are
intercepted. This makes signals even more flexible.
- Add `JANET_NO_DOCSTRINGS` and `JANET_NO_SOURCEMAPS` defines in janetconf.h
for shrinking binary size.
This seems to save about 50kB in most builds, so it's not usually worth it.
- Update module system to allow relative imports. The `:cur:` pattern
in `module/expand-path` will expand to the directory part of the current file, or
whatever the value of `(dyn :current-file)` is. The `:dir:` pattern gets
the directory part of the input path name.
- Remove `:native:` pattern in `module/paths`.
- Add `module/expand-path`
- Remove `module/*syspath*` and `module/*headerpath*` in favor of dynamic
bindings `:syspath` and `:headerpath`.
- Compiled PEGs can now be marshaled and unmarshaled.
- Change signature to `parser/state`
- Add `:until` verb to loop.
- Add `:p` flag to `fiber/new`.
- Add `file/{fdopen,fileno}` functions.
- Add `parser/clone` function.
- Add optional argument to `parser/where` to set parser byte index.
- Add optional `env` argument to `all-bindings` and `all-dynamics`.
- Add scratch memory C API functions for auto-released memory on next gc.
Scratch memory differs from normal GCed memory as it can also be freed normally
for better performance.
- Add API compatibility checking for modules. This will let native modules not load
when the host program is not of a compatible version or configuration.
- Change signature of `os/execute` to be much more flexible.
## 0.6.0 - 2019-05-29
- `file/close` returns exit code when closing file opened with `file/popen`.
- Add `os/rename`
- Update windows installer to include tools like `jpm`.
- Add `jpm` tool for building and managing projects.
- Change interface to `cook` tool.
- Add optional filters to `module/paths` to further refine import methods.
- Add keyword arguments via `&keys` in parameter list.
- Add `-k` flag for flychecking source.
- Change signature to `compile` function.
- Add `module/loaders` for custom loading functions.
- Add external unification to `match` macro.
- Add static library to main build.
- Add `janet/*headerpath*` and change location of installed headers.
- Let `partition` take strings.
- Haiku OS support
- Add `string/trim`, `string/trimr`, and `string/triml`.
- Add `dofile` function.
- Numbers require at least 1 significant digit.
- `file/read` will return nil on end of file.
- Fix various bugs.
## 0.5.0 - 2019-05-09
- Fix some bugs with buffers.
- Add `trace` and `untrace` to the core library.
- Add `string/has-prefix?` and `string/has-suffix?` to string module.
- Add simple debugger to repl that activates on errors or debug signal
- Remove `*env*` and `*doc-width*`.
- Add `fiber/getenv`, `fiber/setenv`, and `dyn`, and `setdyn`.
- Add support for dynamic bindings (via the `dyn` and `setdyn` functions).
- Change signatures of some functions like `eval` which no longer takes
an optional environment.
- Add printf function
- Make `pp` configurable with dynamic binding `:pretty-format`.
- Remove the `meta` function.
- Add `with-dyns` for blocks with dynamic bindings assigned.
- Allow leading and trailing newlines in backtick-delimited string (long strings).
These newlines will not be included in the actual string value.
## 0.4.1 - 2019-04-14
- Squash some bugs
- Peg patterns can now make captures in any position in a grammar.
- Add color to repl output
- Add array/remove function
- Add meson build support
- Add int module for int types
- Add meson build option
- Add (break) special form and improve loop macro
- Allow abstract types to specify custom tostring method
- Extend C API for marshalling abstract types and other values
- Add functions to `os` module.
## 0.4.0 - 2019-03-08
- Fix a number of smaller bugs
- Added :export option to import and require
- Added typed arrays
- Remove `callable?`.
- Remove `tuple/append` and `tuple/prepend`, which may have seemed like `O(1)`
operations. Instead, use the `splice` special to extend tuples.
- Add `-m` flag to main client to allow specifying where to load
system modules from.
- Add `-c` flag to main client to allow compiling Janet modules to images.
- Add `string/format` and `buffer/format`.
- Remove `string/pretty` and `string/number`.
- `make-image` function creates pre compiled images for janet. These images
link to the core library. They can be loaded via require or manually via
`load-image`.
- Add bracketed tuples as tuple constructor.
- Add partition function to core library.
- Pre-compile core library into an image for faster startup.
- Add methods to parser values that mirror the api.
- Add janet\_getmethod to CAPI for easier use of method like syntax.
- Add get/set to abstract types to allow them to behave more
like objects with methods.
- Add parser/insert to modify parser state programmatically
- Add debug/stacktrace for easy, pretty stacktraces
- Remove the status-pp function
- Update API to run-context to be much more sane
- Add :lflags option to cook/make-native
- Disallow NaNs as table or struct keys
- Update module resolution paths and format
## 0.3.0 - 2019-01-26
- Add amalgamated build to janet for easier embedding.
- Add os/date function
- Add slurp and spit to core library.
- Added this changelog.
- Added peg module (Parsing Expression Grammars)
- Move hand written documentation into website repository.

View File

@@ -29,9 +29,42 @@ may require changes before being merged.
run tests with `make test`. If you want to add a new test suite, simply add a file to
the test folder and make sure it is run when`make test` is invoked.
* Be consistent with the style. For C this means follow the indentation and style in
other files (files have MIT license at top, 4 spaces indentation, no trailing whitespace, cuddled brackets, etc.)
For janet code, the use lisp indentation with 2 spaces. One can use janet.vim to
do this indentation, or approximate as close as possible.
other files (files have MIT license at top, 4 spaces indentation, no trailing
whitespace, cuddled brackets, etc.) Use `make format` to
automatically format your C code with
[astyle](http://astyle.sourceforge.net/astyle.html). You will probably need
to install this, but it can be installed with most package managers.
For janet code, use lisp indentation with 2 spaces. One can use janet.vim to
do this indentation, or approximate as close as possible. There is a janet formatter
in [spork](https://github.com/janet-lang/spork.git) that can be used to format code as well.
## C style
For changes to the VM and Core code, you will probably need to know C. Janet is programmed with
a subset of C99 that works with Microsoft Visual C++. This means most of C99 but with the following
omissions.
* No `restrict`
* Certain functions in the standard library are not always available
In practice, this means programming for both MSVC on one hand and everything else on the other.
The code must also build with emscripten, even if some features are not available, although
this is not a priority.
Code should compile warning free and run valgrind clean. I find that these two criteria are some
of the easiest ways to protect against a large number of bugs in an unsafe language like C. To check for
valgrind errors, run `make valtest` and check the output for undefined or flagged behavior.
### Formatting
Use [astyle](http://astyle.sourceforge.net/astyle.html) via `make format` to
ensure a consistent code style for C.
## Janet style
All janet code in the project should be formatted similar to the code in core.janet.
The auto formatting from janet.vim will work well.
## Suggesting Changes

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018 Calvin Rose
Copyright (c) 2020 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 deal in

371
Makefile
View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018 Calvin Rose
# Copyright (c) 2020 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
@@ -24,111 +24,171 @@
PREFIX?=/usr/local
INCLUDEDIR=$(PREFIX)/include/janet
LIBDIR=$(PREFIX)/lib
BINDIR=$(PREFIX)/bin
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\""
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 -fvisibility=hidden \
-DJANET_BUILD=$(JANET_BUILD)
CLIBS=-lm -ldl
INCLUDEDIR?=$(PREFIX)/include
BINDIR?=$(PREFIX)/bin
LIBDIR?=$(PREFIX)/lib
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1 || echo local)\""
CLIBS=-lm -lpthread
JANET_TARGET=build/janet
JANET_LIBRARY=build/libjanet.so
JANET_PATH?=/usr/local/lib/janet
JANET_STATIC_LIBRARY=build/libjanet.a
JANET_PATH?=$(LIBDIR)/janet
JANET_MANPATH?=$(PREFIX)/share/man/man1/
JANET_PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
DEBUGGER=gdb
SONAME_SETTER=-Wl,-soname,
# For cross compilation
HOSTCC?=$(CC)
HOSTAR?=$(AR)
CFLAGS?=-O2
LDFLAGS?=-rdynamic
COMMON_CFLAGS:=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fvisibility=hidden -fPIC
BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) -O0 -g $(COMMON_CFLAGS)
BUILD_CFLAGS:=$(CFLAGS) $(COMMON_CFLAGS)
# For installation
LDCONFIG:=ldconfig "$(LIBDIR)"
# Check OS
UNAME:=$(shell uname -s)
LDCONFIG:=ldconfig
ifeq ($(UNAME), Darwin)
# Add other macos/clang flags
LDCONFIG:=
else
CFLAGS:=$(CFLAGS) -rdynamic
CLIBS:=$(CLIBS) -lrt
CLIBS:=$(CLIBS) -ldl
SONAME_SETTER:=-Wl,-install_name,
LDCONFIG:=true
else ifeq ($(UNAME), Linux)
CLIBS:=$(CLIBS) -lrt -ldl
endif
# For other unix likes, add flags here!
ifeq ($(UNAME), Haiku)
LDCONFIG:=true
LDFLAGS=-Wl,--export-dynamic
endif
$(shell mkdir -p build/core build/mainclient build/webclient)
# Source headers
JANET_HEADERS=$(sort $(wildcard src/include/janet/*.h))
JANET_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h))
# Source files
JANET_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
JANET_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
JANET_WEBCLIENT_SOURCES=$(sort $(wildcard src/webclient/*.c))
all: $(JANET_TARGET) $(JANET_LIBRARY)
##########################################################
##### The main interpreter program and shared object #####
##########################################################
JANET_CORE_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_CORE_SOURCES)) build/core.gen.o
JANET_MAINCLIENT_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_MAINCLIENT_SOURCES)) build/init.gen.o
%.gen.o: %.gen.c
$(CC) $(CFLAGS) -o $@ -c $<
build/%.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
$(CC) $(CFLAGS) -o $@ -c $<
$(JANET_TARGET): $(JANET_CORE_OBJECTS) $(JANET_MAINCLIENT_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
$(JANET_LIBRARY): $(JANET_CORE_OBJECTS)
$(CC) $(CFLAGS) -shared -o $@ $^ $(CLIBS)
$(shell mkdir -p build/core build/mainclient build/webclient build/boot)
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY)
######################
##### Emscripten #####
##### Name Files #####
######################
EMCC=emcc
EMCFLAGS=-std=c99 -Wall -Wextra -Isrc/include -O2 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-s ALLOW_MEMORY_GROWTH=1 \
-s AGGRESSIVE_VARIABLE_ELIMINATION=1 \
-DJANET_BUILD=$(JANET_BUILD)
JANET_EMTARGET=build/janet.js
JANET_WEB_SOURCES=$(JANET_CORE_SOURCES) $(JANET_WEBCLIENT_SOURCES)
JANET_EMOBJECTS=$(patsubst src/%.c,build/%.bc,$(JANET_WEB_SOURCES)) \
build/webinit.gen.bc build/core.gen.bc
JANET_HEADERS=src/include/janet.h src/conf/janetconf.h
%.gen.bc: %.gen.c
$(EMCC) $(EMCFLAGS) -o $@ -c $<
JANET_LOCAL_HEADERS=src/core/features.h \
src/core/util.h \
src/core/state.h \
src/core/gc.h \
src/core/vector.h \
src/core/fiber.h \
src/core/regalloc.h \
src/core/compile.h \
src/core/emit.h \
src/core/symcache.h
build/%.bc: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
$(EMCC) $(EMCFLAGS) -o $@ -c $<
JANET_CORE_SOURCES=src/core/abstract.c \
src/core/array.c \
src/core/asm.c \
src/core/buffer.c \
src/core/bytecode.c \
src/core/capi.c \
src/core/cfuns.c \
src/core/compile.c \
src/core/corelib.c \
src/core/debug.c \
src/core/emit.c \
src/core/fiber.c \
src/core/gc.c \
src/core/inttypes.c \
src/core/io.c \
src/core/marsh.c \
src/core/math.c \
src/core/net.c \
src/core/os.c \
src/core/parse.c \
src/core/peg.c \
src/core/pp.c \
src/core/regalloc.c \
src/core/run.c \
src/core/specials.c \
src/core/string.c \
src/core/strtod.c \
src/core/struct.c \
src/core/symcache.c \
src/core/table.c \
src/core/thread.c \
src/core/tuple.c \
src/core/typedarray.c \
src/core/util.c \
src/core/value.c \
src/core/vector.c \
src/core/vm.c \
src/core/wrap.c
$(JANET_EMTARGET): $(JANET_EMOBJECTS)
$(EMCC) $(EMCFLAGS) -shared -o $@ $^
JANET_BOOT_SOURCES=src/boot/array_test.c \
src/boot/boot.c \
src/boot/buffer_test.c \
src/boot/number_test.c \
src/boot/system_test.c \
src/boot/table_test.c
JANET_BOOT_HEADERS=src/boot/tests.h
emscripten: $(JANET_EMTARGET)
##########################################################
##### The bootstrap interpreter that creates janet.c #####
##########################################################
#############################
##### Generated C files #####
#############################
JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) $(JANET_BOOT_SOURCES))
build/xxd: tools/xxd.c
$(CC) $< -o $@
$(JANET_BOOT_OBJECTS): $(JANET_BOOT_HEADERS)
build/core.gen.c: src/core/core.janet build/xxd
build/xxd $< $@ janet_gen_core
build/init.gen.c: src/mainclient/init.janet build/xxd
build/xxd $< $@ janet_gen_init
build/webinit.gen.c: src/webclient/webinit.janet build/xxd
build/xxd $< $@ janet_gen_webinit
build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
$(CC) $(BOOT_CFLAGS) -o $@ -c $<
build/janet_boot: $(JANET_BOOT_OBJECTS)
$(CC) $(BOOT_CFLAGS) -o $@ $(JANET_BOOT_OBJECTS) $(CLIBS)
# Now the reason we bootstrap in the first place
build/janet.c: build/janet_boot src/boot/boot.janet
build/janet_boot . JANET_PATH '$(JANET_PATH)' > $@
cksum $@
########################
##### Amalgamation #####
########################
SONAME=libjanet.so.1.12
build/shell.c: src/mainclient/shell.c
cp $< $@
build/janet.h: src/include/janet.h
cp $< $@
build/janetconf.h: src/conf/janetconf.h
cp $< $@
build/janet.o: build/janet.c build/janet.h build/janetconf.h
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@ -I build
build/shell.o: build/shell.c build/janet.h build/janetconf.h
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@ -I build
$(JANET_TARGET): build/janet.o build/shell.o
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) -o $@ $^ $(CLIBS)
$(JANET_LIBRARY): build/janet.o build/shell.o
$(HOSTCC) $(LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
$(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
$(HOSTAR) rcs $@ $^
###################
##### Testing #####
###################
TEST_SOURCES=$(wildcard ctest/*.c)
TEST_PROGRAMS=$(patsubst ctest/%.c,build/%.out,$(TEST_SOURCES))
TEST_SCRIPTS=$(wildcard test/suite*.janet)
# Testing assumes HOSTCC=CC
build/%.out: ctest/%.c $(JANET_CORE_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(CLIBS)
TEST_SCRIPTS=$(wildcard test/suite*.janet)
repl: $(JANET_TARGET)
./$(JANET_TARGET)
@@ -136,18 +196,23 @@ repl: $(JANET_TARGET)
debug: $(JANET_TARGET)
$(DEBUGGER) ./$(JANET_TARGET)
VALGRIND_COMMAND=valgrind --leak-check=full
valgrind: $(JANET_TARGET)
valgrind --leak-check=full -v ./$(JANET_TARGET)
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
test: $(JANET_TARGET) $(TEST_PROGRAMS)
for f in build/*.out; do "$$f" || exit; done
for f in test/*.janet; do ./$(JANET_TARGET) "$$f" || exit; done
VALGRIND_COMMAND=valgrind --leak-check=full -v
for f in test/suite*.janet; do ./$(JANET_TARGET) "$$f" || exit; done
for f in examples/*.janet; do ./$(JANET_TARGET) -k "$$f"; done
./$(JANET_TARGET) -k jpm
valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
for f in build/*.out; do $(VALGRIND_COMMAND) "$$f" || exit; done
for f in test/*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
for f in test/suite*.janet; do $(VALGRIND_COMMAND) ./$(JANET_TARGET) "$$f" || exit; done
for f in examples/*.janet; do ./$(JANET_TARGET) -k "$$f"; done
$(VALGRIND_COMMAND) ./$(JANET_TARGET) -k jpm
callgrind: $(JANET_TARGET)
for f in test/suite*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done
########################
##### Distribution #####
@@ -155,10 +220,14 @@ valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
dist: build/janet-dist.tar.gz
build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) \
build/doc.html README.md $(wildcard doc/*.md)
tar -czvf $@ $^
build/janet-%.tar.gz: $(JANET_TARGET) \
src/include/janet.h src/conf/janetconf.h \
jpm.1 janet.1 LICENSE CONTRIBUTING.md $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) \
build/doc.html README.md build/janet.c build/shell.c jpm
$(eval JANET_DIST_DIR = "janet-$(shell basename $*)")
mkdir -p build/$(JANET_DIST_DIR)
cp -r $^ build/$(JANET_DIST_DIR)/
cd build && tar -czvf ../$@ $(JANET_DIST_DIR)
#########################
##### Documentation #####
@@ -166,33 +235,111 @@ build/janet-%.tar.gz: $(JANET_TARGET) src/include/janet/janet.h \
docs: build/doc.html
build/doc.html: $(JANET_TARGET) doc/gendoc.janet
$(JANET_TARGET) doc/gendoc.janet > build/doc.html
build/doc.html: $(JANET_TARGET) tools/gendoc.janet
$(JANET_TARGET) tools/gendoc.janet > build/doc.html
########################
##### Installation #####
########################
build/jpm: jpm $(JANET_TARGET)
$(JANET_TARGET) tools/patch-jpm.janet jpm build/jpm "--libpath=$(LIBDIR)" "--headerpath=$(INCLUDEDIR)/janet" "--binpath=$(BINDIR)"
chmod +x build/jpm
.INTERMEDIATE: build/janet.pc
build/janet.pc: $(JANET_TARGET)
echo 'prefix=$(PREFIX)' > $@
echo 'exec_prefix=$${prefix}' >> $@
echo 'includedir=$(INCLUDEDIR)/janet' >> $@
echo 'libdir=$(LIBDIR)' >> $@
echo "" >> $@
echo "Name: janet" >> $@
echo "Url: https://janet-lang.org" >> $@
echo "Description: Library for the Janet programming language." >> $@
$(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
echo 'Cflags: -I$${includedir}' >> $@
echo 'Libs: -L$${libdir} -ljanet' >> $@
echo 'Libs.private: $(CLIBS)' >> $@
install: $(JANET_TARGET) build/janet.pc build/jpm
mkdir -p '$(DESTDIR)$(BINDIR)'
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
cp -rf $(JANET_HEADERS) '$(DESTDIR)$(INCLUDEDIR)/janet'
mkdir -p '$(DESTDIR)$(JANET_PATH)'
mkdir -p '$(DESTDIR)$(LIBDIR)'
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')'
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so'
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME)
cp -rf build/jpm '$(DESTDIR)$(BINDIR)'
mkdir -p '$(DESTDIR)$(JANET_MANPATH)'
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
cp jpm.1 '$(DESTDIR)$(JANET_MANPATH)'
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || true
uninstall:
-rm '$(DESTDIR)$(BINDIR)/janet'
-rm '$(DESTDIR)$(BINDIR)/jpm'
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet'
-rm -rf '$(DESTDIR)$(LIBDIR)'/libjanet.*
-rm '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
-rm '$(DESTDIR)$(JANET_MANPATH)/janet.1'
-rm '$(DESTDIR)$(JANET_MANPATH)/jpm.1'
# -rm -rf '$(DESTDIR)$(JANET_PATH)'/* - err on the side of correctness here
#################
##### Other #####
#################
format:
tools/format.sh
grammar: build/janet.tmLanguage
build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
$(JANET_TARGET) $< > $@
clean:
-rm -rf build
-rm -rf build vgcore.* callgrind.*
-rm -rf test/install/build test/install/modpath
install: $(JANET_TARGET)
mkdir -p $(BINDIR)
cp $(JANET_TARGET) $(BINDIR)/janet
mkdir -p $(INCLUDEDIR)
cp $(JANET_HEADERS) $(INCLUDEDIR)
mkdir -p $(LIBDIR)
cp $(JANET_LIBRARY) $(LIBDIR)/libjanet.so
cp janet.1 /usr/local/share/man/man1/
mandb
$(LDCONFIG)
test-install:
cd test/install \
&& rm -rf build .cache .manifests \
&& jpm --verbose build \
&& jpm --verbose test \
&& build/testexec \
&& jpm --verbose quickbin testexec.janet build/testexec2 \
&& build/testexec2 \
&& mkdir -p modpath \
&& jpm --verbose --testdeps --modpath=./modpath install https://github.com/janet-lang/json.git
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/jhydro.git
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/path.git
cd test/install && jpm --verbose --test --modpath=./modpath install https://github.com/janet-lang/argparse.git
uninstall:
-rm $(BINDIR)/../$(JANET_TARGET)
-rm $(LIBDIR)/../$(JANET_LIBRARY)
-rm -rf $(INCLUDEDIR)
$(LDCONFIG)
help:
@echo
@echo 'Janet: A Dynamic Language & Bytecode VM'
@echo
@echo Usage:
@echo ' make Build Janet'
@echo ' make repl Start a REPL from a built Janet'
@echo
@echo ' make test Test a built Janet'
@echo ' make valgrind Assess Janet with Valgrind'
@echo ' make callgrind Assess Janet with Valgrind, using Callgrind'
@echo ' make valtest Run the test suite with Valgrind to check for memory leaks'
@echo ' make dist Create a distribution tarball'
@echo ' make docs Generate documentation'
@echo ' make debug Run janet with GDB or LLDB'
@echo ' make install Install into the current filesystem'
@echo ' make uninstall Uninstall from the current filesystem'
@echo ' make clean Clean intermediate build artifacts'
@echo " make format Format Janet's own source files"
@echo ' make grammar Generate a TextMate language grammar'
@echo
.PHONY: clean install repl debug valgrind test \
valtest emscripten dist uninstall docs \
$(TEST_PROGRAM_PHONIES) $(TEST_PROGRAM_VALPHONIES)
valtest dist uninstall docs grammar format help

279
README.md
View File

@@ -1,31 +1,31 @@
[![Build Status](https://travis-ci.org/bakpakin/janet.svg?branch=master)](https://travis-ci.org/bakpakin/janet)
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true)](https://ci.appveyor.com/project/bakpakin/janet)
[![Join the chat](https://badges.gitter.im/janet-language/community.svg)](https://gitter.im/janet-language/community)
&nbsp;
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/bjraxrxexmt3sxyv/branch/master?svg=true)](https://ci.appveyor.com/project/bakpakin/janet/branch/master)
[![Build Status](https://travis-ci.org/janet-lang/janet.svg?branch=master)](https://travis-ci.org/janet-lang/janet)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/freebsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/freebsd.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/openbsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/openbsd.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/meson.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/meson.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/meson_min.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/meson_min.yml?)
<img src="https://raw.githubusercontent.com/honix/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
**Janet** is a functional and imperative programming language and bytecode interpreter. It is a
modern lisp, but lists are replaced
by other data structures with better utility and performance (arrays, tables, structs, tuples).
The language also bridging bridging to native code written in C, meta-programming with macros, and bytecode assembly.
lisp-like language, but lists are replaced
by other data structures (arrays, tables (hash table), struct (immutable hash table), tuples).
The language also supports bridging to native code written in C, meta-programming with macros, and bytecode assembly.
There is a repl for trying out the language, as well as the ability
to run script files. This client program is separate from the core runtime, so
janet could be embedded into other programs. Try janet in your browser at
Janet can be embedded into other programs. Try Janet in your browser at
[https://janet-lang.org](https://janet-lang.org).
#
Implemented in mostly standard C99, janet runs on Windows, Linux and macOS.
The few features that are not standard C (dynamic library loading, compiler specific optimizations),
are fairly straight forward. Janet can be easily ported to new platforms.
For syntax highlighting, there is some preliminary vim syntax highlighting in [janet.vim](https://github.com/bakpakin/janet.vim).
Generic lisp syntax highlighting should, however, provide good results. There is also a janet.tmLanguage file
that should provide good syntax highlighting for many editors.
<br>
## Use Cases
Janet makes a good system scripting language, or a language to embed in other programs. Think Lua or Guile.
Janet makes a good system scripting language, or a language to embed in other programs.
It's like Lua and Guile in that regard. It has more built-in functionality and a richer core language than
Lua, but smaller than GNU Guile or Python.
## Features
@@ -37,7 +37,7 @@ Janet makes a good system scripting language, or a language to embed in other pr
* Mutable and immutable arrays (array/tuple)
* Mutable and immutable hashtables (table/struct)
* Mutable and immutable strings (buffer/string)
* Lisp Macros
* Macros
* Byte code interpreter with an assembly interface, as well as bytecode verification
* Tailcall Optimization
* Direct interop with C via abstract types and C functions
@@ -46,35 +46,134 @@ Janet makes a good system scripting language, or a language to embed in other pr
* Lexical scoping
* Imperative programming as well as functional
* REPL
* 300+ functions and macros in the core library
* Parsing Expression Grammars built in to the core library
* 400+ functions and macros in the core library
* Embedding Janet in other programs
* Interactive environment with detailed stack traces
## Documentation
Documentation can be found in the doc directory of
the repository. There is an introduction
section contains a good overview of the language.
* For a quick tutorial, see [the introduction](https://janet-lang.org/docs/index.html) for more details.
* For the full API for all functions in the core library, see [the core API doc](https://janet-lang.org/api/index.html)
API documentation for all bindings can also be generated
with `make docs`, which will create `build/doc.html`, which
can be viewed with any web browser. This
includes all forms in the core library except special forms.
For individual bindings from within the REPL, use the `(doc symbol-name)` macro to get API
documentation for the core library. For example,
Documentation is also available locally in the repl.
Use the `(doc symbol-name)` macro to get API
documentation for symbols in the core library. For example,
```
(doc doc)
```
Shows documentation for the doc macro.
To get a list of all bindings in the default
environment, use the `(all-symbols)` function.
environment, use the `(all-bindings)` function. You
can also use the `(doc)` macro with no arguments if you are in the repl
to show bound symbols.
## Source
You can get the source on [GitHub](https://github.com/janet-lang/janet) or
[SourceHut](https://git.sr.ht/~bakpakin/janet). While the GitHub repo is the official repo,
the SourceHut mirror is actively maintained.
## Building
### macOS and Unix-like
The Makefile is non-portable and requires GNU-flavored make.
```
cd somewhere/my/projects/janet
make
make test
make repl
```
Find out more about the available make targets by running `make help`.
### 32-bit Haiku
32-bit Haiku build instructions are the same as the unix-like build instructions,
but you need to specify an alternative compiler, such as `gcc-x86`.
```
cd somewhere/my/projects/janet
make CC=gcc-x86
make test
make repl
```
### FreeBSD
FreeBSD build instructions are the same as the unix-like build instuctions,
but you need `gmake` to compile. Alternatively, install directly from
packages, using `pkg install lang/janet`.
```
cd somewhere/my/projects/janet
gmake
gmake test
gmake repl
```
### NetBSD
NetBSD build instructions are the same as the FreeBSD build instuctions.
Alternatively, install directly from packages, using `pkgin install janet`.
### Windows
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#) or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#)
2. Run a Visual Studio Command Prompt (cl.exe and link.exe need to be on the PATH) and cd to the directory with janet.
3. Run `build_win` to compile janet.
4. Run `build_win test` to make sure everything is working.
To build an `.msi` installer executable, in addition to the above steps, you will have to:
5. Install, or otherwise add to your PATH the [WiX 3.11 Toolset](https://github.com/wixtoolset/wix3/releases)
6. run `build_win dist`
Now you should have an `.msi`. You can run `build_win install` to install the `.msi`, or execute the file itself.
### Meson
Janet also has a build file for [Meson](https://mesonbuild.com/), a cross platform build
system. Although Meson has a python dependency, Meson is a very complete build system that
is maybe more convenient and flexible for integrating into existing pipelines.
Meson also provides much better IDE integration than Make or batch files, as well as support
for cross compilation.
For the impatient, building with Meson is as follows. The options provided to
`meson setup` below emulate Janet's Makefile.
```sh
git clone https://github.com/janet-lang/janet.git
cd janet
meson setup build \
--buildtype release \
--optimization 2 \
--libdir /usr/local/lib \
-Dgit_hash=$(git log --pretty=format:'%h' -n 1)
ninja -C build
# Run the binary
build/janet
# Installation
ninja -C build install
```
## Development
Janet can be hacked on with pretty much any environment you like, but for IDE
lovers, [Gnome Builder](https://wiki.gnome.org/Apps/Builder) is probably the
best option, as it has excellent meson integration. It also offers code completion
for Janet's C API right out of the box, which is very useful for exploring. VSCode, Vim,
Emacs, and Atom will have syntax packages for the Janet language, though.
## Installation
Install a stable version of janet from the [releases page](https://github.com/bakpakin/janet/releases).
Janet is prebuilt for a few systems, but if you want to develop janet, run janet on a non-x86 system, or
get the latest, you must build janet from source.
See [the Introduction](https://janet-lang.org/introduction.html) for more details. If you just want
to try out the language, you don't need to install anything. You can also move the `janet` executable wherever you want on your system and run it.
## Usage
@@ -82,80 +181,72 @@ A repl is launched when the binary is invoked with no arguments. Pass the -h fla
to display the usage information. Individual scripts can be run with `./janet myscript.janet`
If you are looking to explore, you can print a list of all available macros, functions, and constants
by entering the command `(all-symbols)` into the repl.
by entering the command `(all-bindings)` into the repl.
```
$ ./janet
Janet 0.0.0 alpha Copyright (C) 2017-2018 Calvin Rose
$ janet
Janet 1.7.1-dev-951e10f Copyright (C) 2017-2020 Calvin Rose
janet:1:> (+ 1 2 3)
6
janet:2:> (print "Hello, World!")
Hello, World!
nil
janet:3:> (os.exit)
$ ./janet -h
usage: ./janet [options] scripts...
janet:3:> (os/exit)
$ janet -h
usage: build/janet [options] script args...
Options are:
-h Show this help
-v Print the version string
-s Use raw stdin instead of getline like functionality
-e Execute a string of janet
-r Enter the repl after running all scripts
-p Keep on executing if there is a top level error (persistent)
-- Stop handling option
$
-h : Show this help
-v : Print the version string
-s : Use raw stdin instead of getline like functionality
-e code : Execute a string of janet
-r : Enter the repl after running all scripts
-p : Keep on executing if there is a top level error (persistent)
-q : Hide prompt, logo, and repl output (quiet)
-k : Compile scripts but do not execute (flycheck)
-m syspath : Set system path for loading global modules
-c source output : Compile janet source code into an image
-n : Disable ANSI color output in the repl
-l path : Execute code in a file before running the main script
-- : Stop handling options
```
## Compiling and Running
If installed, you can also run `man janet` and `man jpm` to get usage information.
Janet only uses Make and batch files to compile on Posix and windows
respectively. To configure janet, edit the header file src/include/janet/janet.h
before compilation.
## Embedding
### Unix-like
Janet can be embedded in a host program very easily. The normal build
will create a file `build/janet.c`, which is a single C file
that contains all the source to Janet. This file, along with
`src/include/janet.h` and `src/conf/janetconf.h` can be dragged into any C
project and compiled into the project. Janet should be compiled with `-std=c99`
on most compilers, and will need to be linked to the math library, `-lm`, and
the dynamic linker, `-ldl`, if one wants to be able to load dynamic modules. If
there is no need for dynamic modules, add the define
`-DJANET_NO_DYNAMIC_MODULES` to the compiler options.
On most platforms, use Make to build janet. The resulting binary will be in `build/janet`.
```sh
cd somewhere/my/projects/janet
make
make test
```
After building, run `make install` to install the janet binary and libs.
Will install in `/usr/local` by default, see the Makefile to customize.
It's also recommended to set the `JANET_PATH` variable in your profile.
This is where janet will look for imported libraries after the current directory.
### FreeBSD
FreeBSD build instructions are the same as the unix-like build instuctions,
but you need `gmake` and `gcc` to compile.
```
cd somewhere/my/projects/janet
gmake CC=gcc
gmake test CC=gcc
```
### Windows
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#)
or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#)
2. Run a Visual Studio Command Prompt (cl.exe and link.exe need to be on the PATH) and cd to the directory with janet.
3. Run `build_win` to compile janet.
4. Run `build_win test` to make sure everything is working.
### Emscripten
To build janet for the web via [Emscripten](https://kripken.github.io/emscripten-site/), make sure you
have `emcc` installed and on your path. On a linux or macOS system, use `make emscripten` to build
`janet.js` and `janet.wasm` - both are needed to run janet in a browser or in node.
The JavaScript build is what runs the repl on the main website,
but really serves mainly as a proof of concept. Janet will run slower in a browser.
Building with emscripten on windows is currently unsupported.
See the [Embedding Section](https://janet-lang.org/capi/embedding.html) on the website for more information.
## Examples
See the examples directory for some example janet code.
## Discussion
Feel free to ask questions and join discussion on the [Janet Gitter Channel](https://gitter.im/janet-language/community).
Alternatively, check out [the #janet channel on Freenode](https://webchat.freenode.net/)
## FAQ
### Why is my terminal spitting out junk when I run the repl?
Make sure your terminal supports ANSI escape codes. Most modern terminals will
support these, but some older terminals, Windows consoles, or embedded terminals
will not. If your terminal does not support ANSI escape codes, run the repl with
the `-n` flag, which disables color output. You can also try the `-s` if further issues
ensue.
## Why Janet
Janet is named after the almost omniscient and friendly artificial being in [The Good Place](https://en.wikipedia.org/wiki/The_Good_Place).
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-the-good-place.gif" alt="Janet logo" width="115px" align="left">

View File

@@ -1,12 +1,12 @@
version: build-{build}
clone_folder: c:\projects\janet
image:
- Visual Studio 2017
- Visual Studio 2019
configuration:
- Release
- Debug
platform:
- x64
- x86
environment:
matrix:
- arch: Win64
@@ -15,34 +15,44 @@ matrix:
# skip unsupported combinations
init:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
install:
- build_win
- build_win test
- choco install nsis -y -pre
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
- build_win dist
- copy janet-install.exe dist\install.exe
- set JANET_BUILD=%appveyor_repo_commit:~0,7%
- build_win all
- refreshenv
# We need to reload vcvars after refreshing
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
- build_win test-install
- set janet_outname=%appveyor_repo_tag_name%
- if "%janet_outname%"=="" set /P janet_outname=<build\version.txt
build: off
only_commits:
files:
- appveyor.yml
- src/
artifacts:
- path: dist
name: janet-windows
- name: janet.c
path: dist\janet.c
type: File
- name: janet.h
path: dist\janet.h
type: File
- name: janetconf.h
path: dist\janetconf.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-windows
artifact: /(janet|shell).*/
draft: true
on:
APPVEYOR_REPO_TAG: true
APPVEYOR_REPO_TAG: true

BIN
assets/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

11
assets/icon_svg.svg Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 640 640" preserveAspectRatio="xMidYMid meet">
<g id="layer101" fill="#d45500" stroke="none">
<path d="M145 531 c-46 -31 -58 -75 -30 -118 21 -32 30 -22 44 47 7 30 19 62 27 71 26 29 1 29 -41 0z"/>
<path d="M341 534 c-23 -29 -26 -50 -11 -88 10 -28 64 -60 86 -52 12 5 12 2 0 -22 -24 -47 -51 -64 -116 -71 -51 -6 -65 -12 -85 -37 -14 -16 -24 -32 -25 -36 0 -12 -35 -9 -48 4 -7 7 -12 24 -12 38 0 41 -11 43 -47 8 -47 -46 -46 -90 5 -138 20 -19 49 -51 63 -70 l27 -35 88 0 c49 0 106 4 127 8 46 10 106 62 143 125 25 42 28 58 30 142 0 52 4 103 9 113 11 27 -14 75 -49 93 -41 21 -115 44 -143 44 -12 0 -31 -12 -42 -26z m89 -119 c0 -3 -2 -5 -5 -5 -3 0 -5 2 -5 5 0 3 2 5 5 5 3 0 5 -2 5 -5z"/>
</g>
<g id="layer102" fill="#deaa87" stroke="none">
<path d="M186 549 c-33 -31 -38 -43 -56 -137 -26 -135 -26 -163 3 -190 33 -31 49 -28 85 17 28 35 36 39 87 43 46 4 61 10 90 38 18 18 39 46 46 62 10 25 9 32 -5 46 -17 16 -19 16 -29 1 -8 -14 -15 -15 -34 -6 -27 12 -40 65 -24 96 10 17 8 23 -12 36 -13 8 -44 18 -69 21 -42 6 -49 4 -82 -27z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -13,48 +13,54 @@
@if "%1"=="clean" goto CLEAN
@if "%1"=="test" goto TEST
@if "%1"=="dist" goto DIST
@if "%1"=="install" goto INSTALL
@if "%1"=="test-install" goto TESTINSTALL
@if "%1"=="all" goto ALL
@rem Set compile and link options here
@setlocal
@set JANET_COMPILE=cl /nologo /Isrc\include /c /O2 /W3 /LD /D_CRT_SECURE_NO_WARNINGS
@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD
@set JANET_LINK=link /nologo
@set JANET_LINK_STATIC=lib /nologo
@rem Add janet build tag
if not "%JANET_BUILD%" == "" (
@set JANET_COMPILE=%JANET_COMPILE% /DJANET_BUILD="\"%JANET_BUILD%\""
)
mkdir build
mkdir build\core
mkdir build\mainclient
mkdir build\boot
@rem Build the xxd tool for generating sources
@cl /nologo /c tools/xxd.c /Fobuild\xxd.obj
@if errorlevel 1 goto :BUILDFAIL
@link /nologo /out:build\xxd.exe build\xxd.obj
@if errorlevel 1 goto :BUILDFAIL
@rem Generate the embedded sources
@build\xxd.exe src\core\core.janet build\core\core.gen.c janet_gen_core
@if errorlevel 1 goto :BUILDFAIL
@build\xxd.exe src\mainclient\init.janet build\mainclient\init.gen.c janet_gen_init
@if errorlevel 1 goto :BUILDFAIL
@rem Build the generated sources
@%JANET_COMPILE% /Fobuild\core\core.gen.obj build\core\core.gen.c
@if errorlevel 1 goto :BUILDFAIL
@%JANET_COMPILE% /Fobuild\mainclient\init.gen.obj build\mainclient\init.gen.c
@rem Build the bootstrap interpreter
for %%f in (src\core\*.c) do (
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
@if errorlevel 1 goto :BUILDFAIL
)
for %%f in (src\boot\*.c) do (
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
@if errorlevel 1 goto :BUILDFAIL
)
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
@if errorlevel 1 goto :BUILDFAIL
build\janet_boot . > build\janet.c
@rem Build the sources
for %%f in (src\core\*.c) do (
@%JANET_COMPILE% /Fobuild\core\%%~nf.obj %%f
@if errorlevel 1 goto :BUILDFAIL
)
%JANET_COMPILE% /Fobuild\janet.obj build\janet.c
@if errorlevel 1 goto :BUILDFAIL
%JANET_COMPILE% /Fobuild\shell.obj src\mainclient\shell.c
@if errorlevel 1 goto :BUILDFAIL
@rem Build the main client
for %%f in (src\mainclient\*.c) do (
@%JANET_COMPILE% /Fobuild\mainclient\%%~nf.obj %%f
@if errorlevel 1 goto :BUILDFAIL
)
@rem Build the resources
rc /nologo /fobuild\janet_win.res janet_win.rc
@rem Link everything to main client
%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj
%JANET_LINK% /out:janet.exe build\janet.obj build\shell.obj build\janet_win.res
@if errorlevel 1 goto :BUILDFAIL
@rem Build static library (libjanet.a)
%JANET_LINK_STATIC% /out:build\libjanet.lib build\janet.obj
@if errorlevel 1 goto :BUILDFAIL
echo === Successfully built janet.exe for Windows ===
@@ -78,28 +84,108 @@ exit /b 0
@rem Clean build artifacts
:CLEAN
del janet.exe janet.exp janet.lib
del *.exe *.lib *.exp
rd /s /q build
rd /s /q dist
exit /b 0
@rem Run tests
:TEST
for %%f in (test/suite*.janet) do (
janet.exe test\%%f
@if errorlevel 1 goto :TESTFAIL
@if errorlevel 1 goto TESTFAIL
)
exit /b 0
@rem Build a dist directory
:DIST
mkdir dist
janet.exe doc\gendoc.janet > dist\doc.html
janet.exe tools\gendoc.janet > dist\doc.html
janet.exe tools\removecr.janet dist\doc.html
copy build\janet.c dist\janet.c
copy src\mainclient\shell.c dist\shell.c
copy janet.exe dist\janet.exe
copy LICENSE dist\LICENSE
copy README.md dist\README.md
copy janet.lib dist\janet.lib
copy janet.exp dist\janet.exp
copy src\include\janet\janet.h dist\janet.h
copy src\include\janet.h dist\janet.h
copy src\conf\janetconf.h dist\janetconf.h
copy build\libjanet.lib dist\libjanet.lib
copy .\jpm dist\jpm
copy tools\jpm.bat dist\jpm.bat
@rem Create installer
janet.exe -e "(->> janet/version (peg/match ''(* :d+ `.` :d+ `.` :d+)) first print)" > build\version.txt
janet.exe -e "(print (os/arch))" > build\arch.txt
set /p JANET_VERSION= < build\version.txt
set /p BUILDARCH= < build\arch.txt
echo "JANET_VERSION is %JANET_VERSION%"
if defined APPVEYOR_REPO_TAG_NAME (
set RELEASE_VERSION=%APPVEYOR_REPO_TAG_NAME%
) else (
set RELEASE_VERSION=%JANET_VERSION%
)
if defined CI (
set WIXBIN="c:\Program Files (x86)\WiX Toolset v3.11\bin\"
) else (
set WIXBIN=
)
%WIXBIN%candle.exe tools\msi\janet.wxs -arch %BUILDARCH% -out build\
%WIXBIN%light.exe "-sice:ICE38" -b tools\msi -ext WixUIExtension build\janet.wixobj -out janet-%RELEASE_VERSION%-windows-%BUILDARCH%-installer.msi
exit /b 0
@rem Run the installer. (Installs to the local user with default settings)
:INSTALL
FOR %%a in (janet-*-windows-*-installer.msi) DO (
@echo Running Installer %%a...
%%a /QN
)
exit /b 0
@rem Test the installation.
:TESTINSTALL
pushd test\install
call jpm clean
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm test
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm --verbose --modpath=. install https://github.com/janet-lang/json.git
@if errorlevel 1 goto :TESTINSTALLFAIL
call build\testexec
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm --verbose quickbin testexec.janet build\testexec2.exe
@if errorlevel 1 goto :TESTINSTALLFAIL
call build\testexec2.exe
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/jhydro.git
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/path.git
@if errorlevel 1 goto :TESTINSTALLFAIL
call jpm --verbose --test --modpath=. install https://github.com/janet-lang/argparse.git
@if errorlevel 1 goto :TESTINSTALLFAIL
popd
exit /b 0
:TESTINSTALLFAIL
popd
goto :TESTFAIL
@rem build, test, dist, install. Useful for local dev.
:ALL
call %0 build
@if errorlevel 1 exit /b 1
call %0 test
@if errorlevel 1 exit /b 1
call %0 dist
@if errorlevel 1 exit /b 1
call %0 install
@if errorlevel 1 exit /b 1
@echo Done!
exit /b 0
:TESTFAIL

View File

@@ -1,6 +0,0 @@
Janet is a dynamic, lightweight programming language with strong functional
capabilities as well as support for imperative programming. It to be used
for short lived scripts as well as for building real programs. It can also
be extended with native code (C modules) for better performance and interfacing with
existing software. Janet takes ideas from Lua, Scheme, Racket, Clojure, Smalltalk, Erlang, Arc, and
a whole bunch of other dynamic languages.

View File

@@ -1,746 +0,0 @@
# Hello, world!
Following tradition, a simple Janet program will print "Hello, world!".
```
(print "Hello, world!")
```
Put the following code in a file named `hello.janet`, and run `./janet hello.janet`.
The words "Hello, world!" should be printed to the console, and then the program
should immediately exit. You now have a working janet program!
Alternatively, run the program `./janet` without any arguments to enter a REPL,
or read eval print loop. This is a mode where Janet functions like a calculator,
reading some input from the user, evaluating it, and printing out the result, all
in an infinite loop. This is a useful mode for exploring or prototyping in Janet.
This hello world program is about the simplest program one can write, and consists of only
a few pieces of syntax. This first element is the `print` symbol. This is a function
that simply prints its arguments to the console. The second argument is the
string literal "Hello, world!", which is the one and only argument to the
print function. Lastly, the print symbol and the string literal are wrapped
in parentheses, forming a tuple. In Janet, parentheses and brackets are interchangeable,
brackets are used mostly when the resulting tuple is not a function call. The tuple
above indicates that the function `print` is to be called with one argument, `"Hello, world"`.
Like all lisps, all operations in Janet are in prefix notation; the name of the
operator is the first value in the tuple, and the arguments passed to it are
in the rest of the tuple.
# A bit more - Arithmetic
Any programming language will have some way to do arithmetic. Janet is no exception,
and supports the basic arithmetic operators
```
# Prints 13
# (1 + (2*2) + (10/5) + 3 + 4 + (5 - 6))
(print (+ 1 (* 2 2) (/ 10 5) 3 4 (- 5 6)))
```
Just like the print function, all arithmetic operators are entered in
prefix notation. Janet also supports the remainder operator, or `%`, which returns
the remainder of division. For example, `(% 10 3)` is 1, and `(% 10.5 3)` is
1.5. The lines that begin with `#` are comments.
Janet actually has two "flavors" of numbers; integers and real numbers. Integers are any
integer value between -2,147,483,648 and 2,147,483,647 (32 bit signed integer).
Reals are real numbers, and are represented by IEEE-754 double precision floating point
numbers. That means that they can represent any number an integer can represent, as well
fractions to very high precision.
Although real numbers can represent any value an integer can, try to distinguish between
real numbers and integers in your program. If you are using a number to index into a structure,
you probably want integers. Otherwise, you may want to use reals (this is only a rule of thumb).
Arithmetic operator will convert integers to real numbers if needed, but real numbers
will not be converted to integers, as not all real numbers can be safely converted to integers.
## Numeric literals
Numeric literals can be written in many ways. Numbers can be written in base 10, with
underscores used to separate digits into groups. A decimal point can be used for floating
point numbers. Numbers can also be written in other bases by prefixing the number with the desired
base and the character 'r'. For example, 16 can be written as `16`, `1_6`, `16r10`, `4r100`, or `0x10`. The
`0x` prefix can be used for hexadecimal as it is so common. The radix must be themselves written in base 10, and
can be any integer from 2 to 36. For any radix above 10, use the letters as digits (not case sensitive).
Numbers can also be in scientific notation such as `3e10`. A custom radix can be used as well
as for scientific notation numbers, (the exponent will share the radix). For numbers in scientific
notation with a radix besides 10, use the `&` symbol to indicate the exponent rather then `e`.
## Arithmetic Functions
Besides the 5 main arithmetic functions, janet also supports a number of math functions
taken from the C library `<math.h>`, as well as bitwise operators that behave like they
do in C or Java. Functions like `math/sin`, `math/cos`, `math/log`, and `math/exp` will
behave as expected to a C programmer. They all take either 1 or 2 numeric arguments and
return a real number (never an integer!) Bitwise functions are all prefixed with b.
Thet are `bnot`, `bor`, `bxor`, `band`, `blshift`, `brshift`, and `brushift`. Bitwise
functions only work on integers.
# Strings, Keywords and Symbols
Janet supports several varieties of types that can be used as labels for things in
your program. The most useful type for this purpose is the keyword type. A keyword
begins with a semicolon, and then contains 0 or more alphanumeric or a few other common
characters. For example, `:hello`, `:my-name`, `::`, and `:ABC123_-*&^%$` are all keywords.
Keywords are actually just special cases of symbols, which are similar but don't start with
a semicolon. The difference between symbols and keywords is that keywords evaluate to themselves, while
symbols evaluate to whatever they are bound to. To have a symbol evaluate to itself, it must be
quoted.
```lisp
# Evaluates to :monday
:monday
# Will throw a compile error as monday is not defined
monday
# Quote it - evaluates to the symbol monday
'monday
# Or first define monday
(def monday "It is monday")
# Now the evaluation should work - monday evaluates to "It is monday"
monday
```
The most common thing to do with a keyword is to check it for equality or use it as a key into
a table or struct. Note that symbols, keywords and strings are all immutable. Besides making your
code easier to reason about, it allows for many optimizations involving these types.
```lisp
# Evaluates to true
(= :hello :hello)
# Evaluates to false, everything in janet is case sensitive
(= :hello :HeLlO)
# Look up into a table - evaluates to 25
(get {
:name "John"
:age 25
:occupation "plumber"
} :age)
```
Strings can be used similarly to keywords, but there primary usage is for defining either text
or arbitrary sequences of bytes. Strings (and symbols) in janet are what is sometimes known as
"8-bit clean"; they can hold any number of bytes, and are completely unaware of things like character
encodings. This is completely compatible with ASCII and UTF-8, two of the most common character
encodings. By being encoding agnostic, janet strings can be very simple, fast, and useful for
for other uses besides holding text.
Literal text can be entered inside quotes, as we have seen above.
```
"Hello, this is a string."
# We can also add escape characters for newlines, double quotes, backslash, tabs, etc.
"Hello\nThis is on line two\n\tThis is indented\n"
# For long strings where you don't want to type a lot of escape characters,
# you can use 1 or more backticks (`\``) to delimit a string.
# To close this string, simply repeat the opening sequence of backticks
``
This is a string.
Line 2
Indented
"We can just type quotes here", and backslashes \ no problem.
``
```
# Functions
Janet is a functional language - that means that one of the basic building blocks of your
program will be defining functions (the other is using data structures). Because janet
is a Lisp, functions are values just like numbers or strings - they can be passed around and
created as needed.
Functions can be defined with the `defn` macro, like so:
```lisp
(defn triangle-area
"Calculates the area of a triangle."
[base height]
(print "calculating area of a triangle...")
(* base height 0.5))
```
A function defined with `defn` consists of a name, a number of optional flags for def, and
finally a function body. The example above is named triangle-area and takes two parameters named base and height. The body of the function will print a message and then evaluate to the area of the triangle.
Once a function like the above one is defined, the programmer can use the `triangle-area`
function just like any other, say `print` or `+`.
```lisp
# Prints "calculating area of a triangle..." and then "25"
(print (triangle-area 5 10))
```
Note that when nesting function calls in other function calls like above (a call to triangle-area is
nested inside a call to print), the inner function calls are evaluated first. Also, arguments to
a function call are evaluated in order, from first argument to last argument).
Because functions are first-class values like numbers or strings, they can be passed
as arguments to other functions as well.
```
(print triangle-area)
```
This prints the location in memory of the function triangle area.
Functions don't need to have names. The `fn` keyword can be used to introduce function
literals without binding them to a symbol.
```
# Evaluates to 40
((fn [x y] (+ x x y)) 10 20)
# Also evaluates to 40
((fn [x y &] (+ x x y)) 10 20)
# Will throw an error about the wrong arity
((fn [x] x) 1 2)
# Will not throw an error about the wrong arity
((fn [x &] x) 1 2)
```
The first expression creates an anonymous function that adds twice
the first argument to the second, and then calls that function with arguments 10 and 20.
This will return (10 + 10 + 20) = 40.
There is a common macro `defn` that can be used for creating functions and immediately binding
them to a name. `defn` works as expected at both the top level and inside another form. There is also
the corresponding
Note that putting an ampersand at the end of the argument list inhibits strict arity checking.
This means that such a function will accept fewer or more arguments than specified.
```lisp
(defn myfun [x y]
(+ x x y))
# You can think of defn as a shorthand for def and fn together
(def myfun-same (fn [x y]
(+ x x Y)))
(myfun 3 4) # -> 10
```
Janet has many macros provided for you (and you can write your own).
Macros are just functions that take your source code
and transform it into some other source code, usually automating some repetitive pattern for you.
# Defs and Vars
Values can be bound to symbols for later use using the keyword `def`. Using undefined
symbols will raise an error.
```
(def a 100)
(def b (+ 1 a))
(def c (+ b b))
(def d (- c 100))
```
Bindings created with def have lexical scoping. Also, bindings created with def are immutable; they
cannot be changed after definition. For mutable bindings, like variables in other programming
languages, use the `var` keyword. The assignment special form `set` can then be used to update
a var.
```
(var myvar 1)
(print myvar)
(set myvar 10)
(print myvar)
```
In the global scope, you can use the `:private` option on a def or var to prevent it from
being exported to code that imports your current module. You can also add documentation to
a function by passing a string the def or var command.
```lisp
(def mydef :private "This will have priavte scope. My doc here." 123)
(var myvar "docstring here" 321)
```
## Scopes
Defs and vars (collectively known as bindings) live inside what is called a scope. A scope is
simply where the bindings are valid. If a binding is referenced outside of its scope, the compiler
will throw an error. Scopes are useful for organizing your bindings and my extension your programs.
There are two main ways to create a scope in Janet.
The first is to use the `do` special form. `do` executes a series of statements in a scope
and evaluates to the last statement. Bindings create inside the form do not escape outside
of its scope.
```lisp
(def a :outera)
(do
(def a 1)
(def b 2)
(def c 3)
(+ a b c)) # -> 6
a # -> :outera
b # -> compile error: "unknown symbol \"b\""
c # -> compile error: "unknown symbol \"c\""
```
Any attempt to reference the bindings from the do form after it has finished
executing will fail. Also notice who defining `a` inside the do form did not
overwrite the original definition of `a` for the global scope.
The second way to create a scope is to create a closure.
The `fn` special form also introduces a scope just like
the `do` special form.
There is another built in macro, `let`, that does multiple defs at once, and then introduces a scope.
`let` is a wrapper around a combination of defs and dos, and is the most "functional" way of
creating bindings.
```lisp
(let [a 1
b 2
c 3]
(+ a b c)) # -> 6
```
The above is equivalent to the example using `do` and `def`.
This is the preferable form in most cases,
but using do with multiple defs is fine as well.
# Data Structures
Once you have a handle on functions and the primitive value types, you may be wondering how
to work with collections of things. Janet has a small number of core data structure types
that are very versatile. Tables, Structs, Arrays, Tuples, Strings, and Buffers, are the 6 main
built in data structure types. These data structures can be arranged in a useful table describing
there relationship to each other.
| | Mutable | Immutable |
| ---------- | ------- | --------------- |
| Indexed | Array | Tuple |
| Dictionary | Table | Struct |
| Byteseq | Buffer | String (Symbol) |
Indexed types are linear lists of elements than can be accessed in constant time with an integer index.
Indexed types are backed by a single chunk of memory for fast access, and are indexed from 0 as in C.
Dictionary types associate keys with values. The difference between dictionaries and indexed types
is that dictionaries are not limited to integer keys. They are backed by a hashtable and also offer
constant time lookup (and insertion for the mutable case).
Finally, the 'byteseq' abstraction is any type that contains a sequence of bytes. A byteseq associates
integer keys (the indices) with integer values between 0 and 255 (the byte values). In this way,
they behave much like Arrays and Tuples. However, one cannot put non integer values into a byteseq.
```lisp
(def mytuple (tuple 1 2 3))
(def myarray @(1 2 3))
(def myarray (array 1 2 3))
(def mystruct {
:key "value"
:key2 "another"
1 2
4 3})
(def another-struct
(struct :a 1 :b 2))
(def my-table @{
:a :b
:c :d
:A :qwerty})
(def another-table
(table 1 2 3 4))
(def my-buffer @"thisismutable")
(def my-buffer2 @```
This is also mutable ":)"
```)
```
To read the values in a data structure, use the get function. The first parameter is the data structure
itself, and the second parameter is the key.
```lisp
(get @{:a 1} :a) # -> 1
(get {:a 1} :a) # -> 1
(get @[:a :b :c] 2) # -> :c
(get (tuple "a" "b" "c") 1) # -> "b"
(get @"hello, world" 1) # -> 101
(get "hello, world" 0) # -> 104
```
### Destructuring
In many cases, however, you do not need the `get` function at all. Janet supports destructuring, which
means both the `def` and `var` special forms can extract values from inside structures themselves.
```lisp
# Before, we might do
(def my-array @[:mary :had :a :little :lamb])
(def lamb (get my-array 4))
(print lamb) # Prints :lamb
# Now, with destructuring,
(def [_ _ _ _ lamb] my-array)
(print lamb) # Again, prints :lamb
# Destructuring works with tables as well
(def person @{:name "Bob Dylan" :age 77}
(def
{:name person-name
:age person-age} person)
```
To update a mutable data structure, use the `put` function. It takes 3 arguments, the data structure,
the key, and the value, and returns the data structure. The allowed types keys and values
depend on what data structure is passed in.
```lisp
(put @[] 100 :a)
(put @{} :key "value")
(put @"" 100 92)
```
Note that for Arrays and Buffers, putting an index that is outside the length of the data structure
will extend the data structure and fill it with nils in the case of the Array,
or 0s in the case of the Buffer.
The last generic function for all data structures is the `length` function. This returns the number of
values in a data structure (the number of keys in a dictionary type).
# Flow Control
Janet has only two built in primitives to change flow while inside a function. The first is the
`if` special form, which behaves as expected in most functional languages. It takes two or three parameters:
a condition, an expression to evaluate to if the condition is true (not nil or false),
and an optional condition to evaluate to when the condition is nil or false. If the optional parameter
is omitted, the if form evaluates to nil.
```lisp
(if (> 4 3)
"4 is greater than 3"
"4 is not greater then three") # Evaluates to the first statement
(if true
(print "Hey")) # Will print
(if false
(print "Oy!")) # Will not print
```
The second primitive control flow construct is the while loop. The while behaves much the same
as in many other programming languages, including C, Java, and Python. The while loop takes
two or more parameters: the first is a condition (like in the `if` statement), that is checked before
every iteration of the loop. If it is nil or false, the while loop ends and evaluates to nil. Otherwise,
the rest of the parameters will be evaluated sequentially and then the program will return to the beginning
of the loop.
```
# Loop from 100 down to 1 and print each time
(var i 100)
(while (pos? i)
(print "the number is " i)
(-- i))
# Print ... until a random number in range [0, 1) is >= 0.9
# (math/random evaluates to a value between 0 and 1)
(while (> 0.9 (math/random))
(print "..."))
```
Besides these special forms, Janet has many macros for both conditional testing and looping
that are much better for the majority of cases. For conditional testing, the `cond`, `switch`, and
`when` macros can be used to great effect. `cond` can be used for making an if-else chain, where using
just raw if forms would result in many parentheses. `case` For looping, the `loop`, `seq`, and `generate`
implement janet's form of list comprehension, as in Python or Clojure.
# The Core Library
Janet has a built in core library of over 300 functions and macros at the time of writing.
While some of these functions may be refactored into separate modules, it is useful to get to know
the core to avoid rewriting provided functions.
For any given function, use the `doc` macro to view the documentation for it in the repl.
```lisp
(doc defn) -> Prints the documentation for "defn"
```
To see a list of all global functions in the repl, type the command
```lisp
(table/getproto *env*)
# Or
(all-symbols)
```
Which will print out every built-in global binding
(it will not show your global bindings). To print all
of your global bindings, just use \*env\*, which is a var
that is bound to the current environment.
The convention of surrounding a symbol in stars is taken from lisp
and Clojure, and indicates a global dynamic variable rather than a normal
definition. To get the static environment at the time of compilation, use the
`_env` symbol.
# Prototypes
To support basic generic programming, Janet tables support a prototype
table. A prototype table contains default values for a table if certain keys
are not found in the original table. This allows many similar tables to share
contents without duplicating memory.
```lisp
# One of many Object Oriented schemes that can
# be implented in janet.
(def proto1 @{:type :custom1
:behave (fn [self x] (print "behaving " x))})
(def proto2 @{:type :custom2
:behave (fn [self x] (print "behaving 2 " x))})
(def thing1 (table/setproto @{} proto1))
(def thing2 (table/setproto @{} proto2))
(print thing1:type) # prints :custom1
(print thing2:type) # prints :custom2
(thing1:behave thing1 :a) # prints "behaving :a"
(thing2:behave thing2 :b) # prints "behaving 2 :b"
```
Looking up in a table with a prototype can be summed up with the following algorithm.
1. `(get my-table my-key)` is called.
2. my-table is checked for the key if my-key. If there is a value for the key, it is returned.
3. if there is a prototype table for my-table, set `my-table = my-table's prototype` and got to 2.
4. Return nil as the key was not found.
Janet will check up to about a 1000 prototypes recursively by default before giving up and returning nil. This
is to prevent an infinite loop. This value can be changed by adjusting the `JANET_RECURSION_GUARD` value
in janet.h.
Note that Janet prototypes are not as expressive as metatables in Lua and many other languages.
This is by design, as adding Lua or Python like capabilities would not be technically difficult.
Users should prefer plain data and functions that operate on them rather than mutable objects
with methods.
# Fibers
Janet has support for single-core asynchronous programming via coroutines, or fibers.
Fibers allow a process to stop and resume execution later, essentially enabling
multiple returns from a function. This allows many patterns such a schedules, generators,
iterators, live debugging, and robust error handling. Janet's error handling is actually built on
top of fibers (when an error is thrown, the parent fiber will handle the error).
A temporary return from a fiber is called a yield, and can be invoked with the `yield` function.
To resume a fiber that has been yielded, use the `resume` function. When resume is called on a fiber,
it will only return when that fiber either returns, yields, throws an error, or otherwise emits
a signal.
Different from traditional coroutines, Janet's fibers implement a signaling mechanism, which
is used to differentiate different kinds of returns. When a fiber yields or throws an error,
control is returned to the calling fiber. The parent fiber must then check what kind of state the
fiber is in to differentiate errors from return values from user defined signals.
To create a fiber, user the `fiber/new` function. The fiber constructor take one or two arguments.
the first, necessary argument is the function that the fiber will execute. This function must accept
an arity of zero. The next optional argument is a collection of flags checking what kinds of
signals to trap and return via `resume`. This is useful so
the programmer does not need to handle all different kinds of signals from a fiber. Any un-trapped signals
are simply propagated to the next fiber.
```lisp
(def f (fiber/new (fn []
(yield 1)
(yield 2)
(yield 3)
(yield 4)
5)))
# Get the status of the fiber (:alive, :dead, :debug, :new, :pending, or :user0-:user9)
(print (fiber/status f)) # -> :new
(print (resume f)) # -> prints 1
(print (resume f)) # -> prints 2
(print (resume f)) # -> prints 3
(print (resume f)) # -> prints 4
(print (fiber/status f)) # -> print :pending
(print (resume f)) # -> prints 5
(print (fiber/status f)) # -> print :dead
(print (resume f)) # -> throws an error because the fiber is dead
```
## Using Fibers to Capture Errors
Besides being used as coroutines, fibers can be used to implement error handling (exceptions).
```lisp
(defn my-function-that-errors [x]
(print "start function with " x)
(error "oops!")
(print "never gets here"))
# Use the :e flag to only trap errors.
(def f (fiber/new my-function-that-errors :e))
(def result (resume f))
(if (= (fiber/status f) :error)
(print "result contains the error")
(print "result contains the good result"))
```
# Macros
Janet supports macros like most lisps. A macro is like a function, but transforms
the code itself rather than data. They let you extend the syntax of the language itself.
You have seen some macros already. The `let`, `loop`, and `defn` forms are macros. When the compiler
sees a macro, it evaluates the macro and then compiles the result. We say the macro has been
*expanded* after the compiler evaluates it. A simple version of the `defn` macro can
be thought of as transforming code of the form
```lisp
(defn1 myfun [x] body)
```
into
```lisp
(def myfun (fn myfun [x] body))
```
We could write such a macro like so:
```lisp
(defmacro defn1 [name args body]
(tuple 'def name (tuple 'fn name args body)))
```
There are a couple of issues with this macro, but it will work for simple functions
quite well.
The first issue is that our defn2 macro can't define functions with multiple expressions
in the body. We can make the macro variadic, just like a function. Here is a second version
of this macro.
```lisp
(defmacro defn2 [name args & body]
(tuple 'def name (apply tuple 'fn name args body)))
```
Great! Now we can define functions with multiple elements in the body. We can still improve this
macro even more though. First, we can add a docstring to it. If someone is using the function later,
they can use `(doc defn3)` to get a description of the function. Next, we can rewrite the macro
using janet's builtin quasiquoting facilities.
```lisp
(defmacro defn3
"Defines a new function."
[name args & body]
`(def ,name (fn ,name ,args ,;body)))
```
This is functionally identical to our previous version `defn2`, but written in such
a way that the macro output is more clear. The leading backtick is shorthand for the
`(quasiquote x)` special form, which is like `(quote x)` except we can unquote
expressions inside it. The comma in front of `name` and `args` is an unquote, which
allows us to put a value in the quasiquote. Without the unquote, the symbol \'name\'
would be put in the returned tuple. Without the unquote, every function we defined
would be called \'name\'!.
Similar to name, we must also unquote body. However, a normal unquote doesn't work.
See what happens if we use a normal unquote for body as well.
```lisp
(def name 'myfunction)
(def args '[x y z])
(defn body '[(print x) (print y) (print z)])
`(def ,name (fn ,name ,args ,body))
# -> (def myfunction (fn myfunction (x y z) ((print x) (print y) (print z))))
```
There is an extra set of parentheses around the body of our function! We don't
want to put the body *inside* the form `(fn args ...)`, we want to *splice* it
into the form. Luckily, janet has the `(splice x)` special form for this purpose,
and a shorthand for it, the ; character.
When combined with the unquote special, we get the desired output.
```lisp
`(def ,name (fn ,name ,args ,;body))
# -> (def myfunction (fn myfunction (x y z) (print x) (print y) (print z)))
```
## Hygiene
Sometime when we write macros, we must generate symbols for local bindings. Ignoring that
it could be written as a function, consider
the following macro
```lisp
(defmacro max1
"Get the max of two values."
[x y]
`(if (> ,x ,y) ,x ,y))
```
This almost works, but will evaluate both x and y twice. This is because both show up
in the macro twice. For example, `(max1 (do (print 1) 1) (do (print 2) 2))` will
print both 1 and 2 twice, which is surprising to a user of this macro.
We can do better:
```lisp
(defmacro max2
"Get the max of two values."
[x y]
`(let [x ,x
y ,y]
(if (> x y) x y)))
```
Now we have no double evaluation problem! But we now have an even more subtle problem.
What happens in the following code?
```lisp
(def x 10)
(max2 8 (+ x 4))
```
We want the max to be 14, but this will actually evaluate to 12! This can be understood
if we expand the macro. You can expand macro once in janet using the `(macex1 x)` function.
(To expand macros until there are no macros left to expand, use `(macex x)`. Be careful,
janet has many macros, so the full expansion may be almost unreadable).
```lisp
(macex1 '(max2 8 (+ x 4)))
# -> (let (x 8 y (+ x 4)) (if (> x y) x y))
```
After expansion, y wrongly refers to the x inside the macro (which is bound to 8) rather than the x defined
to be 10. The problem is the reuse of the symbol x inside the macro, which overshadowed the original
binding.
Janet provides a general solution to this problem in terms of the `(gensym)` function, which returns
a symbol which is guarenteed to be unique and not collide with any symbols defined previously. We can define
our macro once more for a fully correct macro.
```lisp
(defmacro max3
"Get the max of two values."
[x y]
(def $x (gensym))
(def $y (gensym))
`(let [,$x ,x
,$y ,y]
(if (> ,$x ,$y) ,$x ,$y)))
```
As you can see, macros are very powerful but also are prone to subtle bugs. You must remember that
at their core, macros are just functions that output code, and the code that they return must
work in many contexts!

View File

@@ -1,245 +0,0 @@
# The Parser
A Janet program begins life as a text file, just a sequence of byte like
any other on your system. Janet source files should be UTF-8 or ASCII
encoded. Before Janet can compile or run your program, it must transform
your source code into a data structure. Janet is a lisp, which means it is
homoiconic - code is data, so all of the facilities in the language for
manipulating arrays, tuples, strings, and tables can be used for manipulating
your source code as well.
But before janet code is represented as a data structure, it must be read, or parsed,
by the janet parser. Called the reader in many other lisps, the parser is a machine
that takes in plain text and outputs data structures which can be used by both
the compiler and macros. In janet, it is a parser rather than a reader because
there is no code execution at read time. This is safer and simpler, and also
lets janet syntax serve as a robust data interchange format. While a parser
is not extensible, in janet the philosophy is to extend the language via macros
rather than reader macros.
## Nil, True and False
Nil, true and false are all literals than can be entered as such
in the parser.
```
nil
true
false
```
## Symbols
Janet symbols are represented a sequence of alphanumeric characters
not starting with a digit. They can also contain the characters
\!, @, $, \%, \^, \&, \*, -, \_, +, =, \|, \~, :, \<, \>, ., \?, \\, /, as
well as any Unicode codepoint not in the ascii range.
By convention, most symbols should be all lower case and use dashes to connect words
(sometimes called kebab case).
Symbols that come from another module often contain a forward slash that separates
the name of the module from the name of the definition in the module
```
symbol
kebab-case-symbol
snake_case_symbol
my-module/my-fuction
*****
!%$^*__--__._+++===~-crazy-symbol
*global-var*
你好
```
## Keywords
Janet keywords are really just symbols that begin with the character :. However, they
are used differently and treated by the compiler as a constant rather than a name for
something. Keywords are used mostly for keys in tables and structs, or pieces of syntax
in macros.
```
:keyword
:range
:0x0x0x0
:a-keyword
::
:
```
## Numbers
Janet numbers are represented by either 32 bit integers or
IEEE-754 floating point numbers. The syntax is similar to that of many other languages
as well. Numbers can be written in base 10, with
underscores used to separate digits into groups. A decimal point can be used for floating
point numbers. Numbers can also be written in other bases by prefixing the number with the desired
base and the character 'r'. For example, 16 can be written as `16`, `1_6`, `16r10`, `4r100`, or `0x10`. The
`0x` prefix can be used for hexadecimal as it is so common. The radix must be themselves written in base 10, and
can be any integer from 2 to 36. For any radix above 10, use the letters as digits (not case sensitive).
```
0
12
-65912
4.98
1.3e18
1.3E18
18r123C
11raaa&a
1_000_000
0xbeef
```
## Strings
Strings in janet are surrounded by double quotes. Strings are 8bit clean, meaning
meaning they can contain any arbitrary sequence of bytes, including embedded
0s. To insert a double quote into a string itself, escape
the double quote with a backslash. For unprintable characters, you can either use
one of a few common escapes, use the `\xHH` escape to escape a single byte in
hexidecimal. The supported escapes are:
- \\xHH Escape a single arbitrary byte in hexidecimal.
- \\n Newline (ASCII 10)
- \\t Tab character (ASCII 9)
- \\r Carriage Return (ASCII 13)
- \\0 Null (ASCII 0)
- \\z Null (ASCII 0)
- \\f Form Feed (ASCII 12)
- \\e Escape (ASCII 27)
- \\" Double Quote (ASCII 34)
- \\\\ Backslash (ASCII 92)
Strings can also contain literal newline characters that will be ignore.
This lets one define a multiline string that does not contain newline characters.
An alternative way of representing strings in janet is the long string, or the backquote
delimited string. A string can also be define to start with a certain number of
backquotes, and will end the same number of backquotes. Long strings
do not contain escape sequences; all bytes will be parsed literally until
ending delimiter is found. This is useful
for definining multiline strings with literal newline characters, unprintable
characters, or strings that would otherwise require many escape sequences.
```
"This is a string."
"This\nis\na\nstring."
"This
is
a
string."
``
This
is
a
string
``
```
## Buffers
Buffers are similar strings except they are mutable data structures. Strings in janet
cannot be mutated after created, where a buffer can be changed after creation.
The syntax for a buffer is the same as that for a string or long string, but
the buffer must be prefixed with the '@' character.
```
@""
@"Buffer."
@``Another buffer``
```
## Tuples
Tuples are a sequence of white space separated values surrounded by either parentheses
or brackets. The parser considers any of the characters ASCII 32, \\0, \\f, \\n, \\r or \\t
to be whitespace.
```
(do 1 2 3)
[do 1 2 3]
```
## Arrays
Arrays are the same as tuples, but have a leading @ to indicate mutability.
```
@(:one :two :three)
@[:one :two :three]
```
## Structs
Structs are represented by a sequence of whitespace delimited key value pairs
surrounded by curly braces. The sequence is defined as key1, value1, key2, value2, etc.
There must be an even number of items between curly braces or the parser will
signal a parse error. Any value can be a key or value. Using nil as a key or
value, however, will drop that pair from the parsed struct.
```
{}
{:key1 "value1" :key2 :value2 :key3 3}
{(1 2 3) (4 5 6)}
{@[] @[]}
{1 2 3 4 5 6}
```
## Tables
Table have the same syntax as structs, except they have the @ prefix to indicate
that they are mutable.
```
@{}
@{:key1 "value1" :key2 :value2 :key3 3}
@{(1 2 3) (4 5 6)}
@{@[] @[]}
@{1 2 3 4 5 6}
```
## Comments
Comments begin with a \# character and continue until the end of the line.
There are no multiline comments. For ricm multiline comments, use a
string literal.
## Shorthands
Often called reader macros in other lisps, Janet provides several shorthand
notations for some forms.
### 'x
Shorthand for `(quote x)`
### ;x
Shorthand for `(splice x)`
### ~x
Shorthand for `(quasiquote x)`
### ,x
Shorthand for `(unquote x)`
These shorthand notations can be combined in any order, allowing
forms like `''x` (`(quote (quote x))`), or `,;x` (`(unquote (splice x))`).
## API
The parser contains the following functions which exposes
the parser state machine as a janet abstract object.
- `parser/byte`
- `parser/consume`
- `parser/error`
- `parser/flush`
- `parser/new`
- `parser/produce`
- `parser/state`
- `parser/status`
- `parser/where`

View File

@@ -1,31 +0,0 @@
# SQLite bindings
There are some sqlite3 bindings in the directory natives/sqlite3 bundled with
the janet source code. They serve mostly as a
proof of concept external c library. To use, first compile the module with Make.
```sh
make natives
```
Next, enter the repl and create a database and a table.
```
janet:1:> (import natives/sqlite3 :as sql)
nil
janet:2:> (def db (sql/open "test.db"))
<sqlite3.connection 0x5561A138C470>
janet:3:> (sql/eval db `CREATE TABLE customers(id INTEGER PRIMARY KEY, name TEXT);`)
@[]
janet:4:> (sql/eval db `INSERT INTO customers VALUES(:id, :name);` {:name "John" :id 12345})
@[]
janet:5:> (sql/eval db `SELECT * FROM customers;`)
@[{"id" 12345 "name" "John"}]
```
Finally, close the database connection when done with it.
```
janet:6:> (sql/close db)
nil
```

View File

@@ -1,238 +0,0 @@
The Janet language is implemented on top of an abstract machine (AM). The compiler
converts Janet data structures to this bytecode, which can then be efficiently executed
from inside a C program. To understand the janet bytecode, it is useful to understand
the abstractions used inside the Janet AM, as well as the C types used to implement these
features.
## The Stack = The Fiber
A Janet Fiber is the type used to represent multiple concurrent processes
in janet. It is basically a wrapper around the idea of a stack. The stack is
divided into a number of stack frames (`JanetStackFrame *` in C), each of which
contains information such as the function that created the stack frame,
the program counter for the stack frame, a pointer to the previous frame,
and the size of the frame. Each stack frame also is paired with a number
registers.
```
X: Slot
X
X - Stack Top, for next function call.
-----
Frame next
-----
X
X
X
X
X
X
X - Stack 0
-----
Frame 0
-----
X
X
X - Stack -1
-----
Frame -1
-----
X
X
X
X
X - Stack -2
-----
Frame -2
-----
...
...
...
-----
Bottom of stack
```
Fibers also have an incomplete stack frame for the next function call on top
of their stacks. Making a function call involves pushing arguments to this
temporary stack, and then invoking either the CALL or TCALL instructions.
Arguments for the next function call are pushed via the PUSH, PUSH2, PUSH3, and
PUSHA instructions. The stack of a fiber will grow as large as needed, although by
default janet will limit the maximum size of a fiber's stack.
The maximum stack size can be modified on a per fiber basis.
The slots in the stack are exposed as virtual registers to instructions. They
can hold any Janet value.
## Closures
All functions in janet are closures; they combine some bytecode instructions
with 0 or more environments. In the C source, a closure (hereby the same as
a function) is represented by the type `JanetFunction *`. The bytecode instruction
part of the function is represented by `JanetFuncDef *`, and a function environment
is represented with `JanetFuncEnv *`.
The function definition part of a function (the 'bytecode' part, `JanetFuncDef *`),
we also store various metadata about the function which is useful for debugging,
as well as constants referenced by the function.
## C Functions
Janet uses C functions to bridge to native code. A C function
(`JanetCFunction *` in C) is a C function pointer that can be called like
a normal janet closure. From the perspective of the bytecode instruction set, there is no difference
in invoking a C function and invoking a normal janet function.
## Bytecode Format
Janet bytecode presents an interface to a virtual machine with a large number
of identical registers that can hold any Janet value (`Janet *` in C). Most instructions
have a destination register, and 1 or 2 source register. Registers are simply
named with positive integers.
Each instruction is a 32 bit integer, meaning that the instruction set is a constant
width RISC instruction set like MIPS. The opcode of each instruction is the least significant
byte of the instruction. The highest bit of
this leading byte is reserved for debugging purpose, so there are 128 possible opcodes encodable
with this scheme. Not all of these possible opcode are defined, and will trap the interpreter
and emit a debug signal. Note that this mean an unknown opcode is still valid bytecode, it will
just put the interpreter into a debug state when executed.
```
X - Payload bits
O - Opcode bits
4 3 2 1
+----+----+----+----+
| XX | XX | XX | OO |
+----+----+----+----+
```
8 bits for the opcode leaves 24 bits for the payload, which may or may not be utilized.
There are a few instruction variants that divide these payload bits.
* 0 arg - Used for noops, returning nil, or other instructions that take no
arguments. The payload is essentially ignored.
* 1 arg - All payload bits correspond to a single value, usually a signed or unsigned integer.
Used for instructions of 1 argument, like returning a value, yielding a value to the parent fiber,
or doing a (relative) jump.
* 2 arg - Payload is split into byte 2 and bytes 3 and 4.
The first argument is the 8 bit value from byte 2, and the second argument is the 16 bit value
from bytes 3 and 4 (`instruction >> 16`). Used for instructions of two arguments, like move, normal
function calls, conditionals, etc.
* 3 arg - Bytes 2, 3, and 4 each correspond to an 8 bit argument.
Used for arithmetic operations, emitting a signal, etc.
These instruction variants can be further refined based on the semantics of the arguments.
Some instructions may treat an argument as a slot index, while other instructions
will treat the argument as a signed integer literal, and index for a constant, an index
for an environment, or an unsigned integer.
## Instruction Reference
A listing of all opcode values can be found in src/include/janet/janetopcodes.h. The janet assembly
short names can be found src/assembler/asm.c. In this document, we will refer to the instructions
by their short names as presented to the assembler rather than their numerical values.
Each instruction is also listed with a signature, which are the arguments the instruction
expects. There are a handful of instruction signatures, which combine the arity and type
of the instruction. The assembler does not
do any typechecking per closure, but does prevent jumping to invalid instructions and
failure to return or error.
### Notation
* The $ prefix indicates that a instruction parameter is acting as a virtual register (slot).
If a parameter does not have the $ suffix in the description, it is acting as some kind
of literal (usually an unsigned integer for indexes, and a signed integer for literal integers).
* Some operators in the description have the suffix 'i' or 'r'. These indicate
that these operators correspond to integers or real numbers only, respectively. All
bitwise operators and bit shifts only work with integers.
* The `>>>` indicates unsigned right shift, as in Java. Because all integers in janet are
signed, we differentiate the two kinds of right bit shift.
* The 'im' suffix in the instruction name is short for immediate. The 'i' suffix is short for integer,
and the 'r' suffix is short for real.
### Reference Table
| Instruction | Signature | Description |
| ----------- | --------------------------- | --------------------------------- |
| `add` | `(add dest lhs rhs)` | $dest = $lhs + $rhs |
| `addi` | `(addi dest lhs rhs)` | $dest = $lhs +i $rhs |
| `addim` | `(addim dest lhs im)` | $dest = $lhs +i im |
| `addr` | `(addr dest lhs rhs)` | $dest = $lhs +r $rhs |
| `band` | `(band dest lhs rhs)` | $dest = $lhs & $rhs |
| `bnot` | `(bnot dest operand)` | $dest = ~$operand |
| `bor` | `(bor dest lhs rhs)` | $dest = $lhs | $rhs |
| `bxor` | `(bxor dest lhs rhs)` | $dest = $lhs ^ $rhs |
| `call` | `(call dest callee)` | $dest = call($callee, args) |
| `clo` | `(clo dest index)` | $dest = closure(defs[$index]) |
| `cmp` | `(cmp dest lhs rhs)` | $dest = janet\_compare($lhs, $rhs) |
| `div` | `(div dest lhs rhs)` | $dest = $lhs / $rhs |
| `divi` | `(divi dest lhs rhs)` | $dest = $lhs /i $rhs |
| `divim` | `(divim dest lhs im)` | $dest = $lhs /i im |
| `divr` | `(divr dest lhs rhs)` | $dest = $lhs /r $rhs |
| `eq` | `(eq dest lhs rhs)` | $dest = $lhs == $rhs |
| `eqi` | `(eqi dest lhs rhs)` | $dest = $lhs ==i $rhs |
| `eqim` | `(eqim dest lhs im)` | $dest = $lhs ==i im |
| `eqr` | `(eqr dest lhs rhs)` | $dest = $lhs ==r $rhs |
| `err` | `(err message)` | Throw error $message. |
| `get` | `(get dest ds key)` | $dest = $ds[$key] |
| `geti` | `(geti dest ds index)` | $dest = $ds[index] |
| `gt` | `(gt dest lhs rhs)` | $dest = $lhs > $rhs |
| `gti` | `(gti dest lhs rhs)` | $dest = $lhs \>i $rhs |
| `gtim` | `(gtim dest lhs im)` | $dest = $lhs \>i im |
| `gtr` | `(gtr dest lhs rhs)` | $dest = $lhs \>r $rhs |
| `gter` | `(gter dest lhs rhs)` | $dest = $lhs >=r $rhs |
| `jmp` | `(jmp label)` | pc = label, pc += offset |
| `jmpif` | `(jmpif cond label)` | if $cond pc = label else pc++ |
| `jmpno` | `(jmpno cond label)` | if $cond pc++ else pc = label |
| `ldc` | `(ldc dest index)` | $dest = constants[index] |
| `ldf` | `(ldf dest)` | $dest = false |
| `ldi` | `(ldi dest integer)` | $dest = integer |
| `ldn` | `(ldn dest)` | $dest = nil |
| `lds` | `(lds dest)` | $dest = current closure (self) |
| `ldt` | `(ldt dest)` | $dest = true |
| `ldu` | `(ldu dest env index)` | $dest = envs[env][index] |
| `len` | `(len dest ds)` | $dest = length(ds) |
| `lt` | `(lt dest lhs rhs)` | $dest = $lhs < $rhs |
| `lti` | `(lti dest lhs rhs)` | $dest = $lhs \<i $rhs |
| `ltim` | `(ltim dest lhs im)` | $dest = $lhs \<i im |
| `ltr` | `(ltr dest lhs rhs)` | $dest = $lhs \<r $rhs |
| `mkarr` | `(mkarr dest)` | $dest = call(array, args) |
| `mkbuf` | `(mkbuf dest)` | $dest = call(buffer, args) |
| `mktab` | `(mktab dest)` | $dest = call(table, args) |
| `mkstr` | `(mkstr dest)` | $dest = call(string, args) |
| `mkstu` | `(mkstu dest)` | $dest = call(struct, args) |
| `mktup` | `(mktup dest)` | $dest = call(tuple, args) |
| `movf` | `(movf src dest)` | $dest = $src |
| `movn` | `(movn dest src)` | $dest = $src |
| `mul` | `(mul dest lhs rhs)` | $dest = $lhs * $rhs |
| `muli` | `(muli dest lhs rhs)` | $dest = $lhs \*i $rhs |
| `mulim` | `(mulim dest lhs im)` | $dest = $lhs \*i im |
| `mulr` | `(mulr dest lhs rhs)` | $dest = $lhs \*r $rhs |
| `noop` | `(noop)` | Does nothing. |
| `push` | `(push val)` | Push $val on arg |
| `push2` | `(push2 val1 val3)` | Push $val1, $val2 on args |
| `push3` | `(push3 val1 val2 val3)` | Push $val1, $val2, $val3, on args |
| `pusha` | `(pusha array)` | Push values in $array on args |
| `put` | `(put ds key val)` | $ds[$key] = $val |
| `puti` | `(puti ds index val)` | $ds[index] = $val |
| `res` | `(res dest fiber val)` | $dest = resume $fiber with $val |
| `ret` | `(ret val)` | Return $val |
| `retn` | `(retn)` | Return nil |
| `setu` | `(setu env index val)` | envs[env][index] = $val |
| `sig` | `(sig dest value sigtype)` | $dest = emit $value as sigtype |
| `sl` | `(sl dest lhs rhs)` | $dest = $lhs << $rhs |
| `slim` | `(slim dest lhs shamt)` | $dest = $lhs << shamt |
| `sr` | `(sr dest lhs rhs)` | $dest = $lhs >> $rhs |
| `srim` | `(srim dest lhs shamt)` | $dest = $lhs >> shamt |
| `sru` | `(sru dest lhs rhs)` | $dest = $lhs >>> $rhs |
| `sruim` | `(sruim dest lhs shamt)` | $dest = $lhs >>> shamt |
| `sub` | `(sub dest lhs rhs)` | $dest = $lhs - $rhs |
| `tcall` | `(tcall callee)` | Return call($callee, args) |
| `tchck` | `(tcheck slot types)` | Assert $slot does matches types |

View File

@@ -5,10 +5,14 @@
(def solutions @{})
(def len (length s))
(for k 0 len
(put tab s@k k))
(put tab (s k) k))
(for i 0 len
(for j 0 len
(def k (get tab (- 0 s@i s@j)))
(def k (get tab (- 0 (s i) (s j))))
(when (and k (not= k i) (not= k j) (not= i j))
(put solutions {i true j true k true} true))))
(map keys (keys solution)))
(map keys (keys solutions)))
(def arr @[2 4 1 3 8 7 -3 -1 12 -5 -8])
(printf "3sum of %P: " arr)
(printf "%P\n" (sum3 arr))

View File

@@ -13,8 +13,16 @@
(addim 0 0 -0x1) # $0 = $0 - 1
(push 0) # push($0)
(call 0 1) # $0 = call($1)
(addi 0 0 2) # $0 = $0 + $2 (integers)
(add 0 0 2) # $0 = $0 + $2 (integers)
:done
(ret 0) # return $0
]
}))
# Test it
(defn testn
[n]
(print "fibasm(" n ") = " (fibasm n)))
(for i 0 10 (testn i))

View File

@@ -35,7 +35,13 @@
:bright-white 97
:bg-bright-white 107})
(loop [[name color] :in (pairs colormap)]
(defglobal (string.slice name 1)
(fn color-wrapper [& pieces]
(string "\e[" color "m" (apply string pieces) "\e[0m"))))
(defn color
"Take a string made by concatenating xs and colorize it for an ANSI terminal."
[c & xs]
(def code (get colormap c))
(if (not code) (error (string "color " c " unknown")))
(string "\e[" code "m" ;xs "\e[0m"))
# Print all colors
(loop [c :keys colormap] (print (color c c)))

11
examples/debug.janet Normal file
View File

@@ -0,0 +1,11 @@
# Load this file and run (myfn) to see the debugger
(defn myfn
[]
(debug)
(for i 0 10 (print i)))
(debug/fbreak myfn 3)
# Enable debugging in repl with
# (setdyn :debug true)

151
examples/debugger.janet Normal file
View File

@@ -0,0 +1,151 @@
###
### A useful debugger library for Janet. Should be used
### inside a debug repl. This has been moved into the core.
###
(defn .fiber
"Get the current fiber being debugged."
[]
(dyn :fiber))
(defn .stack
"Print the current fiber stack"
[]
(print)
(with-dyns [:err-color false] (debug/stacktrace (.fiber) ""))
(print))
(defn .frame
"Show a stack frame"
[&opt n]
(def stack (debug/stack (.fiber)))
(in stack (or n 0)))
(defn .fn
"Get the current function"
[&opt n]
(in (.frame n) :function))
(defn .slots
"Get an array of slots in a stack frame"
[&opt n]
(in (.frame n) :slots))
(defn .slot
"Get the value of the nth slot."
[&opt nth frame-idx]
(in (.slots frame-idx) (or nth 0)))
(defn .quit
"Resume (dyn :fiber) with the value passed to it after exiting the debugger."
[&opt val]
(setdyn :exit true)
(setdyn :resume-value val)
nil)
(defn .disasm
"Gets the assembly for the current function."
[&opt n]
(def frame (.frame n))
(def func (frame :function))
(disasm func))
(defn .bytecode
"Get the bytecode for the current function."
[&opt n]
((.disasm n) 'bytecode))
(defn .ppasm
"Pretty prints the assembly for the current function"
[&opt n]
(def frame (.frame n))
(def func (frame :function))
(def dasm (disasm func))
(def bytecode (dasm 'bytecode))
(def pc (frame :pc))
(def sourcemap (dasm 'sourcemap))
(var last-loc [-2 -2])
(print "\n function: " (dasm 'name) " [" (in dasm 'source "") "]")
(when-let [constants (dasm 'constants)]
(printf " constants: %.4Q" constants))
(printf " slots: %.4Q\n" (frame :slots))
(def padding (string/repeat " " 20))
(loop [i :range [0 (length bytecode)]
:let [instr (bytecode i)]]
(prin (if (= (tuple/type instr) :brackets) "*" " "))
(prin (if (= i pc) "> " " "))
(prinf "\e[33m%.20s\e[0m" (string (string/join (map string instr) " ") padding))
(when sourcemap
(let [[sl sc] (sourcemap i)
loc [sl sc]]
(when (not= loc last-loc)
(set last-loc loc)
(prin " # line " sl ", column " sc))))
(print))
(print))
(defn .source
"Show the source code for the function being debugged."
[&opt n]
(def frame (.frame n))
(def s (frame :source))
(def all-source (slurp s))
(print "\n\e[33m" all-source "\e[0m\n"))
(defn .breakall
"Set breakpoints on all instructions in the current function."
[&opt n]
(def fun (.fn n))
(def bytecode (.bytecode n))
(for i 0 (length bytecode)
(debug/fbreak fun i))
(print "Set " (length bytecode) " breakpoints in " fun))
(defn .clearall
"Clear all breakpoints on the current function."
[&opt n]
(def fun (.fn n))
(def bytecode (.bytecode n))
(for i 0 (length bytecode)
(debug/unfbreak fun i))
(print "Cleared " (length bytecode) " breakpoints in " fun))
(defn .break
"Set breakpoint at the current pc."
[]
(def frame (.frame))
(def fun (frame :function))
(def pc (frame :pc))
(debug/fbreak fun pc)
(print "Set breakpoint in " fun " at pc=" pc))
(defn .clear
"Clear the current breakpoint"
[]
(def frame (.frame))
(def fun (frame :function))
(def pc (frame :pc))
(debug/unfbreak fun pc)
(print "Cleared breakpoint in " fun " at pc=" pc))
(defn .next
"Go to the next breakpoint."
[&opt n]
(var res nil)
(for i 0 (or n 1)
(set res (resume (.fiber))))
res)
(defn .nextc
"Go to the next breakpoint, clearing the current breakpoint."
[&opt n]
(.clear)
(.next n))
(defn .step
"Execute the next n instructions."
[&opt n]
(var res nil)
(for i 0 (or n 1)
(set res (debug/step (.fiber))))
res)

View File

@@ -19,7 +19,7 @@
,state
(do
(set ,loaded true)
(set ,state (do ;forms)))))))
(set ,state (do ,;forms)))))))
# Use tuples instead of structs to save memory
(def- HEAD 0)
@@ -52,7 +52,7 @@
(defn lazy-range
"Return a sequence of integers [start, end)."
@[start end]
[start end &]
(if end
(if (< start end)
(delay (tuple start (lazy-range (+ 1 start) end)))
@@ -94,7 +94,7 @@
(defn randseq
"Return a sequence of random numbers."
[]
(delay (tuple (math.random) (randseq))))
(delay (tuple (math/random) (randseq))))
(defn take-while
"Returns a sequence of values until the predicate is false."

View File

@@ -4,11 +4,11 @@
(seq [x :range [-1 2]
y :range [-1 2]
:when (not (and (zero? x) (zero? y)))]
(tuple x y)))
[x y]))
(defn- neighbors
[[x y]]
(map (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) window))
(map (fn [[x1 y1]] [(+ x x1) (+ y y1)]) window))
(defn tick
"Get the next state in the Game Of Life."
@@ -16,7 +16,7 @@
(def cell-set (frequencies state))
(def neighbor-set (frequencies (mapcat neighbors state)))
(seq [coord :keys neighbor-set
:let [count neighbor-set.coord]
:let [count (get neighbor-set coord)]
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
coord))
@@ -24,11 +24,11 @@
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
[state x1 y1 x2 y2]
(def cellset @{})
(each cell state (set cellset.cell true))
(each cell state (put cellset cell true))
(loop [x :range [x1 (+ 1 x2)]
:after (print)
y :range [y1 (+ 1 y2)]]
(file/write stdout (if (get cellset (tuple x y)) "X " ". ")))
(file/write stdout (if (get cellset [x y]) "X " ". ")))
(print))
#

View File

@@ -2,10 +2,8 @@
# of the triangle to the leaves of the triangle.
(defn myfold [xs ys]
(let [xs1 (tuple/prepend xs 0)
xs2 (tuple/append xs 0)
m1 (map + xs1 ys)
m2 (map + xs2 ys)]
(let [m1 (map + [;xs 0] ys)
m2 (map + [0 ;xs] ys)]
(map max m1 m2)))
(defn maxpath [t]

1
examples/numarray/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,117 @@
#include <stdlib.h>
#include <janet.h>
typedef struct {
double *data;
size_t size;
} num_array;
static num_array *num_array_init(num_array *array, size_t size) {
array->data = (double *)calloc(size, sizeof(double));
array->size = size;
return array;
}
static void num_array_deinit(num_array *array) {
free(array->data);
}
static int num_array_gc(void *p, size_t s) {
(void) s;
num_array *array = (num_array *)p;
num_array_deinit(array);
return 0;
}
int num_array_get(void *p, Janet key, Janet *out);
void num_array_put(void *p, Janet key, Janet value);
static const JanetAbstractType num_array_type = {
"numarray",
num_array_gc,
NULL,
num_array_get,
num_array_put,
JANET_ATEND_PUT
};
static Janet num_array_new(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
int32_t size = janet_getinteger(argv, 0);
num_array *array = (num_array *)janet_abstract(&num_array_type, sizeof(num_array));
num_array_init(array, size);
return janet_wrap_abstract(array);
}
static Janet num_array_scale(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
double factor = janet_getnumber(argv, 1);
size_t i;
for (i = 0; i < array->size; i++) {
array->data[i] *= factor;
}
return argv[0];
}
static Janet num_array_sum(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
double sum = 0;
for (size_t i = 0; i < array->size; i++) sum += array->data[i];
return janet_wrap_number(sum);
}
void num_array_put(void *p, Janet key, Janet value) {
size_t index;
num_array *array = (num_array *)p;
if (!janet_checkint(key))
janet_panic("expected integer key");
if (!janet_checktype(value, JANET_NUMBER))
janet_panic("expected number value");
index = (size_t)janet_unwrap_integer(key);
if (index < array->size) {
array->data[index] = janet_unwrap_number(value);
}
}
static const JanetMethod methods[] = {
{"scale", num_array_scale},
{"sum", num_array_sum},
{NULL, NULL}
};
int num_array_get(void *p, Janet key, Janet *out) {
size_t index;
num_array *array = (num_array *)p;
if (janet_checktype(key, JANET_KEYWORD))
return janet_getmethod(janet_unwrap_keyword(key), methods, out);
if (!janet_checkint(key))
janet_panic("expected integer key");
index = (size_t)janet_unwrap_integer(key);
if (index >= array->size) {
return 0;
} else {
*out = janet_wrap_number(array->data[index]);
}
return 1;
}
static const JanetReg cfuns[] = {
{
"new", num_array_new,
"(numarray/new size)\n\n"
"Create new numarray"
},
{
"scale", num_array_scale,
"(numarray/scale numarray factor)\n\n"
"scale numarray by factor"
},
{NULL, NULL, NULL}
};
JANET_MODULE_ENTRY(JanetTable *env) {
janet_cfuns(env, "numarray", cfuns);
}

View File

@@ -0,0 +1,7 @@
(declare-project
:name "numarray"
:description "Example c lib with abstract type")
(declare-native
:name "numarray"
:source @["numarray.c"])

View File

@@ -0,0 +1,17 @@
(import build/numarray)
(def a (numarray/new 30))
(print (get a 20))
(print (a 20))
(put a 5 3.14)
(print (a 5))
(set (a 5) 100)
(print (a 5))
# (numarray/scale a 5))
# ((a :scale) a 5)
(:scale a 5)
(for i 0 10 (print (a i)))
(print "sum=" (:sum a))

View File

@@ -12,3 +12,5 @@
(if (zero? (% i trial)) (set isprime? false)))
(if isprime? (array/push list i)))
list)
(pp (primes 100))

11
examples/rtest.janet Normal file
View File

@@ -0,0 +1,11 @@
# How random is the RNG really?
(def counts (seq [_ :range [0 100]] 0))
(for i 0 1000000
(let [x (math/random)
intrange (math/floor (* 100 x))
oldcount (counts intrange)]
(put counts intrange (if oldcount (+ 1 oldcount) 1))))
(pp counts)

73
examples/tarray.janet Normal file
View File

@@ -0,0 +1,73 @@
# naive matrix implementation for testing typed array
(defn matrix [nrow ncol] {:nrow nrow :ncol ncol :array (tarray/new :float64 (* nrow ncol))})
(defn matrix/row [mat i]
(def {:nrow nrow :ncol ncol :array array} mat)
(tarray/new :float64 ncol 1 (* i ncol) array))
(defn matrix/column [mat j]
(def {:nrow nrow :ncol ncol :array array} mat)
(tarray/new :float64 nrow ncol j array))
(defn matrix/set [mat i j value]
(def {:nrow nrow :ncol ncol :array array} mat)
(set (array (+ (* i ncol) j)) value))
(defn matrix/get [mat i j value]
(def {:nrow nrow :ncol ncol :array array} mat)
(array (+ (* i ncol) j)))
# other variants to test rows and cols views
(defn matrix/set* [mat i j value]
(set ((matrix/row mat i) j) value))
(defn matrix/set** [mat i j value]
(set ((matrix/column mat j) i) value))
(defn matrix/get* [mat i j value]
((matrix/row mat i) j))
(defn matrix/get** [mat i j value]
((matrix/column mat j) i))
(defn tarray/print [arr]
(def size (tarray/length arr))
(prinf "[%2i]" size)
(for i 0 size
(prinf " %+6.3f " (arr i)))
(print))
(defn matrix/print [mat]
(def {:nrow nrow :ncol ncol :array tarray} mat)
(printf "matrix %iX%i %p" nrow ncol tarray)
(for i 0 nrow
(tarray/print (matrix/row mat i))))
(def nr 5)
(def nc 4)
(def A (matrix nr nc))
(loop (i :range (0 nr) j :range (0 nc))
(matrix/set A i j i))
(matrix/print A)
(loop (i :range (0 nr) j :range (0 nc))
(matrix/set* A i j i))
(matrix/print A)
(loop (i :range (0 nr) j :range (0 nc))
(matrix/set** A i j i))
(matrix/print A)
(printf "properties:\n%p" (tarray/properties (A :array)))
(for i 0 nr
(printf "row properties:[%i]\n%p" i (tarray/properties (matrix/row A i))))
(for i 0 nc
(printf "col properties:[%i]\n%p" i (tarray/properties (matrix/column A i))))

6
examples/tcpclient.janet Normal file
View File

@@ -0,0 +1,6 @@
(with [conn (net/connect "127.0.0.1" "8000")]
(printf "Connected to %q!" conn)
(:write conn "Echo...")
(print "Wrote to connection...")
(def res (:read conn 1024))
(pp res))

13
examples/tcpserver.janet Normal file
View File

@@ -0,0 +1,13 @@
(defn handler
"Simple handler for connections."
[stream]
(defer (:close stream)
(def id (gensym))
(def b @"")
(print "Connection " id "!")
(while (:read stream 1024 b)
(:write stream b)
(buffer/clear b))
(printf "Done %v!" id)))
(net/server "127.0.0.1" "8000" handler)

68
examples/threads.janet Normal file
View File

@@ -0,0 +1,68 @@
(defn worker-main
"Sends 11 messages back to parent"
[parent]
(def name (thread/receive))
(def interval (thread/receive))
(for i 0 10
(os/sleep interval)
(:send parent (string/format "thread %s wakeup no. %d" name i)))
(:send parent name))
(defn make-worker
[name interval]
(-> (thread/new worker-main)
(:send name)
(:send interval)))
(def bob (make-worker "bob" 0.02))
(def joe (make-worker "joe" 0.03))
(def sam (make-worker "sam" 0.05))
# Receive out of order
(for i 0 33
(print (thread/receive)))
#
# Recursive Thread Tree - should pause for a bit, and then print a cool zigzag.
#
(def rng (math/rng (os/cryptorand 16)))
(defn choose [& xs]
(in xs (:int rng (length xs))))
(defn worker-tree
[parent]
(def name (thread/receive))
(def depth (thread/receive))
(if (< depth 5)
(do
(defn subtree []
(-> (thread/new worker-tree)
(:send (string name "/" (choose "bob" "marley" "harry" "suki" "anna" "yu")))
(:send (inc depth))))
(let [l (subtree)
r (subtree)
lrep (thread/receive)
rrep (thread/receive)]
(:send parent [name ;lrep ;rrep])))
(do
(:send parent [name]))))
(-> (thread/new worker-tree) (:send "adam") (:send 0))
(def lines (thread/receive))
(map print lines)
#
# Receive timeout
#
(def slow (make-worker "slow-loras" 0.5))
(for i 0 50
(try
(let [msg (thread/receive 0.1)]
(print "\n" msg))
([err] (prin ".") (:flush stdout))))
(print "\ndone timing, timeouts ending.")
(try (while true (print (thread/receive))) ([err] (print "done")))

29
examples/urlloader.janet Normal file
View File

@@ -0,0 +1,29 @@
# An example of using Janet's extensible module system
# to import files from URL. To try this, run `janet -l examples/urlloader.janet`
# from the repl, and then:
#
# (import https://raw.githubusercontent.com/janet-lang/janet/master/examples/colors.janet :as c)
#
# This will import a file using curl. You can then try
#
# (print (c/color :green "Hello!"))
#
# This is a bit of a toy example (it just shells out to curl), but it is very
# powerful and will work well in many cases.
(defn- load-url
[url args]
(def f (file/popen (string "curl " url)))
(def res (dofile f :source url ;args))
(try (file/close f) ([err] nil))
res)
(defn- check-http-url
[path]
(if (or (string/has-prefix? "http://" path)
(string/has-prefix? "https://" path))
path))
# Add the module loader and path tuple to right places
(array/push module/paths [check-http-url :janet-http])
(put module/loaders :janet-http load-url)

View File

@@ -1,335 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>janet</string>
</array>
<key>foldingStartMarker</key>
<string>\{</string>
<key>foldingStopMarker</key>
<string>\}</string>
<key>foldingStartMarker</key>
<string>\[</string>
<key>foldingStopMarker</key>
<string>\]</string>
<key>foldingStartMarker</key>
<string>\(</string>
<key>foldingStopMarker</key>
<string>\)</string>
<key>keyEquivalent</key>
<string>^~L</string>
<key>name</key>
<string>Janet</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#all</string>
</dict>
</array>
<key>repository</key>
<dict>
<key>all</key>
<dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#comment</string>
</dict>
<dict>
<key>include</key>
<string>#parens</string>
</dict>
<dict>
<key>include</key>
<string>#brackets</string>
</dict>
<dict>
<key>include</key>
<string>#braces</string>
</dict>
<dict>
<key>include</key>
<string>#readermac</string>
</dict>
<dict>
<key>include</key>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>#longstring</string>
</dict>
<dict>
<key>include</key>
<string>#literal</string>
</dict>
<dict>
<key>include</key>
<string>#corelib</string>
</dict>
<dict>
<key>include</key>
<string>#r-number</string>
</dict>
<dict>
<key>include</key>
<string>#dec-number</string>
</dict>
<dict>
<key>include</key>
<string>#hex-number</string>
</dict>
<dict>
<key>include</key>
<string>#keysym</string>
</dict>
<dict>
<key>include</key>
<string>#symbol</string>
</dict>
</array>
</dict>
<key>comment</key>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.janet</string>
</dict>
</dict>
<key>match</key>
<string>(#).*$</string>
<key>name</key>
<string>comment.line.janet</string>
</dict>
<key>braces</key>
<dict>
<key>begin</key>
<string>(@?{)</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.braces.begin.janet</string>
</dict>
</dict>
<key>end</key>
<string>(})</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.braces.end.janet</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#all</string>
</dict>
</array>
</dict>
<key>brackets</key>
<dict>
<key>begin</key>
<string>(@?\[)</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.brackets.begin.janet</string>
</dict>
</dict>
<key>end</key>
<string>(\])</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.brackets.end.janet</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#all</string>
</dict>
</array>
</dict>
<key>parens</key>
<dict>
<key>begin</key>
<string>(@?\()</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.parens.begin.janet</string>
</dict>
</dict>
<key>end</key>
<string>(\))</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.parens.end.janet</string>
</dict>
</dict>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#all</string>
</dict>
</array>
</dict>
<key>readermac</key>
<dict>
<key>match</key>
<string>[\'\~\;\,]</string>
<key>name</key>
<string>punctuation.other.janet</string>
</dict>
<!-- string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*]) token match here (?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string -->
<key>literal</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])(true|false|nil)(?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string>
<key>name</key>
<string>constant.language.janet</string>
</dict>
<key>corelib</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])(%|%=|\*|\*=|\*doc\-width\*|\*env\*|\+|\+\+|\+=|\-|\-\-|\-=|\-&gt;|\-&gt;&gt;|\-\?&gt;|\-\?&gt;&gt;|&#47;|&#47;=|&lt;|&lt;=|=|==|&gt;|&gt;=|_env|abstract\?|all|all\-symbols|allsyms|and|apply|array|array&#47;concat|array&#47;ensure|array&#47;insert|array&#47;new|array&#47;peek|array&#47;pop|array&#47;push|array&#47;slice|array\?|as\-&gt;|as\?\-&gt;|asm|band|blshift|bnot|boolean\?|bor|brshift|brushift|buffer|buffer&#47;clear|buffer&#47;new|buffer&#47;popn|buffer&#47;push\-byte|buffer&#47;push\-integer|buffer&#47;push\-string|buffer&#47;slice|buffer\?|bxor|bytes\?|callable\?|case|cfunction\?|comment|comp|compile|complement|cond|coro|count|debug|debug&#47;arg\-stack|debug&#47;break|debug&#47;fbreak|debug&#47;lineage|debug&#47;stack|debug&#47;unbreak|debug&#47;unfbreak|dec|deep\-not=|deep=|def\-|default|defglobal|defmacro|defmacro\-|defn|defn\-|describe|dictionary\?|disasm|distinct|doc|doc\*|doc\-format|drop\-until|drop\-while|each|empty\?|env\-lookup|error|eval|eval\-string|even\?|every\?|extreme|false\?|fiber&#47;current|fiber&#47;maxstack|fiber&#47;new|fiber&#47;setmaxstack|fiber&#47;status|fiber\?|file&#47;close|file&#47;flush|file&#47;open|file&#47;popen|file&#47;read|file&#47;seek|file&#47;write|filter|find|find\-index|first|flatten|flatten\-into|for|frequencies|function\?|gccollect|gcinterval|gcsetinterval|generate|gensym|get|getline|hash|idempotent\?|identity|if\-let|if\-not|import|import\*|inc|indexed\?|int|integer\?|interleave|interpose|invert|janet&#47;build|janet&#47;version|juxt|juxt\*|keep|keys|keyword\?|kvs|last|length|let|loop|macex|macex1|make\-env|map|mapcat|marshal|match|match\-1|math&#47;acos|math&#47;asin|math&#47;atan|math&#47;ceil|math&#47;cos|math&#47;e|math&#47;exp|math&#47;floor|math&#47;inf|math&#47;log|math&#47;log10|math&#47;pi|math&#47;pow|math&#47;random|math&#47;seedrandom|math&#47;sin|math&#47;sqrt|math&#47;tan|max|max\-order|merge|merge\-into|min|min\-order|module&#47;find|module&#47;native\-paths|module&#47;paths|native|neg\?|next|nil\?|not|not=|not==|number\?|odd\?|one\?|or|order&lt;|order&lt;=|order&gt;|order&gt;=|os&#47;clock|os&#47;cwd|os&#47;execute|os&#47;exit|os&#47;getenv|os&#47;setenv|os&#47;shell|os&#47;sleep|os&#47;time|os&#47;which|pairs|parser&#47;byte|parser&#47;consume|parser&#47;error|parser&#47;flush|parser&#47;new|parser&#47;produce|parser&#47;state|parser&#47;status|parser&#47;where|partial|pos\?|post\-walk|pre\-walk|print|process&#47;args|product|put|range|real|real\?|reduce|repl|require|resume|reverse|run\-context|scan\-integer|scan\-number|scan\-real|sentinel|seq|some|sort|sorted|status\-pp|stderr|stdin|stdout|string|string&#47;ascii\-lower|string&#47;ascii\-upper|string&#47;bytes|string&#47;check\-set|string&#47;find|string&#47;find\-all|string&#47;from\-bytes|string&#47;join|string&#47;number|string&#47;pretty|string&#47;repeat|string&#47;replace|string&#47;replace\-all|string&#47;reverse|string&#47;slice|string&#47;split|string\?|struct|struct\?|sum|symbol|symbol\?|table|table&#47;getproto|table&#47;new|table&#47;rawget|table&#47;setproto|table&#47;to\-struct|table\?|take\-until|take\-while|true\?|tuple|tuple&#47;append|tuple&#47;prepend|tuple&#47;slice|tuple\?|type|unless|unmarshal|update|values|varglobal|walk|when|when\-let|with\-idemp|yield|zero\?|zipcoll)(?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string>
<key>name</key>
<string>keyword.control.janet</string>
</dict>
<key>keysym</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*]):[\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*]*</string>
<key>name</key>
<string>constant.keyword.janet</string>
</dict>
<key>symbol</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])[\.a-zA-Z_\-=!@\$%^&amp;?|\\/&lt;&gt;*][\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*]*</string>
<key>name</key>
<string>variable.other.janet</string>
</dict>
<key>hex-number</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])[-+]?0x([_\da-fA-F]+|[_\da-fA-F]+\.[_\da-fA-F]*|\.[_\da-fA-F]+)(&amp;[+-]?[\da-fA-F]+)?(?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string>
<key>name</key>
<string>constant.numeric.hex.janet</string>
</dict>
<key>dec-number</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])[-+]?([_\d]+|[_\d]+\.[_\d]*|\.[_\d]+)([eE&amp;][+-]?[\d]+)?(?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string>
<key>name</key>
<string>constant.numeric.decimal.janet</string>
</dict>
<key>r-number</key>
<dict>
<key>match</key>
<string>(?&lt;![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])[-+]?\d\d?r([_\w]+|[_\w]+\.[_\w]*|\.[_\w]+)(&amp;[+-]?[\w]+)?(?![\.:\w_\-=!@\$%^&amp;?|\\/&lt;&gt;*])</string>
<key>name</key>
<string>constant.numeric.decimal.janet</string>
</dict>
<key>string</key>
<dict>
<key>begin</key>
<string>(@?")</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.janet</string>
</dict>
</dict>
<key>end</key>
<string>(")</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.janet</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.janet</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>(\\[ne0zft"\\']|\\x[0-9a-fA-F][0-9a-fA-f])</string>
<key>name</key>
<string>constant.character.escape.janet</string>
</dict>
</array>
</dict>
<key>longstring</key>
<dict>
<key>begin</key>
<string>(@?)(`+)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.janet</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.janet</string>
</dict>
</dict>
<key>end</key>
<string>\2</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.janet</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.triple.janet</string>
</dict>
<key>nomatch</key>
<dict>
<key>match</key>
<string>\S+</string>
<key>name</key>
<string>invalid.illegal.janet</string>
</dict>
</dict>
<key>scopeName</key>
<string>source.janet</string>
<key>uuid</key>
<string>3743190f-20c4-44d0-8640-6611a983296b</string>
</dict>
</plist>

View File

@@ -1,30 +0,0 @@
# Helper to generate core library mappings for janet
(def allsyms (all-symbols))
(def- escapes
{(get "|" 0) `\|`
(get "-" 0) `\-`
(get "+" 0) `\+`
(get "*" 0) `\*`
(get "^" 0) `\^`
(get "$" 0) `\$`
(get "?" 0) `\?`
38 "&amp;"
60 "&lt;"
62 "&gt;"
34 "&quot;"
39 "&#39;"
47 "&#47;"})
(defn- escape
"Escape special characters for HTML and regex encoding."
[str]
(def buf @"")
(loop [byte :in str]
(if-let [rep escapes.byte]
(buffer/push-string buf rep)
(buffer/push-byte buf byte)))
buf)
(print (string/join (map escape allsyms) "|"))

View File

@@ -1,55 +0,0 @@
!define MULTIUSER_EXECUTIONLEVEL Highest
!define MULTIUSER_MUI
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!define MULTIUSER_INSTALLMODE_INSTDIR "janet"
!include "MultiUser.nsh"
!include "MUI2.nsh"
Name "Janet"
OutFile "janet-install.exe"
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "LICENSE"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "Janet" BfWSection
SetOutPath $INSTDIR
File "janet.exe"
WriteUninstaller "$INSTDIR\janet-uninstall.exe"
# Start Menu
CreateShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\janet.exe" "" ""
SectionEnd
Function .onInit
!insertmacro MULTIUSER_INIT
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${BfWSection} "The Janet programming language."
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section "Uninstall"
Delete "$INSTDIR\janet.exe"
Delete "$INSTDIR\janet-uninstall.exe"
RMDir "$INSTDIR"
SectionEnd
Function un.onInit
!insertmacro MULTIUSER_UNINIT
!insertmacro MUI_UNGETLANGUAGE
FunctionEnd

199
janet.1
View File

@@ -1,26 +1,134 @@
.TH JANET 1
.SH NAME
janet \- run the janet language abstract machine
janet \- run the Janet language abstract machine
.SH SYNOPSIS
.B janet
[\fB\-hvsrp\fR]
[\fB\-e\fR \fIJANET SOURCE\fR]
[\fB\-hvsrpnqk\fR]
[\fB\-e\fR \fISOURCE\fR]
[\fB\-l\fR \fIMODULE\fR]
[\fB\-m\fR \fIPATH\fR]
[\fB\-c\fR \fIMODULE JIMAGE\fR]
[\fB\-\-\fR]
.IR files ...
.BR script
.BR args ...
.SH DESCRIPTION
Janet is a functional and imperative programming language and bytecode interpreter.
It is a modern lisp, but lists are replaced by other data structures with better utility
and performance (arrays, tables, structs, tuples). The language also bridging bridging
Janet is a functional and imperative programming language and bytecode interpreter.
It is a Lisp-like language, but lists are replaced by other data structures
(arrays, tables, structs, tuples). The language also features bridging
to native code written in C, meta-programming with macros, and bytecode assembly.
There is a repl for trying out the language, as well as the ability to run script files.
This client program is separate from the core runtime, so janet could be embedded
into other programs. Try janet in your browser at https://janet-lang.org.
This client program is separate from the core runtime, so Janet could be embedded
into other programs. Try Janet in your browser at https://janet-lang.org.
Implemented in mostly standard C99, janet runs on Windows, Linux and macOS.
Implemented in mostly standard C99, Janet runs on Windows, Linux and macOS.
The few features that are not standard C99 (dynamic library loading, compiler
specific optimizations), are fairly straight forward. Janet can be easily ported to
specific optimizations), are fairly straight forward. Janet can be easily ported to
most new platforms.
.SH REPL KEY-BINDINGS
.TP 16
.BR Home
Move cursor to the beginning of input line.
.TP 16
.BR End
Move cursor to the end of input line.
.TP 16
.BR Left/Right
Move cursor in input line.
.TP 16
.BR Up/Down
Go backwards and forwards through history.
.TP 16
.BR Tab
Complete current symbol, or show available completions.
.TP 16
.BR Delete
Delete one character after the cursor.
.TP 16
.BR Backspace
Delete one character before the cursor.
.TP 16
.BR Ctrl\-A
Move cursor to the beginning of input line.
.TP 16
.BR Ctrl\-B
Move cursor one character to the left.
.TP 16
.BR Ctrl\-E
Move cursor to the end of input line.
.TP 16
.BR Ctrl\-F
Move cursor one character to the right.
.TP 16
.BR Ctrl\-H
Delete one character before the cursor.
.TP 16
.BR Ctrl\-K
Delete everything after the cursor on the input line.
.TP 16
.BR Ctrl\-L
Clear the screen.
.TP 16
.BR Ctrl\-N/Ctrl\-P
Go forwards and backwards through history.
.TP 16
.BR Ctrl\-U
Delete everything before the cursor on the input line.
.TP 16
.BR Ctrl\-W
Delete one word before the cursor.
.TP 16
.BR Ctrl\-G
Show documentation for the current symbol under the cursor.
.TP 16
.BR Alt\-B/Alt\-F
Move cursor backwards and forwards one word.
.TP 16
.BR Alt\-D
Delete one word after the cursor.
.TP 16
.BR Alt\-,
Go to earliest item in history.
.TP 16
.BR Alt\-.
Go to last item in history.
.LP
The repl keybindings are loosely based on a subset of GNU readline, although
Janet does not use GNU readline internally for the repl. It is a limited
substitute for GNU readline, and does not handle
utf-8 input or other mutlibyte input well.
To disable the built-in repl input handling, pass the \fB\-s\fR option to Janet, and
use a program like rlwrap with Janet to provide input.
For key bindings that operate on words, a word is considered to be a sequence
of characters that does not contain whitespace.
.SH DOCUMENTATION
For more complete API documentation, run a REPL (Read Eval Print Loop), and use the doc macro to
@@ -37,37 +145,80 @@ Shows the version text and exits immediately.
.TP
.BR \-s
Read raw input from stdin, such as from a pipe without printing a prompt.
Read raw input from stdin and forgo prompt history and other readline-like features.
.TP
.BR \-e\ code
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
arguments are executed before later ones.
.TP
.BR \-d
Enable debug mode. On all terminating signals as well the debug signal, this will
cause the debugger to come up in the REPL. Same as calling (setdyn :debug true) in a
default repl.
.TP
.BR \-n
Disable ANSI colors in the repl. Has no effect if no repl is run.
.TP
.BR \-r
Open a REPL (Read Eval Print Loop) after executing all sources. By default, if janet is called with no
Open a REPL (Read Eval Print Loop) after executing all sources. By default, if Janet is called with no
arguments, a REPL is opened.
.TP
.BR \-p
Turn on the persistent flag. By default, when janet is executing commands from a file and encounters an error,
it will immediately exit after printing the error message. In persistent mode, janet will keep executing commands
Turn on the persistent flag. By default, when Janet is executing commands from a file and encounters an error,
it will immediately exit after printing the error message. In persistent mode, Janet will keep executing commands
after an error. Persistent mode can be good for debugging and testing.
.TP
.BR \-e
Execute a string of janet source. Source code is executed in the order it is encountered, so earlier
arguments are executed before later ones.
.BR \-q
Hide the logo in the repl.
.TP
.BR \-k
Don't execute a script, only compile it to check for errors. Useful for linting scripts.
.TP
.BR \-m\ syspath
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
from a directory different than the default. The default is set when Janet is built, and defaults to
/usr/local/lib/janet on Linux/Posix, and C:/Janet/Library on Windows. This option supersedes JANET_PATH.
.TP
.BR \-c\ source\ output
Precompiles Janet source code into an image, a binary dump that can be efficiently loaded later.
Source should be a path to the Janet module to compile, and output should be the file path of
resulting image. Output should usually end with the .jimage extension.
.TP
.BR \-l\ lib
Import a Janet module before running a script or repl. Multiple files can be loaded
in this manner, and exports from each file will be made available to the script
or repl.
.TP
.BR \-\-
Stop parsing command line arguments. All arguments after this one will be considered file names.
Stop parsing command line arguments. All arguments after this one will be considered file names
and then arguments to the script.
.SH ENVIRONMENT
.B JANET_PATH
.RS
The location to look for janet libraries. This is the only environment variable janet needs to
find native and source code modules. If no JANET_PATH is set, janet will look in
/usr/local/lib/janet for modules.
To make janet search multiple locations, modify the module.paths
array in janet.
The location to look for Janet libraries. This is the only environment variable Janet needs to
find native and source code modules. If no JANET_PATH is set, Janet will look in
the default location set at compile time.
.RE
.B JANET_HASHSEED
.RS
To disable randomization of Janet's PRF on start up, one can set this variable. This can have the
effect of making programs deterministic that otherwise would depend on the random seed chosen at program start.
This variable does nothing in the default configuration of Janet, as PRF is disabled by default. Also, JANET_REDUCED_OS
cannot be defined for this variable to have an effect.
.RE
.SH AUTHOR

1
janet_win.rc Normal file
View File

@@ -0,0 +1 @@
IDI_MYICON ICON "assets\icon.ico"

1409
jpm Executable file

File diff suppressed because it is too large Load Diff

267
jpm.1 Normal file
View File

@@ -0,0 +1,267 @@
.TH JPM 1
.SH NAME
jpm \- the Janet Project Manager, a build tool for Janet
.SH SYNOPSIS
.B jpm
[\fB\-\-flag ...\fR]
[\fB\-\-option=value ...\fR]
.IR command
.IR args ...
.SH DESCRIPTION
jpm is the build tool that ships with a standard Janet install. It is
used for building Janet projects, installing dependencies, installing
projects, building native modules, and exporting your Janet project to a
standalone executable. Although not required for working with Janet, it
removes much of the boilerplate with installing dependencies and
building native modules. jpm requires only Janet to run, and uses git
to install dependencies (jpm will work without git installed).
.SH DOCUMENTATION
jpm has several subcommands, each used for managing either a single Janet project or
all Janet modules installed on the system. Global commands, those that manage modules
at the system level, do things like install and uninstall packages, as well as clear the cache.
More interesting are the local commands. For more information on jpm usage, see https://janet-lang.org/docs/index.html
.SH FLAGS
.TP
.BR \-\-nocolor
Disable color in the jpm debug repl.
.TP
.BR \-\-verbose
Print detailed messages of what jpm is doing, including compilation commands and other shell commands.
.TP
.BR \-\-test
If passed to jpm install, runs tests before installing. Will run tests recursively on dependencies.
.TP
.BR \-\-offline
Prevents jpm from going to network to get dependencies - all dependencies should be in the cache or this command will fail.
Use this flag with the deps and update-pkgs subcommands. This is not a surefire way to prevent a build script from accessing
the network, for example, a build script that invokes curl will still have network access.
.SH OPTIONS
.TP
.BR \-\-modpath=/some/path
Set the path to install modules to. Defaults to $JANET_MODPATH, $JANET_PATH, or (dyn :syspath) in that order. You most likely don't need this.
.TP
.BR \-\-headerpath=/some/path
Set the path the jpm will include when building C source code. This lets
you specify the location of janet.h and janetconf.h on your system. On a
normal install, this option is not needed.
.TP
.BR \-\-binpath=/some/path
Set the path that jpm will install scripts and standalone executables to. Executables
defined via declare-execuatble or scripts declared via declare-binscript will be installed
here when jpm install is run. Defaults to $JANET_BINPATH, or a reasonable default for the system.
See JANET_BINPATH for more.
.TP
.BR \-\-libpath=/some/path
Sets the path jpm will use to look for libjanet.a for building standalone executables. libjanet.so
is \fBnot\fR used for building native modules or standalone executables, only
for linking into applications that want to embed janet as a dynamic module.
Linking statically might be a better idea, even in that case. Defaults to
$JANET_LIBPATH, or a reasonable default. See JANET_LIBPATH for more.
.TP
.BR \-\-compiler=$CC
Sets the C compiler used for compiling native modules and standalone executables. Defaults
to cc.
.BR \-\-cpp\-compiler=$CXX
Sets the C++ compiler used for compiling native modules and standalone executables. Defaults
to c++..
.TP
.BR \-\-linker
Sets the linker used to create native modules and executables. Only used on windows, where
it defaults to link.exe.
.TP
.BR \-\-pkglist=https://github.com/janet-lang/pkgs.git
Sets the git repository for the package listing used to resolve shorthand package names.
.TP
.BR \-\-archiver=$AR
Sets the command used for creating static libraries, use for linking into the standalone executable.
Native modules are compiled twice, once a normal native module (shared object), and once as an
archive. Defaults to ar.
.SH COMMANDS
.TP
.BR help
Shows the usage text and exits immediately.
.TP
.BR build
Builds all artifacts specified in the project.janet file in the current directory. Artifacts will
be created in the ./build/ directory.
.TP
.BR install\ [\fBrepo...\fR]
When run with no arguments, installs all installable artifacts in the current project to
the current JANET_MODPATH for modules and JANET_BINPATH for executables and scripts. Can also
take an optional git repository URL and will install all artifacts in that repository instead.
When run with an argument, install does not need to be run from a jpm project directory. Will also
install multiple dependencies in one command.
.TP
.BR uninstall\ [\fBname...\fR]
Uninstall a project installed with install. uninstall expects the name of the project, not the
repository url, path to installed file or executable name. The name of the project must be specified
at the top of the project.janet file in the declare-project form. If no name is given, uninstalls
the current project if installed. Will also uninstall multiple packages in one command.
.TP
.BR clean
Remove all artifacts created by jpm. This just deletes the build folder.
.TP
.BR test
Runs jpm tests. jpm will run all janet source files in the test directory as tests. A test
is considered failing if it exits with a non-zero exit code.
.TP
.BR deps
Install all dependencies that this project requires recursively. jpm does not
resolve dependency issues, like conflicting versions of the same module are required, or
different modules with the same name. Dependencies are installed with git, so deps requires
git to be on the PATH.
.TP
.BR clear-cache
jpm caches git repositories that are needed to install modules from a remote
source in a global cache ($JANET_PATH/.cache). If these dependencies are out of
date or too large, clear-cache will remove the cache and jpm will rebuild it
when needed. clear-cache is a global command, so a project.janet is not
required.
.TP
.BR list-installed
List all installed packages in the current syspath.
.TP
.BR list-pkgs [\fBsearch\fR]
List all package aliases in the current package listing that contain the given search string.
If no search string is given, prints the entire listing.
.TP
.BR clear-manifest
jpm creates a manifest directory that contains a list of all installed files.
By deleting this directory, jpm will think that nothing is installed and will
try reinstalling everything on the jpm deps or jpm load-lockfile commands. Be careful with
this command, as it may leave extra files on your system and shouldn't be needed
most of the time in a healthy install.
.TP
.BR run\ [\fBrule\fR]
Run a given rule defined in project.janet. Project definitions files (project.janet) usually
contain a few artifact declarations, which set up rules that jpm can then resolve, or execute.
A project.janet can also create custom rules to create arbitrary files or run arbitrary code, much
like make. run will run a single rule or build a single file.
.TP
.BR rules
List all rules that can be run via run. This is useful for exploring rules in the project.
.TP
.BR rule-tree\ [\fBroot\fR] [\fdepth\fR]
Show rule dependency tree in a pretty format. Optionally provide a rule to use as the tree
root, as well as a max depth to print. By default, prints the full tree for all rules. This
can be quite long, so it is recommended to give a root rule.
.TP
.BR show-paths
Show all of the paths used when installing and building artifacts.
.TP
.BR update-pkgs
Update the package listing by installing the 'pkgs' package. Same as jpm install pkgs
.TP
.BR quickbin [\fBentry\fR] [\fBexecutable\fR]
Create a standalone, statically linked executable from a Janet source file that contains a main function.
The main function is the entry point of the program and will receive command line arguments
as function arguments. The entry file can import other modules, including native C modules, and
jpm will attempt to include the dependencies into the generated executable.
.TP
.BR debug-repl
Load the current project.janet file and start a repl in it's environment. This lets a user better
debug the project file, as well as run rules manually.
.TP
.BR make-lockfile\ [\fBfilename\fR]
Create a lockfile. A lockfile is a record that describes what dependencies were installed at the
time of the lockfile's creation, including exact versions. A lockfile can then be later used
to set up that environment on a different machine via load-lockfile. By default, the lockfile
is created at lockfile.jdn, although any path can be used.
.TP
.BR load-lockfile\ [\fBfilename\fR]
Install dependencies from a lockfile previously created with make-lockfile. By default, will look
for a lockfile at lockfile.jdn, although any path can be used.
.SH ENVIRONMENT
.B JANET_PATH
.RS
The location to look for Janet libraries. This is the only environment variable Janet needs to
find native and source code modules. If no JANET_PATH is set, Janet will look in
the default location set at compile time, which can be determined with (dyn :syspath)
.RE
.B JANET_MODPATH
.RS
The location that jpm will use to install libraries to. Defaults to JANET_PATH, but you could
set this to a different directory if you want to. Doing so would let you import Janet modules
on the normal system path (JANET_PATH or (dyn :syspath)), but install to a different directory. It is also a more reliable way to install
This variable is overwritten by the --modpath=/some/path if it is provided.
.RE
.B JANET_HEADERPATH
.RS
The location that jpm will look for janet header files (janet.h and janetconf.h) that are used
to build native modules and standalone executables. If janet.h and janetconf.h are available as
default includes on your system, this value is not required. If not provided, will default to
<jpm script location>/../include/janet. The --headerpath=/some/path option will override this
variable.
.RE
.B JANET_LIBPATH
.RS
Similar to JANET_HEADERPATH, this path is where jpm will look for
libjanet.a for creating standalong executables. This does not need to be
set on a normal install.
If not provided, this will default to <jpm script location>/../lib.
The --libpath=/some/path option will override this variable.
.RE
.B JANET_BINPATH
.RS
The directory where jpm will install binary scripts and executables to.
Defaults to
(dyn :syspath)/bin
The --binpath=/some/path will override this variable.
.RE
.B JANET_PKGLIST
.RS
The git repository URL that contains a listing of packages. This allows installing packages with shortnames, which
is mostly a convenience. However, package dependencies can use short names, package listings
can be used to choose a particular set of dependency versions for a whole project.
.B JANET_GIT
.RS
An optional path to a git executable to use to clone git dependencies. By default, uses "git" on the current $PATH. You shouldn't need to set this
if you have a normal install of git.
.SH AUTHOR
Written by Calvin Rose <calsrose@gmail.com>

262
meson.build Normal file
View File

@@ -0,0 +1,262 @@
# Copyright (c) 2020 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
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
project('janet', 'c',
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.12.1')
# Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
header_path = join_paths(get_option('prefix'), get_option('includedir'), 'janet')
# Link math library on all systems
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
dl_dep = cc.find_library('dl', required : false)
thread_dep = dependency('threads')
# Link options
if build_machine.system() != 'windows'
add_project_link_arguments('-rdynamic', language : 'c')
endif
# Generate custom janetconf.h
conf = configuration_data()
version_parts = meson.project_version().split('.')
last_parts = version_parts[2].split('-')
if last_parts.length() > 1
conf.set_quoted('JANET_VERSION_EXTRA', '-' + last_parts[1])
else
conf.set_quoted('JANET_VERSION_EXTRA', '')
endif
conf.set('JANET_VERSION_MAJOR', version_parts[0].to_int())
conf.set('JANET_VERSION_MINOR', version_parts[1].to_int())
conf.set('JANET_VERSION_PATCH', last_parts[0].to_int())
conf.set_quoted('JANET_VERSION', meson.project_version())
# Use options
conf.set_quoted('JANET_BUILD', get_option('git_hash'))
conf.set('JANET_NO_NANBOX', not get_option('nanbox'))
conf.set('JANET_SINGLE_THREADED', get_option('single_threaded'))
conf.set('JANET_NO_DYNAMIC_MODULES', not get_option('dynamic_modules'))
conf.set('JANET_NO_DOCSTRINGS', not get_option('docstrings'))
conf.set('JANET_NO_SOURCEMAPS', not get_option('sourcemaps'))
conf.set('JANET_NO_ASSEMBLER', not get_option('assembler'))
conf.set('JANET_NO_PEG', not get_option('peg'))
conf.set('JANET_NO_NET', not get_option('net'))
conf.set('JANET_REDUCED_OS', get_option('reduced_os'))
conf.set('JANET_NO_TYPED_ARRAY', not get_option('typed_array'))
conf.set('JANET_NO_INT_TYPES', not get_option('int_types'))
conf.set('JANET_PRF', get_option('prf'))
conf.set('JANET_RECURSION_GUARD', get_option('recursion_guard'))
conf.set('JANET_MAX_PROTO_DEPTH', get_option('max_proto_depth'))
conf.set('JANET_MAX_MACRO_EXPAND', get_option('max_macro_expand'))
conf.set('JANET_STACK_MAX', get_option('stack_max'))
conf.set('JANET_NO_UMASK', not get_option('umask'))
conf.set('JANET_NO_REALPATH', not get_option('realpath'))
conf.set('JANET_NO_PROCESSES', not get_option('processes'))
conf.set('JANET_SIMPLE_GETLINE', get_option('simple_getline'))
if get_option('os_name') != ''
conf.set('JANET_OS_NAME', get_option('os_name'))
endif
if get_option('arch_name') != ''
conf.set('JANET_ARCH_NAME', get_option('arch_name'))
endif
jconf = configure_file(output : 'janetconf.h',
configuration : conf)
# Include directories
incdir = include_directories(['src/include', '.'])
# Order is important here, as some headers
# depend on other headers for the amalg target
core_headers = [
'src/core/features.h',
'src/core/util.h',
'src/core/state.h',
'src/core/gc.h',
'src/core/vector.h',
'src/core/fiber.h',
'src/core/regalloc.h',
'src/core/compile.h',
'src/core/emit.h',
'src/core/symcache.h'
]
core_src = [
'src/core/abstract.c',
'src/core/array.c',
'src/core/asm.c',
'src/core/buffer.c',
'src/core/bytecode.c',
'src/core/capi.c',
'src/core/cfuns.c',
'src/core/compile.c',
'src/core/corelib.c',
'src/core/debug.c',
'src/core/emit.c',
'src/core/fiber.c',
'src/core/gc.c',
'src/core/inttypes.c',
'src/core/io.c',
'src/core/marsh.c',
'src/core/math.c',
'src/core/net.c',
'src/core/os.c',
'src/core/parse.c',
'src/core/peg.c',
'src/core/pp.c',
'src/core/regalloc.c',
'src/core/run.c',
'src/core/specials.c',
'src/core/string.c',
'src/core/strtod.c',
'src/core/struct.c',
'src/core/symcache.c',
'src/core/table.c',
'src/core/thread.c',
'src/core/tuple.c',
'src/core/typedarray.c',
'src/core/util.c',
'src/core/value.c',
'src/core/vector.c',
'src/core/vm.c',
'src/core/wrap.c'
]
boot_src = [
'src/boot/array_test.c',
'src/boot/boot.c',
'src/boot/buffer_test.c',
'src/boot/number_test.c',
'src/boot/system_test.c',
'src/boot/table_test.c',
]
mainclient_src = [
'src/mainclient/shell.c'
]
# Build boot binary
janet_boot = executable('janet-boot', core_src, boot_src,
include_directories : incdir,
c_args : '-DJANET_BOOTSTRAP',
dependencies : [m_dep, dl_dep, thread_dep],
native : true)
# Build janet.c
janetc = custom_target('janetc',
input : [janet_boot],
output : 'janet.c',
capture : true,
command : [
janet_boot, meson.current_source_dir(),
'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path
])
libjanet = library('janet', janetc,
include_directories : incdir,
dependencies : [m_dep, dl_dep, thread_dep],
version: meson.project_version(),
soversion: version_parts[0] + '.' + version_parts[1],
install : true)
# Extra c flags - adding -fvisibility=hidden matches the Makefile and
# shaves off about 10k on linux x64, likely similar on other platforms.
if cc.has_argument('-fvisibility=hidden')
extra_cflags = ['-fvisibility=hidden']
else
extra_cflags = []
endif
janet_mainclient = executable('janet', janetc, mainclient_src,
include_directories : incdir,
dependencies : [m_dep, dl_dep, thread_dep],
c_args : extra_cflags,
install : true)
if meson.is_cross_build()
native_cc = meson.get_compiler('c', native: true)
if native_cc.has_argument('-fvisibility=hidden')
extra_native_cflags = ['-fvisibility=hidden']
else
extra_native_cflags = []
endif
janet_nativeclient = executable('janet-native', janetc, mainclient_src,
include_directories : incdir,
dependencies : [m_dep, dl_dep, thread_dep],
c_args : extra_native_cflags,
native : true)
else
janet_nativeclient = janet_mainclient
endif
# Documentation
docs = custom_target('docs',
input : ['tools/gendoc.janet'],
output : ['doc.html'],
capture : true,
command : [janet_nativeclient, '@INPUT@'])
# Tests
test_files = [
'test/suite0000.janet',
'test/suite0001.janet',
'test/suite0002.janet',
'test/suite0003.janet',
'test/suite0004.janet',
'test/suite0005.janet',
'test/suite0006.janet',
'test/suite0007.janet',
'test/suite0008.janet',
'test/suite0009.janet',
'test/suite0010.janet'
]
foreach t : test_files
test(t, janet_nativeclient, args : files([t]), workdir : meson.current_source_dir())
endforeach
# Repl
run_target('repl', command : [janet_nativeclient])
# For use as meson subproject (wrap)
janet_dep = declare_dependency(include_directories : incdir,
link_with : libjanet)
# pkgconfig
pkg = import('pkgconfig')
pkg.generate(libjanet,
description: 'Library for the Janet programming language.')
# Installation
install_man('janet.1')
install_headers(['src/include/janet.h', jconf], subdir: 'janet')
install_data(sources : ['tools/.keep'], install_dir : join_paths(get_option('libdir'), 'janet'))
if get_option('peg') and not get_option('reduced_os') and get_option('processes')
install_man('jpm.1')
patched_jpm = custom_target('patched-jpm',
input : ['tools/patch-jpm.janet', 'jpm'],
install : true,
install_dir : get_option('bindir'),
build_by_default : true,
output : ['jpm'],
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@',
'--binpath=' + join_paths(get_option('prefix'), get_option('bindir')),
'--libpath=' + join_paths(get_option('prefix'), get_option('libdir')),
'--headerpath=' + join_paths(get_option('prefix'), get_option('includedir'))])
endif

26
meson_options.txt Normal file
View File

@@ -0,0 +1,26 @@
option('git_hash', type : 'string', value : 'meson')
option('single_threaded', type : 'boolean', value : false)
option('nanbox', type : 'boolean', value : true)
option('dynamic_modules', type : 'boolean', value : true)
option('docstrings', type : 'boolean', value : true)
option('sourcemaps', type : 'boolean', value : true)
option('reduced_os', type : 'boolean', value : false)
option('assembler', type : 'boolean', value : true)
option('peg', type : 'boolean', value : true)
option('typed_array', type : 'boolean', value : true)
option('int_types', type : 'boolean', value : true)
option('prf', type : 'boolean', value : false)
option('net', type : 'boolean', value : true)
option('processes', type : 'boolean', value : true)
option('umask', type : 'boolean', value : true)
option('realpath', type : 'boolean', value : true)
option('simple_getline', type : 'boolean', value : false)
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200)
option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7fffffff)
option('arch_name', type : 'string', value: '')
option('os_name', type : 'string', value: '')

View File

@@ -1,25 +0,0 @@
@rem Generated batch script, run in 'Visual Studio Developer Prompt'
@rem
@echo off
cl /nologo /I..\..\src\include /c /O2 /W3 json.c
@if errorlevel 1 goto :BUILDFAIL
link /nologo /dll ..\..\janet.lib /out:json.dll *.obj
if errorlevel 1 goto :BUILDFAIL
@echo .
@echo ======
@echo Build Succeeded.
@echo =====
exit /b 0
:BUILDFAIL
@echo .
@echo =====
@echo BUILD FAILED. See Output For Details.
@echo =====
@echo .
exit /b 1

View File

@@ -1,605 +0,0 @@
/*
* Copyright (c) 2018 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include <stdlib.h>
#include <errno.h>
/*****************/
/* JSON Decoding */
/*****************/
/* Check if a character is whitespace */
static int white(uint8_t c) {
return c == '\t' || c == '\n' || c == ' ' || c == '\r';
}
/* Skip whitespace */
static void skipwhite(const char **p) {
const char *cp = *p;
for (;;) {
if (white(*cp))
cp++;
else
break;
}
*p = cp;
}
/* Get a hex digit value */
static int hexdig(char dig) {
if (dig >= '0' && dig <= '9')
return dig - '0';
if (dig >= 'a' && dig <= 'f')
return 10 + dig - 'a';
if (dig >= 'A' && dig <= 'F')
return 10 + dig - 'A';
return -1;
}
/* Read the hex value for a unicode escape */
static const char *decode_utf16_escape(const char *p, uint32_t *outpoint) {
if (!p[0] || !p[1] || !p[2] || !p[3])
return "unexpected end of source";
int d1 = hexdig(p[0]);
int d2 = hexdig(p[1]);
int d3 = hexdig(p[2]);
int d4 = hexdig(p[3]);
if (d1 < 0 || d2 < 0 || d3 < 0 || d4 < 0)
return "invalid hex digit";
*outpoint = d4 | (d3 << 4) | (d2 << 8) | (d1 << 12);
return NULL;
}
/* Parse a string. Also handles the conversion of utf-16 to
* utf-8. */
static const char *decode_string(const char **p, Janet *out) {
JanetBuffer *buffer = janet_buffer(0);
const char *cp = *p;
while (*cp != '"') {
uint8_t b = (uint8_t) *cp;
if (b < 32) return "invalid character in string";
if (b == '\\') {
cp++;
switch(*cp) {
default:
return "unknown string escape";
case 'b':
b = '\b';
break;
case 'f':
b = '\f';
break;
case 'n':
b = '\n';
break;
case 'r':
b = '\r';
break;
case 't':
b = '\t';
break;
case '"':
b = '"';
break;
case '\\':
b = '\\';
break;
case 'u':
{
/* Get codepoint and check for surrogate pair */
uint32_t codepoint;
const char *err = decode_utf16_escape(cp + 1, &codepoint);
if (err) return err;
if (codepoint >= 0xDC00 && codepoint <= 0xDFFF) {
return "unexpected utf-16 low surrogate";
} else if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
if (cp[5] != '\\') return "expected utf-16 low surrogate pair";
if (cp[6] != 'u') return "expected utf-16 low surrogate pair";
uint32_t lowsur;
const char *err = decode_utf16_escape(cp + 7, &lowsur);
if (err) return err;
if (lowsur < 0xDC00 || lowsur > 0xDFFF)
return "expected utf-16 low surrogate pair";
codepoint = ((codepoint - 0xD800) << 10) +
(lowsur - 0xDC00) + 0x10000;
cp += 11;
} else {
cp += 5;
}
/* Write codepoint */
if (codepoint <= 0x7F) {
janet_buffer_push_u8(buffer, codepoint);
} else if (codepoint <= 0x7FF) {
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x1F) | 0xC0);
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
} else if (codepoint <= 0xFFFF) {
janet_buffer_push_u8(buffer, ((codepoint >> 12) & 0x0F) | 0xE0);
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x3F) | 0x80);
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
} else {
janet_buffer_push_u8(buffer, ((codepoint >> 18) & 0x07) | 0xF0);
janet_buffer_push_u8(buffer, ((codepoint >> 12) & 0x3F) | 0x80);
janet_buffer_push_u8(buffer, ((codepoint >> 6) & 0x3F) | 0x80);
janet_buffer_push_u8(buffer, ((codepoint >> 0) & 0x3F) | 0x80);
}
}
continue;
}
}
janet_buffer_push_u8(buffer, b);
cp++;
}
*out = janet_stringv(buffer->data, buffer->count);
*p = cp + 1;
return NULL;
}
static const char *decode_one(const char **p, Janet *out, int depth) {
/* Prevent stack overflow */
if (depth > JANET_RECURSION_GUARD) goto recurdepth;
/* Skip leading whitepspace */
skipwhite(p);
/* Main switch */
switch (**p) {
default:
goto badchar;
case '\0':
goto eos;
/* Numbers */
case '-': case '0': case '1' : case '2': case '3' : case '4':
case '5': case '6': case '7' : case '8': case '9':
{
errno = 0;
char *end = NULL;
double x = strtod(*p, &end);
if (end == *p) goto badnum;
*p = end;
*out = janet_wrap_real(x);
break;
}
/* false, null, true */
case 'f':
{
const char *cp = *p;
if (cp[1] != 'a' || cp[2] != 'l' || cp[3] != 's' || cp[4] != 'e')
goto badident;
*out = janet_wrap_false();
*p = cp + 5;
break;
}
case 'n':
{
const char *cp = *p;
if (cp[1] != 'u' || cp[2] != 'l' || cp[3] != 'l')
goto badident;
*out = janet_wrap_nil();
*p = cp + 4;
break;
}
case 't':
{
const char *cp = *p;
if (cp[1] != 'r' || cp[2] != 'u' || cp[3] != 'e')
goto badident;
*out = janet_wrap_true();
*p = cp + 4;
break;
}
/* String */
case '"':
{
const char *cp = *p + 1;
const char *start = cp;
while (*cp >= 32 && *cp != '"' && *cp != '\\')
cp++;
/* Only use a buffer for strings with escapes, else just copy
* memory from source */
if (*cp == '\\') {
*p = *p + 1;
const char *err = decode_string(p, out);
if (err) return err;
break;
}
if (*cp != '"') goto badchar;
*p = cp + 1;
*out = janet_stringv((const uint8_t *)start, cp - start);
break;
}
/* Array */
case '[':
{
*p = *p + 1;
JanetArray *array = janet_array(0);
const char *err;
Janet subval;
skipwhite(p);
while (**p != ']') {
err = decode_one(p, &subval, depth + 1);
if (err) return err;
janet_array_push(array, subval);
skipwhite(p);
if (**p == ']') break;
if (**p != ',') goto wantcomma;
*p = *p + 1;
}
*p = *p + 1;
*out = janet_wrap_array(array);
}
break;
/* Object */
case '{':
{
*p = *p + 1;
JanetTable *table = janet_table(0);
const char *err;
Janet subkey, subval;
skipwhite(p);
while (**p != '}') {
skipwhite(p);
if (**p != '"') goto wantstring;
err = decode_one(p, &subkey, depth + 1);
if (err) return err;
skipwhite(p);
if (**p != ':') goto wantcolon;
*p = *p + 1;
err = decode_one(p, &subval, depth + 1);
if (err) return err;
janet_table_put(table, subkey, subval);
skipwhite(p);
if (**p == '}') break;
if (**p != ',') goto wantcomma;
*p = *p + 1;
}
*p = *p + 1;
*out = janet_wrap_table(table);
break;
}
}
/* Good return */
return NULL;
/* Errors */
recurdepth:
return "recured too deeply";
eos:
return "unexpected end of source";
badident:
return "bad identifier";
badnum:
return "bad number";
wantcomma:
return "expected comma";
wantcolon:
return "expected colon";
badchar:
return "unexpected character";
wantstring:
return "expected json string";
}
static int json_decode(JanetArgs args) {
Janet ret;
JANET_FIXARITY(args, 1);
const char *err;
const char *start;
const char *p;
if (janet_checktype(args.v[0], JANET_BUFFER)) {
JanetBuffer *buffer = janet_unwrap_buffer(args.v[0]);
/* Ensure 0 padded */
janet_buffer_push_u8(buffer, 0);
start = p = (const char *)buffer->data;
err = decode_one(&p, &ret, 0);
buffer->count--;
} else {
const uint8_t *bytes;
int32_t len;
JANET_ARG_BYTES(bytes, len, args, 0);
start = p = (const char *)bytes;
err = decode_one(&p, &ret, 0);
}
/* Check trailing values */
if (!err) {
skipwhite(&p);
if (*p)
err = "unexpected extra token";
}
if (err) {
JANET_THROWV(args, janet_wrap_string(janet_formatc(
"decode error at postion %d: %s",
p - start,
err)));
}
JANET_RETURN(args, ret);
}
/*****************/
/* JSON Encoding */
/*****************/
typedef struct {
JanetBuffer *buffer;
int32_t indent;
const uint8_t *tab;
const uint8_t *newline;
int32_t tablen;
int32_t newlinelen;
} Encoder;
static const char *encode_newline(Encoder *e) {
if (janet_buffer_push_bytes(e->buffer, e->newline, e->newlinelen))
return "buffer overflow";
/* Skip loop if no tab string */
if (e->tablen) {
for (int32_t i = 0; i < e->indent; i++)
if (janet_buffer_push_bytes(e->buffer, e->tab, e->tablen))
return "buffer overflow";
}
return NULL;
}
static const char *encode_one(Encoder *e, Janet x, int depth) {
switch(janet_type(x)) {
default:
goto badtype;
case JANET_NIL:
{
if (janet_buffer_push_cstring(e->buffer, "null"))
goto overflow;
}
break;
case JANET_FALSE:
{
if (janet_buffer_push_cstring(e->buffer, "false"))
goto overflow;
}
break;
case JANET_TRUE:
{
if (janet_buffer_push_cstring(e->buffer, "true"))
goto overflow;
}
break;
case JANET_INTEGER:
{
char cbuf[20];
sprintf(cbuf, "%d", janet_unwrap_integer(x));
if (janet_buffer_push_cstring(e->buffer, cbuf))
goto overflow;
}
break;
case JANET_REAL:
{
char cbuf[25];
sprintf(cbuf, "%.17g", janet_unwrap_real(x));
if (janet_buffer_push_cstring(e->buffer, cbuf))
goto overflow;
}
break;
case JANET_STRING:
case JANET_SYMBOL:
case JANET_BUFFER:
{
const uint8_t *bytes;
const uint8_t *c;
const uint8_t *end;
int32_t len;
janet_bytes_view(x, &bytes, &len);
if (janet_buffer_push_u8(e->buffer, '"')) goto overflow;
c = bytes;
end = bytes + len;
while (c < end) {
/* get codepoint */
uint32_t codepoint;
if (*c < 0x80) {
/* one byte */
codepoint = *c++;
} else if (*c < 0xE0) {
/* two bytes */
if (c + 2 > end) goto overflow;
codepoint = ((c[0] & 0x1F) << 6) |
(c[1] & 0x3F);
c += 2;
} else if (*c < 0xF0) {
/* three bytes */
if (c + 3 > end) goto overflow;
codepoint = ((c[0] & 0x0F) << 12) |
((c[1] & 0x3F) << 6) |
(c[2] & 0x3F);
c += 3;
} else if (*c < 0xF8) {
/* four bytes */
if (c + 4 > end) goto overflow;
codepoint = ((c[0] & 0x07) << 18) |
((c[1] & 0x3F) << 12) |
((c[3] & 0x3F) << 6) |
(c[3] & 0x3F);
c += 4;
} else {
/* invalid */
goto invalidutf8;
}
/* write codepoint */
if (codepoint > 0x1F && codepoint < 0x80) {
/* Normal, no escape */
if (codepoint == '\\' || codepoint == '"')
if (janet_buffer_push_u8(e->buffer, '\\'))
goto overflow;
if (janet_buffer_push_u8(e->buffer, (uint8_t) codepoint))
goto overflow;
} else if (codepoint < 0x10000) {
/* One unicode escape */
uint8_t buf[6];
buf[0] = '\\';
buf[1] = 'u';
buf[2] = (codepoint >> 12) & 0xF;
buf[3] = (codepoint >> 8) & 0xF;
buf[4] = (codepoint >> 4) & 0xF;
buf[5] = codepoint & 0xF;
if (janet_buffer_push_bytes(e->buffer, buf, sizeof(buf)))
goto overflow;
} else {
/* Two unicode escapes (surrogate pair) */
uint32_t hi, lo;
uint8_t buf[12];
hi = ((codepoint - 0x10000) >> 10) + 0xD800;
lo = ((codepoint - 0x10000) & 0x3FF) + 0xDC00;
buf[0] = '\\';
buf[1] = 'u';
buf[2] = (hi >> 12) & 0xF;
buf[3] = (hi >> 8) & 0xF;
buf[4] = (hi >> 4) & 0xF;
buf[5] = hi & 0xF;
buf[6] = '\\';
buf[7] = 'u';
buf[8] = (lo >> 12) & 0xF;
buf[9] = (lo >> 8) & 0xF;
buf[10] = (lo >> 4) & 0xF;
buf[11] = lo & 0xF;
if (janet_buffer_push_bytes(e->buffer, buf, sizeof(buf)))
goto overflow;
}
}
if (janet_buffer_push_u8(e->buffer, '"')) goto overflow;
}
break;
case JANET_TUPLE:
case JANET_ARRAY:
{
const char *err;
const Janet *items;
int32_t len;
janet_indexed_view(x, &items, &len);
if (janet_buffer_push_u8(e->buffer, '[')) goto overflow;
e->indent++;
for (int32_t i = 0; i < len; i++) {
if ((err = encode_newline(e))) return err;
if ((err = encode_one(e, items[i], depth + 1)))
return err;
if (janet_buffer_push_u8(e->buffer, ','))
goto overflow;
}
e->indent--;
if (e->buffer->data[e->buffer->count - 1] == ',') {
e->buffer->count--;
if ((err = encode_newline(e))) return err;
}
if (janet_buffer_push_u8(e->buffer, ']')) goto overflow;
}
break;
case JANET_TABLE:
case JANET_STRUCT:
{
const char *err;
const JanetKV *kvs;
int32_t count, capacity;
janet_dictionary_view(x, &kvs, &count, &capacity);
if (janet_buffer_push_u8(e->buffer, '{')) goto overflow;
e->indent++;
for (int32_t i = 0; i < capacity; i++) {
if (janet_checktype(kvs[i].key, JANET_NIL))
continue;
if (!janet_checktype(kvs[i].key, JANET_STRING))
return "only strings keys are allowed in objects";
if ((err = encode_newline(e))) return err;
if ((err = encode_one(e, kvs[i].key, depth + 1)))
return err;
const char *sep = e->tablen ? ": " : ":";
if (janet_buffer_push_cstring(e->buffer, sep))
goto overflow;
if ((err = encode_one(e, kvs[i].value, depth + 1)))
return err;
if (janet_buffer_push_u8(e->buffer, ','))
goto overflow;
}
e->indent--;
if (e->buffer->data[e->buffer->count - 1] == ',') {
e->buffer->count--;
if ((err = encode_newline(e))) return err;
}
if (janet_buffer_push_u8(e->buffer, '}')) goto overflow;
}
break;
}
return NULL;
/* Errors */
overflow:
return "buffer overflow";
badtype:
return "type not supported";
invalidutf8:
return "string contains invalid utf-8";
}
static int json_encode(JanetArgs args) {
JANET_MINARITY(args, 1);
JANET_MAXARITY(args, 3);
Encoder e;
e.indent = 0;
e.buffer = janet_buffer(10);
e.tab = NULL;
e.newline = NULL;
e.tablen = 0;
e.newlinelen = 0;
if (args.n >= 2) {
JANET_ARG_BYTES(e.tab, e.tablen, args, 1);
if (args.n >= 3) {
JANET_ARG_BYTES(e.newline, e.newlinelen, args, 2);
} else {
e.newline = (const uint8_t *)"\r\n";
e.newlinelen = 2;
}
}
const char *err = encode_one(&e, args.v[0], 0);
if (err) JANET_THROW(args, err);
JANET_RETURN_BUFFER(args, e.buffer);
}
/****************/
/* Module Entry */
/****************/
static const JanetReg cfuns[] = {
{"encode", json_encode,
"(json/encode x [,tab [,newline]])\n\n"
"Encodes a janet value in JSON (utf-8)."
},
{"decode", json_decode,
"(json/decode json-source)\n\n"
"Returns a janet object after parsing JSON."
},
{NULL, NULL, NULL}
};
JANET_MODULE_ENTRY(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, "json", cfuns);
return 0;
}

View File

@@ -1,62 +0,0 @@
# Created by https://www.gitignore.io/api/c
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# End of https://www.gitignore.io/api/c
sqlite3.c
sqlite3.h
sqlite-autoconf-3230100

View File

@@ -1,60 +0,0 @@
# Copyright (c) 2018 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
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
CFLAGS=-std=c99 -Wall -Wextra -I../../src/include -O2 -shared -fpic \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_OMIT_LOAD_EXTENSION
TARGET=sqlite3.so
# MacOS specifics
UNAME:=$(shell uname -s)
ifeq ($(UNAME), Darwin)
CFLAGS:=$(CFLAGS) -undefined dynamic_lookup
endif
# Default target
all: $(TARGET)
OBJECTS:=main.o sqlite3.o
$(TARGET): $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^
sqlite-autoconf-3230100/sqlite3.%:
curl https://www.sqlite.org/2018/sqlite-autoconf-3230100.tar.gz | tar -xvz
sqlite3.c: sqlite-autoconf-3230100/sqlite3.c
cp $< $@
sqlite3.h: sqlite-autoconf-3230100/sqlite3.h
cp $< $@
%.o: %.c sqlite3.h
$(CC) $(CFLAGS) -c $<
clean:
rm -rf sqlite-autoconf-3230100
rm *.o
rm sqlite3.c
rm sqlite3.h
rm $(TARGET)
install:
cp $(TARGET) $(DST_PATH)
.PHONY: clean all

View File

@@ -1,428 +0,0 @@
/*
* Copyright (c) 2018 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "sqlite3.h"
#include <janet/janet.h>
#define FLAG_CLOSED 1
#define MSG_DB_CLOSED "database already closed"
typedef struct {
sqlite3* handle;
int flags;
} Db;
/* Close a db, noop if already closed */
static void closedb(Db *db) {
if (!(db->flags & FLAG_CLOSED)) {
db->flags |= FLAG_CLOSED;
sqlite3_close_v2(db->handle);
}
}
/* Called to garbage collect a sqlite3 connection */
static int gcsqlite(void *p, size_t s) {
(void) s;
Db *db = (Db *)p;
closedb(db);
return 0;
}
static const JanetAbstractType sql_conn_type = {
":sqlite3.connection",
gcsqlite,
NULL,
};
/* Open a new database connection */
static int sql_open(JanetArgs args) {
sqlite3 *conn;
const uint8_t *filename;
int status;
JANET_FIXARITY(args, 1);
JANET_ARG_STRING(filename, args, 0);
status = sqlite3_open((const char *)filename, &conn);
if (status == SQLITE_OK) {
Db *db = (Db *) janet_abstract(&sql_conn_type, sizeof(Db));
db->handle = conn;
db->flags = 0;
JANET_RETURN_ABSTRACT(args, db);
} else {
const char *err = sqlite3_errmsg(conn);
JANET_THROW(args, err);
}
}
/* Close a database connection */
static int sql_close(JanetArgs args) {
Db *db;
JANET_FIXARITY(args, 1);
JANET_ARG_ABSTRACT(db, args, 0, &sql_conn_type);
closedb(db);
JANET_RETURN_NIL(args);
}
/* Check for embedded NULL bytes */
static int has_null(const uint8_t *str, int32_t len) {
while (len--) {
if (!str[len])
return 1;
}
return 0;
}
/* Bind a single parameter */
static const char *bind1(sqlite3_stmt *stmt, int index, Janet value) {
int res;
switch (janet_type(value)) {
default:
return "invalid sql value";
case JANET_NIL:
res = sqlite3_bind_null(stmt, index);
break;
case JANET_FALSE:
res = sqlite3_bind_int(stmt, index, 0);
break;
case JANET_TRUE:
res = sqlite3_bind_int(stmt, index, 1);
break;
case JANET_REAL:
res = sqlite3_bind_double(stmt, index, janet_unwrap_real(value));
break;
case JANET_INTEGER:
res = sqlite3_bind_int64(stmt, index, janet_unwrap_integer(value));
break;
case JANET_STRING:
case JANET_SYMBOL:
{
const uint8_t *str = janet_unwrap_string(value);
int32_t len = janet_string_length(str);
if (has_null(str, len)) {
return "cannot have embedded nulls in text values";
} else {
res = sqlite3_bind_text(stmt, index, (const char *)str, len + 1, SQLITE_STATIC);
}
}
break;
case JANET_BUFFER:
{
JanetBuffer *buffer = janet_unwrap_buffer(value);
res = sqlite3_bind_blob(stmt, index, buffer->data, buffer->count, SQLITE_STATIC);
}
break;
}
if (res != SQLITE_OK) {
sqlite3 *db = sqlite3_db_handle(stmt);
return sqlite3_errmsg(db);
}
return NULL;
}
/* Bind many parameters */
static const char *bindmany(sqlite3_stmt *stmt, Janet params) {
/* parameters */
const Janet *seq;
const JanetKV *kvs;
int32_t len, cap;
int limitindex = sqlite3_bind_parameter_count(stmt);
if (janet_indexed_view(params, &seq, &len)) {
if (len > limitindex + 1) {
return "invalid index in sql parameters";
}
for (int i = 0; i < len; i++) {
const char *err = bind1(stmt, i + 1, seq[i]);
if (err) {
return err;
}
}
} else if (janet_dictionary_view(params, &kvs, &len, &cap)) {
for (int i = 0; i < cap; i++) {
int index = 0;
switch (janet_type(kvs[i].key)) {
default:
/* Will fail */
break;
case JANET_NIL:
/* Will skip as nil keys indicate empty hash table slot */
continue;
case JANET_INTEGER:
index = janet_unwrap_integer(kvs[i].key);
break;
case JANET_STRING:
case JANET_SYMBOL:
{
const uint8_t *s = janet_unwrap_string(kvs[i].key);
index = sqlite3_bind_parameter_index(
stmt,
(const char *)s);
}
break;
}
if (index <= 0 || index > limitindex) {
return "invalid index in sql parameters";
}
const char *err = bind1(stmt, index, kvs[i].value);
if (err) {
return err;
}
}
} else {
return "invalid type for sql parameters";
}
return NULL;
}
/* Execute a statement but don't collect results */
static const char *execute(sqlite3_stmt *stmt) {
int status;
const char *ret = NULL;
do {
status = sqlite3_step(stmt);
} while (status == SQLITE_ROW);
/* Check for errors */
if (status != SQLITE_DONE) {
sqlite3 *db = sqlite3_db_handle(stmt);
ret = sqlite3_errmsg(db);
}
return ret;
}
/* Execute and return values from prepared statement */
static const char *execute_collect(sqlite3_stmt *stmt, JanetArray *rows) {
/* Count number of columns in result */
int ncol = sqlite3_column_count(stmt);
int status;
const char *ret = NULL;
/* Get column names */
Janet *tupstart = janet_tuple_begin(ncol);
for (int i = 0; i < ncol; i++) {
tupstart[i] = janet_cstringv(sqlite3_column_name(stmt, i));
}
const Janet *colnames = janet_tuple_end(tupstart);
do {
status = sqlite3_step(stmt);
if (status == SQLITE_ROW) {
JanetKV *row = janet_struct_begin(ncol);
for (int i = 0; i < ncol; i++) {
int t = sqlite3_column_type(stmt, i);
Janet value;
switch (t) {
case SQLITE_NULL:
value = janet_wrap_nil();
break;
case SQLITE_INTEGER:
value = janet_wrap_integer(sqlite3_column_int(stmt, i));
break;
case SQLITE_FLOAT:
value = janet_wrap_real(sqlite3_column_double(stmt, i));
break;
case SQLITE_TEXT:
{
int nbytes = sqlite3_column_bytes(stmt, i);
uint8_t *str = janet_string_begin(nbytes);
memcpy(str, sqlite3_column_text(stmt, i), nbytes);
value = janet_wrap_string(janet_string_end(str));
}
break;
case SQLITE_BLOB:
{
int nbytes = sqlite3_column_bytes(stmt, i);
JanetBuffer *b = janet_buffer(nbytes);
memcpy(b->data, sqlite3_column_blob(stmt, i), nbytes);
b->count = nbytes;
value = janet_wrap_buffer(b);
}
break;
}
janet_struct_put(row, colnames[i], value);
}
janet_array_push(rows, janet_wrap_struct(janet_struct_end(row)));
}
} while (status == SQLITE_ROW);
/* Check for errors */
if (status != SQLITE_DONE) {
sqlite3 *db = sqlite3_db_handle(stmt);
ret = sqlite3_errmsg(db);
}
return ret;
}
/* Evaluate a string of sql */
static int sql_eval(JanetArgs args) {
const char *err;
sqlite3_stmt *stmt = NULL, *stmt_next = NULL;
const uint8_t *query;
JANET_MINARITY(args, 2);
JANET_MAXARITY(args, 3);
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
if (db->flags & FLAG_CLOSED) {
JANET_THROW(args, MSG_DB_CLOSED);
}
JANET_ARG_STRING(query, args, 1);
if (has_null(query, janet_string_length(query))) {
err = "cannot have embedded NULL in sql statememts";
goto error;
}
JanetArray *rows = janet_array(10);
const char *c = (const char *)query;
/* Evaluate all statements in a loop */
do {
/* Compile the next statement */
if (sqlite3_prepare_v2(db->handle, c, -1, &stmt_next, &c) != SQLITE_OK) {
err = sqlite3_errmsg(db->handle);
goto error;
}
/* Check if we have found last statement */
if (NULL == stmt_next) {
/* Execute current statement and collect results */
if (stmt) {
err = execute_collect(stmt, rows);
if (err) goto error;
}
} else {
/* Execute current statement but don't collect results. */
if (stmt) {
err = execute(stmt);
if (err) goto error;
}
/* Bind params to next statement*/
if (args.n == 3) {
/* parameters */
err = bindmany(stmt_next, args.v[2]);
if (err) goto error;
}
}
/* rotate stmt and stmt_next */
if (stmt) sqlite3_finalize(stmt);
stmt = stmt_next;
stmt_next = NULL;
} while (NULL != stmt);
/* Good return path */
JANET_RETURN_ARRAY(args, rows);
error:
if (stmt) sqlite3_finalize(stmt);
if (stmt_next) sqlite3_finalize(stmt_next);
JANET_THROW(args, err);
}
/* Convert int64_t to a string */
static const uint8_t *coerce_int64(int64_t x) {
uint8_t bytes[40];
int i = 0;
/* Edge cases */
if (x == 0) return janet_cstring("0");
if (x == INT64_MIN) return janet_cstring("-9,223,372,036,854,775,808");
/* Negative becomes pos */
if (x < 0) {
bytes[i++] = '-';
x = -x;
}
while (x) {
bytes[i++] = x % 10;
x = x / 10;
}
bytes[i] = '\0';
return janet_string(bytes, i);
}
/* Gets the last inserted row id */
static int sql_last_insert_rowid(JanetArgs args) {
JANET_FIXARITY(args, 1);
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
if (db->flags & FLAG_CLOSED) {
JANET_THROW(args, MSG_DB_CLOSED);
}
sqlite3_int64 id = sqlite3_last_insert_rowid(db->handle);
if (id >= INT32_MIN && id <= INT32_MAX) {
JANET_RETURN_INTEGER(args, (int32_t) id);
}
/* Convert to string */
JANET_RETURN_STRING(args, coerce_int64(id));
}
/* Get the sqlite3 errcode */
static int sql_error_code(JanetArgs args) {
JANET_FIXARITY(args, 1);
JANET_CHECKABSTRACT(args, 0, &sql_conn_type);
Db *db = (Db *)janet_unwrap_abstract(args.v[0]);
if (db->flags & FLAG_CLOSED) {
JANET_THROW(args, MSG_DB_CLOSED);
}
int errcode = sqlite3_errcode(db->handle);
JANET_RETURN_INTEGER(args, errcode);
}
/*****************************************************************************/
static const JanetReg cfuns[] = {
{"open", sql_open,
"(sqlite3/open path)\n\n"
"Opens a sqlite3 database on disk. Returns the database handle if the database was opened "
"successfully, and otheriwse throws an error."
},
{"close", sql_close,
"(sqlite3/close db)\n\n"
"Closes a database. Use this to free a database after use. Returns nil."
},
{"eval", sql_eval,
"(sqlite3/eval db sql [,params])\n\n"
"Evaluate sql in the context of database db. Multiple sql statements "
"can be changed together, and optionally parameters maybe passed in. "
"The optional parameters maybe either an indexed data type (tuple or array), or a dictionary "
"data type (struct or table). If params is a tuple or array, then sqlite "
"parameters are substituted using indices. For example:\n\n"
"\t(sqlite3/eval db `SELECT * FROM tab WHERE id = ?;` [123])\n\n"
"Will select rows from tab where id is equal to 123. Alternatively, "
"the programmer can use named parameters with tables or structs, like so:\n\n"
"\t(sqlite3/eval db `SELECT * FROM tab WHERE id = :id;` {:id 123})\n\n"
"Will return an array of rows, where each row contains a table where columns names "
"are keys for column values."
},
{"last-insert-rowid", sql_last_insert_rowid,
"(sqlite3/last-insert-rowid db)\n\n"
"Returns the id of the last inserted row. If the id will fit into a 32-bit"
"signed integer, will returned an integer, otherwise will return a string representation "
"of the id (an 8 bytes string containing a long integer)."
},
{"error-code", sql_error_code,
"(sqlite3/error-code db)\n\n"
"Returns the error number of the last sqlite3 command that threw an error. Cross "
"check these numbers with the SQLite documentation for more information."
},
{NULL, NULL, NULL}
};
JANET_MODULE_ENTRY(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, "sqlite3", cfuns);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,16 +20,16 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include <janet.h>
#include <assert.h>
int main() {
#include "tests.h"
int array_test() {
int i;
JanetArray *array1, *array2;
janet_init();
array1 = janet_array(10);
array2 = janet_array(0);
@@ -62,7 +62,5 @@ int main() {
assert(array1->count == 5);
janet_deinit();
return 0;
}

114
src/boot/boot.c Normal file
View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2020 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <janet.h>
#include "tests.h"
#ifdef JANET_WINDOWS
#include <direct.h>
#define chdir(x) _chdir(x)
#else
#include <unistd.h>
#endif
extern const unsigned char *janet_gen_boot;
extern int32_t janet_gen_boot_size;
int main(int argc, const char **argv) {
/* Init janet */
janet_init();
/* Run tests */
array_test();
buffer_test();
number_test();
system_test();
table_test();
/* C tests passed */
/* Set up VM */
int status;
JanetTable *env;
env = janet_core_env(NULL);
/* Create args tuple */
JanetArray *args = janet_array(argc);
for (int i = 0; i < argc; i++)
janet_array_push(args, janet_cstringv(argv[i]));
janet_def(env, "boot/args", janet_wrap_array(args), "Command line arguments.");
/* Add in options from janetconf.h so boot.janet can configure the image as needed. */
JanetTable *opts = janet_table(0);
#ifdef JANET_NO_DOCSTRINGS
janet_table_put(opts, janet_ckeywordv("no-docstrings"), janet_wrap_true());
#endif
#ifdef JANET_NO_SOURCEMAPS
janet_table_put(opts, janet_ckeywordv("no-sourcemaps"), janet_wrap_true());
#endif
janet_def(env, "boot/config", janet_wrap_table(opts), "Boot options");
/* Run bootstrap script to generate core image */
const char *boot_filename;
#ifdef JANET_NO_SOURCEMAPS
boot_filename = NULL;
#else
boot_filename = "boot.janet";
#endif
int chdir_status = chdir(argv[1]);
if (chdir_status) {
fprintf(stderr, "Could not change to directory %s\n", argv[1]);
exit(1);
}
FILE *boot_file = fopen("src/boot/boot.janet", "rb");
if (NULL == boot_file) {
fprintf(stderr, "Could not open src/boot/boot.janet\n");
exit(1);
}
/* Slurp file into buffer */
fseek(boot_file, 0, SEEK_END);
size_t boot_size = ftell(boot_file);
fseek(boot_file, 0, SEEK_SET);
unsigned char *boot_buffer = malloc(boot_size);
if (NULL == boot_buffer) {
fprintf(stderr, "Failed to allocate boot buffer\n");
exit(1);
}
if (!fread(boot_buffer, 1, boot_size, boot_file)) {
fprintf(stderr, "Failed to read into boot buffer\n");
exit(1);
}
fclose(boot_file);
status = janet_dobytes(env, boot_buffer, (int32_t) boot_size, boot_filename, NULL);
free(boot_buffer);
/* Deinitialize vm */
janet_deinit();
return status;
}

3045
src/boot/boot.janet Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,16 +20,16 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include <janet.h>
#include <assert.h>
int main() {
#include "tests.h"
int buffer_test() {
int i;
JanetBuffer *buffer1, *buffer2;
janet_init();
buffer1 = janet_buffer(100);
buffer2 = janet_buffer(0);
@@ -58,7 +58,5 @@ int main() {
assert(buffer1->data[i] == buffer2->data[i]);
}
janet_deinit();
return 0;
}

67
src/boot/number_test.c Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <janet.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "tests.h"
/* Check a subset of numbers against system implementation.
* Note that this depends on the system implementation being correct,
* which may not be the case for old or non compliant systems. Also,
* we cannot check against bases other 10. */
/* Compare valid c numbers to system implementation. */
static void test_valid_str(const char *str) {
int err;
double cnum, jnum;
jnum = 0.0;
cnum = atof(str);
err = janet_scan_number((const uint8_t *) str, (int32_t) strlen(str), &jnum);
assert(!err);
assert(cnum == jnum);
}
int number_test() {
test_valid_str("1.0");
test_valid_str("1");
test_valid_str("2.1");
test_valid_str("1e10");
test_valid_str("2e10");
test_valid_str("1e-10");
test_valid_str("2e-10");
test_valid_str("1.123123e10");
test_valid_str("1.123123e-10");
test_valid_str("-1.23e2");
test_valid_str("-4.5e15");
test_valid_str("-4.5e151");
test_valid_str("-4.5e200");
test_valid_str("-4.5e123");
test_valid_str("123123123123123123132123");
test_valid_str("0000000011111111111111111111111111");
test_valid_str(".112312333333323123123123123123123");
return 0;
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -21,11 +20,14 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include <janet.h>
#include <assert.h>
#include <stdio.h>
#include <math.h>
int main() {
#include "tests.h"
int system_test() {
#ifdef JANET_32
assert(sizeof(void *) == 4);
@@ -33,8 +35,6 @@ int main() {
assert(sizeof(void *) == 8);
#endif
janet_init();
/* Reflexive testing and nanbox testing */
assert(janet_equals(janet_wrap_nil(), janet_wrap_nil()));
assert(janet_equals(janet_wrap_false(), janet_wrap_false()));
@@ -43,13 +43,33 @@ int main() {
assert(janet_equals(janet_wrap_integer(INT32_MAX), janet_wrap_integer(INT32_MAX)));
assert(janet_equals(janet_wrap_integer(-2), janet_wrap_integer(-2)));
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
assert(janet_equals(janet_wrap_real(1.4), janet_wrap_real(1.4)));
assert(janet_equals(janet_wrap_real(3.14159265), janet_wrap_real(3.14159265)));
assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4)));
assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265)));
#ifdef NAN
assert(janet_checktype(janet_wrap_number(NAN), JANET_NUMBER));
#else
assert(janet_checktype(janet_wrap_number(0.0 / 0.0), JANET_NUMBER));
#endif
assert(NULL != &janet_wrap_nil);
assert(janet_equals(janet_cstringv("a string."), janet_cstringv("a string.")));
assert(janet_equals(janet_csymbolv("sym"), janet_csymbolv("sym")));
janet_deinit();
Janet *t1 = janet_tuple_begin(3);
t1[0] = janet_wrap_nil();
t1[1] = janet_wrap_integer(4);
t1[2] = janet_cstringv("hi");
Janet tuple1 = janet_wrap_tuple(janet_tuple_end(t1));
Janet *t2 = janet_tuple_begin(3);
t2[0] = janet_wrap_nil();
t2[1] = janet_wrap_integer(4);
t2[2] = janet_cstringv("hi");
Janet tuple2 = janet_wrap_tuple(janet_tuple_end(t2));
assert(janet_equals(tuple1, tuple2));
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,14 +20,14 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include <janet.h>
#include <assert.h>
int main() {
JanetTable *t1, *t2;
#include "tests.h"
janet_init();
int table_test() {
JanetTable *t1, *t2;
t1 = janet_table(10);
t2 = janet_table(0);
@@ -39,7 +39,7 @@ int main() {
assert(t1->count == 4);
assert(t1->capacity >= t1->count);
assert(janet_equals(janet_table_get(t1, janet_cstringv("hello")), janet_wrap_integer(2)));
assert(janet_equals(janet_table_get(t1, janet_cstringv("akey")), janet_wrap_integer(5)));
assert(janet_equals(janet_table_get(t1, janet_cstringv("box")), janet_wrap_boolean(0)));
@@ -61,7 +61,11 @@ int main() {
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10)));
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100)));
janet_deinit();
assert(t2->count == 4);
assert(janet_equals(janet_table_remove(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10)));
assert(t2->count == 3);
assert(janet_equals(janet_table_remove(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100)));
assert(t2->count == 2);
return 0;
}

11
src/boot/tests.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef TESTS_H_DNMBUYYL
#define TESTS_H_DNMBUYYL
/* Tests */
extern int array_test();
extern int buffer_test();
extern int number_test();
extern int system_test();
extern int table_test();
#endif /* end of include guard: TESTS_H_DNMBUYYL */

76
src/conf/janetconf.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2020 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* This is an example janetconf.h file. This will be usually generated
* by the build system. */
#ifndef JANETCONF_H
#define JANETCONF_H
#define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 12
#define JANET_VERSION_PATCH 1
#define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.12.1"
/* #define JANET_BUILD "local" */
/* These settings all affect linking, so use cautiously. */
/* #define JANET_SINGLE_THREADED */
/* #define JANET_NO_DYNAMIC_MODULES */
/* #define JANET_NO_NANBOX */
/* #define JANET_API __attribute__((visibility ("default"))) */
/* These settings should be specified before amalgamation is
* built. Any build with these set should be considered non-standard, and
* certain Janet libraries should be expected not to work. */
/* #define JANET_NO_DOCSTRINGS */
/* #define JANET_NO_SOURCEMAPS */
/* #define JANET_REDUCED_OS */
/* #define JANET_NO_PROCESSES */
/* #define JANET_NO_ASSEMBLER */
/* #define JANET_NO_PEG */
/* #define JANET_NO_NET */
/* #define JANET_NO_TYPED_ARRAY */
/* #define JANET_NO_INT_TYPES */
/* #define JANET_NO_REALPATH */
/* #define JANET_NO_SYMLINKS */
/* #define JANET_NO_UMASK */
/* Other settings */
/* #define JANET_DEBUG */
/* #define JANET_PRF */
/* #define JANET_NO_UTC_MKTIME */
/* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */
/* #define JANET_EXIT(msg) do { printf("C assert failed executing janet: %s\n", msg); exit(1); } while (0) */
/* #define JANET_TOP_LEVEL_SIGNAL(msg) call_my_function((msg), stderr) */
/* #define JANET_RECURSION_GUARD 1024 */
/* #define JANET_MAX_PROTO_DEPTH 200 */
/* #define JANET_MAX_MACRO_EXPAND 200 */
/* #define JANET_STACK_MAX 16384 */
/* #define JANET_OS_NAME my-custom-os */
/* #define JANET_ARCH_NAME pdp-8 */
/* Main client settings, does not affect library code */
/* #define JANET_SIMPLE_GETLINE */
#endif /* end of include guard: JANETCONF_H */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,15 +20,26 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "gc.h"
#endif
/* Create new userdata */
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
char *data = janet_gcalloc(JANET_MEMORY_ABSTRACT, sizeof(JanetAbstractHeader) + size);
JanetAbstractHeader *header = (JanetAbstractHeader *)data;
void *a = data + sizeof(JanetAbstractHeader);
void *janet_abstract_begin(const JanetAbstractType *atype, size_t size) {
JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_NONE,
sizeof(JanetAbstractHead) + size);
header->size = size;
header->type = atype;
return a;
return (void *) & (header->data);
}
void *janet_abstract_end(void *x) {
janet_gc_settype((void *)(janet_abstract_head(x)), JANET_MEMORY_ABSTRACT);
return x;
}
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
return janet_abstract_end(janet_abstract_begin(atype, size));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,15 +20,23 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "gc.h"
#include "util.h"
#include "state.h"
#endif
#include <string.h>
/* Initializes an array */
JanetArray *janet_array_init(JanetArray *array, int32_t capacity) {
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
Janet *data = NULL;
if (capacity > 0) {
data = (Janet *) malloc(sizeof(Janet) * capacity);
janet_vm_next_collection += capacity * sizeof(Janet);
data = (Janet *) malloc(sizeof(Janet) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
@@ -39,26 +47,16 @@ JanetArray *janet_array_init(JanetArray *array, int32_t capacity) {
return array;
}
void janet_array_deinit(JanetArray *array) {
free(array->data);
}
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
return janet_array_init(array, capacity);
}
/* Creates a new array from n elements. */
JanetArray *janet_array_n(const Janet *elements, int32_t n) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
array->capacity = n;
array->count = n;
array->data = malloc(sizeof(Janet) * n);
array->data = malloc(sizeof(Janet) * (size_t) n);
if (!array->data) {
JANET_OUT_OF_MEMORY;
}
memcpy(array->data, elements, sizeof(Janet) * n);
safe_memcpy(array->data, elements, sizeof(Janet) * n);
return array;
}
@@ -67,11 +65,14 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) {
Janet *newData;
Janet *old = array->data;
if (capacity <= array->capacity) return;
capacity *= growth;
int64_t new_capacity = ((int64_t) capacity) * growth;
if (new_capacity > INT32_MAX) new_capacity = INT32_MAX;
capacity = (int32_t) new_capacity;
newData = realloc(old, capacity * sizeof(Janet));
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
janet_vm_next_collection += (capacity - array->capacity) * sizeof(Janet);
array->data = newData;
array->capacity = capacity;
}
@@ -92,6 +93,9 @@ void janet_array_setcount(JanetArray *array, int32_t count) {
/* Push a value to the top of the array */
void janet_array_push(JanetArray *array, Janet x) {
if (array->count == INT32_MAX) {
janet_panic("array overflow");
}
int32_t newcount = array->count + 1;
janet_array_ensure(array, newcount, 2);
array->data[array->count] = x;
@@ -118,194 +122,258 @@ Janet janet_array_peek(JanetArray *array) {
/* C Functions */
static int cfun_new(JanetArgs args) {
int32_t cap;
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_INTEGER(cap, args, 0);
array = janet_array(cap);
JANET_RETURN_ARRAY(args, array);
static Janet cfun_array_new(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array(cap);
return janet_wrap_array(array);
}
static int cfun_pop(JanetArgs args) {
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_ARRAY(array, args, 0);
JANET_RETURN(args, janet_array_pop(array));
static Janet cfun_array_new_filled(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
JanetArray *array = janet_array(count);
for (int32_t i = 0; i < count; i++) {
array->data[i] = x;
}
array->count = count;
return janet_wrap_array(array);
}
static int cfun_peek(JanetArgs args) {
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_ARRAY(array, args, 0);
JANET_RETURN(args, janet_array_peek(array));
static Janet cfun_array_fill(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetArray *array = janet_getarray(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
for (int32_t i = 0; i < array->count; i++) {
array->data[i] = x;
}
return argv[0];
}
static int cfun_push(JanetArgs args) {
JanetArray *array;
int32_t newcount;
JANET_MINARITY(args, 1);
JANET_ARG_ARRAY(array, args, 0);
newcount = array->count - 1 + args.n;
static Janet cfun_array_pop(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
return janet_array_pop(array);
}
static Janet cfun_array_peek(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
return janet_array_peek(array);
}
static Janet cfun_array_push(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
if (INT32_MAX - argc + 1 <= array->count) {
janet_panic("array overflow");
}
int32_t newcount = array->count - 1 + argc;
janet_array_ensure(array, newcount, 2);
if (args.n > 1) memcpy(array->data + array->count, args.v + 1, (args.n - 1) * sizeof(Janet));
if (argc > 1) memcpy(array->data + array->count, argv + 1, (size_t)(argc - 1) * sizeof(Janet));
array->count = newcount;
JANET_RETURN(args, args.v[0]);
return argv[0];
}
static int cfun_ensure(JanetArgs args) {
JanetArray *array;
int32_t newcount;
int32_t growth;
JANET_FIXARITY(args, 3);
JANET_ARG_ARRAY(array, args, 0);
JANET_ARG_INTEGER(newcount, args, 1);
JANET_ARG_INTEGER(growth, args, 2);
if (newcount < 0) JANET_THROW(args, "expected positive integer");
static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
janet_fixarity(argc, 3);
JanetArray *array = janet_getarray(argv, 0);
int32_t newcount = janet_getinteger(argv, 1);
int32_t growth = janet_getinteger(argv, 2);
if (newcount < 1) janet_panic("expected positive integer");
janet_array_ensure(array, newcount, growth);
JANET_RETURN(args, args.v[0]);
return argv[0];
}
static int cfun_slice(JanetArgs args) {
const Janet *vals;
int32_t len;
JanetArray *ret;
int32_t start, end;
JANET_MINARITY(args, 1);
JANET_MAXARITY(args, 3);
if (!janet_indexed_view(args.v[0], &vals, &len))
JANET_THROW(args, "expected array|tuple");
/* Get start */
if (args.n < 2) {
start = 0;
} else if (janet_checktype(args.v[1], JANET_INTEGER)) {
start = janet_unwrap_integer(args.v[1]);
} else {
JANET_THROW(args, "expected integer");
}
/* Get end */
if (args.n < 3) {
end = -1;
} else if (janet_checktype(args.v[2], JANET_INTEGER)) {
end = janet_unwrap_integer(args.v[2]);
} else {
JANET_THROW(args, "expected integer");
}
if (start < 0) start = len + start;
if (end < 0) end = len + end + 1;
if (end < 0 || start < 0 || end > len || start > len)
JANET_THROW(args, "slice range out of bounds");
if (end >= start) {
ret = janet_array(end - start);
memcpy(ret->data, vals + start, sizeof(Janet) * (end - start));
ret->count = end - start;
} else {
ret = janet_array(0);
}
JANET_RETURN_ARRAY(args, ret);
static Janet cfun_array_slice(int32_t argc, Janet *argv) {
JanetView view = janet_getindexed(argv, 0);
JanetRange range = janet_getslice(argc, argv);
JanetArray *array = janet_array(range.end - range.start);
if (array->data)
memcpy(array->data, view.items + range.start, sizeof(Janet) * (range.end - range.start));
array->count = range.end - range.start;
return janet_wrap_array(array);
}
static int cfun_concat(JanetArgs args) {
static Janet cfun_array_concat(int32_t argc, Janet *argv) {
int32_t i;
JanetArray *array;
JANET_MINARITY(args, 1);
JANET_ARG_ARRAY(array, args, 0);
for (i = 1; i < args.n; i++) {
switch (janet_type(args.v[i])) {
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
for (i = 1; i < argc; i++) {
switch (janet_type(argv[i])) {
default:
janet_array_push(array, args.v[i]);
janet_array_push(array, argv[i]);
break;
case JANET_ARRAY:
case JANET_TUPLE:
{
int32_t j, len;
const Janet *vals;
janet_indexed_view(args.v[i], &vals, &len);
for (j = 0; j < len; j++)
janet_array_push(array, vals[j]);
}
break;
case JANET_TUPLE: {
int32_t j, len = 0;
const Janet *vals = NULL;
janet_indexed_view(argv[i], &vals, &len);
for (j = 0; j < len; j++)
janet_array_push(array, vals[j]);
}
break;
}
}
JANET_RETURN_ARRAY(args, array);
return janet_wrap_array(array);
}
static int cfun_insert(JanetArgs args) {
int32_t at;
static Janet cfun_array_insert(int32_t argc, Janet *argv) {
size_t chunksize, restsize;
JanetArray *array;
JANET_MINARITY(args, 2);
JANET_ARG_ARRAY(array, args, 0);
JANET_ARG_INTEGER(at, args, 1);
janet_arity(argc, 2, -1);
JanetArray *array = janet_getarray(argv, 0);
int32_t at = janet_getinteger(argv, 1);
if (at < 0) {
at = array->count + at + 1;
at = array->count + at + 1;
}
if (at < 0 || at > array->count)
JANET_THROW(args, "insertion index out of bounds");
chunksize = (args.n - 2) * sizeof(Janet);
janet_panicf("insertion index %d out of range [0,%d]", at, array->count);
chunksize = (argc - 2) * sizeof(Janet);
restsize = (array->count - at) * sizeof(Janet);
janet_array_ensure(array, array->count + args.n - 2, 2);
memmove(array->data + at + args.n - 2,
array->data + at,
restsize);
memcpy(array->data + at, args.v + 2, chunksize);
array->count += (args.n - 2);
JANET_RETURN_ARRAY(args, array);
if (INT32_MAX - (argc - 2) < array->count) {
janet_panic("array overflow");
}
janet_array_ensure(array, array->count + argc - 2, 2);
if (restsize) {
memmove(array->data + at + argc - 2,
array->data + at,
restsize);
}
safe_memcpy(array->data + at, argv + 2, chunksize);
array->count += (argc - 2);
return argv[0];
}
static const JanetReg cfuns[] = {
{"array/new", cfun_new,
"(array/new capacity)\n\n"
"Creates a new empty array with a preallocated capacity. The same as "
"(array) but can be more efficient if the maximum size of an array is known."
static Janet cfun_array_remove(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 3);
JanetArray *array = janet_getarray(argv, 0);
int32_t at = janet_getinteger(argv, 1);
int32_t n = 1;
if (at < 0) {
at = array->count + at + 1;
}
if (at < 0 || at > array->count)
janet_panicf("removal index %d out of range [0,%d]", at, array->count);
if (argc == 3) {
n = janet_getinteger(argv, 2);
if (n < 0)
janet_panicf("expected non-negative integer for argument n, got %v", argv[2]);
}
if (at + n > array->count) {
n = array->count - at;
}
memmove(array->data + at,
array->data + at + n,
(array->count - at - n) * sizeof(Janet));
array->count -= n;
return argv[0];
}
static Janet cfun_array_trim(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
if (array->count) {
if (array->count < array->capacity) {
Janet *newData = realloc(array->data, array->count * sizeof(Janet));
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
array->data = newData;
array->capacity = array->count;
}
} else {
array->capacity = 0;
free(array->data);
array->data = NULL;
}
return argv[0];
}
static const JanetReg array_cfuns[] = {
{
"array/new", cfun_array_new,
JDOC("(array/new capacity)\n\n"
"Creates a new empty array with a pre-allocated capacity. The same as "
"(array) but can be more efficient if the maximum size of an array is known.")
},
{"array/pop", cfun_pop,
"(array/pop arr)\n\n"
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
"the input array."
{
"array/new-filled", cfun_array_new_filled,
JDOC("(array/new-filled count &opt value)\n\n"
"Creates a new array of count elements, all set to value, which defaults to nil. Returns the new array.")
},
{"array/peek", cfun_peek,
"(array/peek arr)\n\n"
"Returns the last element of the array. Does not modify the array."
{
"array/fill", cfun_array_fill,
JDOC("(array/fill arr &opt value)\n\n"
"Replace all elements of an array with value (defaulting to nil) without changing the length of the array. "
"Returns the modified array.")
},
{"array/push", cfun_push,
"(array/push arr x)\n\n"
"Insert an element in the end of an array. Modifies the input array and returns it."
{
"array/pop", cfun_array_pop,
JDOC("(array/pop arr)\n\n"
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
"the input array.")
},
{"array/ensure", cfun_ensure,
"(array/ensure arr capacity)\n\n"
"Ensures that the memory backing the array has enough memory for capacity "
"items. Capacity must be an integer. If the backing capacity is already enough, "
"then this function does nothing. Otherwise, the backing memory will be reallocated "
"so that there is enough space."
{
"array/peek", cfun_array_peek,
JDOC("(array/peek arr)\n\n"
"Returns the last element of the array. Does not modify the array.")
},
{"array/slice", cfun_slice,
"(array/slice arrtup [, start=0 [, end=(length arrtup)]])\n\n"
"Takes a slice of array or tuple from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the array. "
"Returns a new array."
{
"array/push", cfun_array_push,
JDOC("(array/push arr x)\n\n"
"Insert an element in the end of an array. Modifies the input array and returns it.")
},
{"array/concat", cfun_concat,
"(array/concat arr & parts)\n\n"
"Concatenates a variadic number of arrays (and tuples) into the first argument "
"which must an array. If any of the parts are arrays or tuples, their elements will "
"be inserted into the array. Otherwise, each part in parts will be appended to arr in order. "
"Return the modified array arr."
{
"array/ensure", cfun_array_ensure,
JDOC("(array/ensure arr capacity growth)\n\n"
"Ensures that the memory backing the array is large enough for capacity "
"items at the given rate of growth. Capacity and growth must be integers. "
"If the backing capacity is already enough, then this function does nothing. "
"Otherwise, the backing memory will be reallocated so that there is enough space.")
},
{"array/insert", cfun_insert,
"(array/insert arr at & xs)\n\n"
"Insert all of xs into array arr at index at. at should be an integer "
"0 and the length of the array. A negative value for at will index from "
"the end of the array, such that inserting at -1 appends to the array. "
"Returns the array."
{
"array/slice", cfun_array_slice,
JDOC("(array/slice arrtup &opt start end)\n\n"
"Takes a slice of array or tuple from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the array. "
"Note that index -1 is synonymous with index (length arrtup) to allow a full "
"negative slice range. Returns a new array.")
},
{
"array/concat", cfun_array_concat,
JDOC("(array/concat arr & parts)\n\n"
"Concatenates a variadic number of arrays (and tuples) into the first argument "
"which must an array. If any of the parts are arrays or tuples, their elements will "
"be inserted into the array. Otherwise, each part in parts will be appended to arr in order. "
"Return the modified array arr.")
},
{
"array/insert", cfun_array_insert,
JDOC("(array/insert arr at & xs)\n\n"
"Insert all of xs into array arr at index at. at should be an integer "
"0 and the length of the array. A negative value for at will index from "
"the end of the array, such that inserting at -1 appends to the array. "
"Returns the array.")
},
{
"array/remove", cfun_array_remove,
JDOC("(array/remove arr at &opt n)\n\n"
"Remove up to n elements starting at index at in array arr. at can index from "
"the end of the array with a negative index, and n must be a non-negative integer. "
"By default, n is 1. "
"Returns the array.")
},
{
"array/trim", cfun_array_trim,
JDOC("(array/trim arr)\n\n"
"Set the backing capacity of an array to its current length. Returns the modified array.")
},
{NULL, NULL, NULL}
};
/* Load the array module */
int janet_lib_array(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
return 0;
void janet_lib_array(JanetTable *env) {
janet_core_cfuns(env, NULL, array_cfuns);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,14 +20,20 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "gc.h"
#include "util.h"
#include "state.h"
#endif
/* Initialize a buffer */
JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
uint8_t *data = NULL;
if (capacity > 0) {
data = malloc(sizeof(uint8_t) * capacity);
janet_gcpressure(capacity);
data = malloc(sizeof(uint8_t) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
@@ -54,8 +60,10 @@ void janet_buffer_ensure(JanetBuffer *buffer, int32_t capacity, int32_t growth)
uint8_t *new_data;
uint8_t *old = buffer->data;
if (capacity <= buffer->capacity) return;
capacity *= growth;
new_data = realloc(old, capacity * sizeof(uint8_t));
int64_t big_capacity = ((int64_t) capacity) * growth;
capacity = big_capacity > INT32_MAX ? INT32_MAX : (int32_t) big_capacity;
janet_gcpressure(capacity - buffer->capacity);
new_data = realloc(old, (size_t) capacity * sizeof(uint8_t));
if (NULL == new_data) {
JANET_OUT_OF_MEMORY;
}
@@ -77,74 +85,71 @@ void janet_buffer_setcount(JanetBuffer *buffer, int32_t count) {
/* Adds capacity for enough extra bytes to the buffer. Ensures that the
* next n bytes pushed to the buffer will not cause a reallocation */
int janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
/* Check for buffer overflow */
if ((int64_t)n + buffer->count > INT32_MAX) {
return -1;
janet_panic("buffer overflow");
}
int32_t new_size = buffer->count + n;
if (new_size > buffer->capacity) {
int32_t new_capacity = new_size * 2;
uint8_t *new_data = realloc(buffer->data, new_capacity * sizeof(uint8_t));
janet_gcpressure(new_capacity - buffer->capacity);
if (NULL == new_data) {
JANET_OUT_OF_MEMORY;
}
buffer->data = new_data;
buffer->capacity = new_capacity;
}
return 0;
}
/* Push a cstring to buffer */
int janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
int32_t len = 0;
while (cstring[len]) ++len;
return janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
}
/* Push multiple bytes into the buffer */
int janet_buffer_push_bytes(JanetBuffer *buffer, const uint8_t *string, int32_t length) {
if (janet_buffer_extra(buffer, length)) return -1;
void janet_buffer_push_bytes(JanetBuffer *buffer, const uint8_t *string, int32_t length) {
if (0 == length) return;
janet_buffer_extra(buffer, length);
memcpy(buffer->data + buffer->count, string, length);
buffer->count += length;
return 0;
}
int janet_buffer_push_string(JanetBuffer *buffer, const uint8_t *string) {
return janet_buffer_push_bytes(buffer, string, janet_string_length(string));
void janet_buffer_push_string(JanetBuffer *buffer, const uint8_t *string) {
janet_buffer_push_bytes(buffer, string, janet_string_length(string));
}
/* Push a single byte to the buffer */
int janet_buffer_push_u8(JanetBuffer *buffer, uint8_t byte) {
if (janet_buffer_extra(buffer, 1)) return -1;
void janet_buffer_push_u8(JanetBuffer *buffer, uint8_t byte) {
janet_buffer_extra(buffer, 1);
buffer->data[buffer->count] = byte;
buffer->count++;
return 0;
}
/* Push a 16 bit unsigned integer to the buffer */
int janet_buffer_push_u16(JanetBuffer *buffer, uint16_t x) {
if (janet_buffer_extra(buffer, 2)) return -1;
void janet_buffer_push_u16(JanetBuffer *buffer, uint16_t x) {
janet_buffer_extra(buffer, 2);
buffer->data[buffer->count] = x & 0xFF;
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
buffer->count += 2;
return 0;
}
/* Push a 32 bit unsigned integer to the buffer */
int janet_buffer_push_u32(JanetBuffer *buffer, uint32_t x) {
if (janet_buffer_extra(buffer, 4)) return -1;
void janet_buffer_push_u32(JanetBuffer *buffer, uint32_t x) {
janet_buffer_extra(buffer, 4);
buffer->data[buffer->count] = x & 0xFF;
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
buffer->data[buffer->count + 2] = (x >> 16) & 0xFF;
buffer->data[buffer->count + 3] = (x >> 24) & 0xFF;
buffer->count += 4;
return 0;
}
/* Push a 64 bit unsigned integer to the buffer */
int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
if (janet_buffer_extra(buffer, 8)) return -1;
void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
janet_buffer_extra(buffer, 8);
buffer->data[buffer->count] = x & 0xFF;
buffer->data[buffer->count + 1] = (x >> 8) & 0xFF;
buffer->data[buffer->count + 2] = (x >> 16) & 0xFF;
@@ -154,165 +159,327 @@ int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
buffer->data[buffer->count + 6] = (x >> 48) & 0xFF;
buffer->data[buffer->count + 7] = (x >> 56) & 0xFF;
buffer->count += 8;
return 0;
}
/* C functions */
static int cfun_new(JanetArgs args) {
int32_t cap;
JanetBuffer *buffer;
JANET_FIXARITY(args, 1);
JANET_ARG_INTEGER(cap, args, 0);
buffer = janet_buffer(cap);
JANET_RETURN_BUFFER(args, buffer);
static Janet cfun_buffer_new(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetBuffer *buffer = janet_buffer(cap);
return janet_wrap_buffer(buffer);
}
static int cfun_u8(JanetArgs args) {
int32_t i;
JanetBuffer *buffer;
JANET_MINARITY(args, 1);
JANET_ARG_BUFFER(buffer, args, 0);
for (i = 1; i < args.n; i++) {
int32_t integer;
JANET_ARG_INTEGER(integer, args, i);
if (janet_buffer_push_u8(buffer, (uint8_t) (integer & 0xFF)))
JANET_THROW(args, "buffer overflow");
static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
int32_t byte = 0;
if (argc == 2) {
byte = janet_getinteger(argv, 1) & 0xFF;
}
JANET_RETURN(args, args.v[0]);
JanetBuffer *buffer = janet_buffer(count);
if (buffer->data)
memset(buffer->data, byte, count);
buffer->count = count;
return janet_wrap_buffer(buffer);
}
static int cfun_int(JanetArgs args) {
int32_t i;
JanetBuffer *buffer;
JANET_MINARITY(args, 1);
JANET_ARG_BUFFER(buffer, args, 0);
for (i = 1; i < args.n; i++) {
int32_t integer;
JANET_ARG_INTEGER(integer, args, i);
if (janet_buffer_push_u32(buffer, (uint32_t) integer))
JANET_THROW(args, "buffer overflow");
static Janet cfun_buffer_fill(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t byte = 0;
if (argc == 2) {
byte = janet_getinteger(argv, 1) & 0xFF;
}
JANET_RETURN(args, args.v[0]);
}
static int cfun_chars(JanetArgs args) {
int32_t i;
JanetBuffer *buffer;
JANET_MINARITY(args, 1);
JANET_ARG_BUFFER(buffer, args, 0);
for (i = 1; i < args.n; i++) {
int32_t len;
const uint8_t *str;
JANET_ARG_BYTES(str, len, args, i);
if (janet_buffer_push_bytes(buffer, str, len))
JANET_THROW(args, "buffer overflow");
if (buffer->count) {
memset(buffer->data, byte, buffer->count);
}
JANET_RETURN(args, args.v[0]);
return argv[0];
}
static int cfun_clear(JanetArgs args) {
JanetBuffer *buffer;
JANET_FIXARITY(args, 1);
JANET_ARG_BUFFER(buffer, args, 0);
static Janet cfun_buffer_trim(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
if (buffer->count) {
if (buffer->count < buffer->capacity) {
uint8_t *newData = realloc(buffer->data, buffer->count);
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
buffer->data = newData;
buffer->capacity = buffer->count;
}
} else {
buffer->capacity = 0;
free(buffer->data);
buffer->data = NULL;
}
return argv[0];
}
static Janet cfun_buffer_u8(int32_t argc, Janet *argv) {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
for (i = 1; i < argc; i++) {
janet_buffer_push_u8(buffer, (uint8_t)(janet_getinteger(argv, i) & 0xFF));
}
return argv[0];
}
static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
for (i = 1; i < argc; i++) {
double number = janet_getnumber(argv, i);
uint32_t word = (uint32_t) number;
if (word != number)
janet_panicf("cannot convert %v to machine word", argv[i]);
janet_buffer_push_u32(buffer, word);
}
return argv[0];
}
static Janet cfun_buffer_chars(int32_t argc, Janet *argv) {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
for (i = 1; i < argc; i++) {
JanetByteView view = janet_getbytes(argv, i);
if (view.bytes == buffer->data) {
janet_buffer_ensure(buffer, buffer->count + view.len, 2);
view.bytes = buffer->data;
}
janet_buffer_push_bytes(buffer, view.bytes, view.len);
}
return argv[0];
}
static Janet cfun_buffer_clear(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
buffer->count = 0;
JANET_RETURN(args, args.v[0]);
return argv[0];
}
static int cfun_popn(JanetArgs args) {
JanetBuffer *buffer;
int32_t n;
JANET_FIXARITY(args, 2);
JANET_ARG_BUFFER(buffer, args, 0);
JANET_ARG_INTEGER(n, args, 1);
if (n < 0) JANET_THROW(args, "n must be non-negative");
static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t n = janet_getinteger(argv, 1);
if (n < 0) janet_panic("n must be non-negative");
if (buffer->count < n) {
buffer->count = 0;
} else {
buffer->count -= n;
}
JANET_RETURN(args, args.v[0]);
return argv[0];
}
static int cfun_slice(JanetArgs args) {
const uint8_t *data;
int32_t len, start, end;
JanetBuffer *ret;
JANET_ARG_BYTES(data, len, args, 0);
/* Get start */
if (args.n < 2) {
start = 0;
} else if (janet_checktype(args.v[1], JANET_INTEGER)) {
start = janet_unwrap_integer(args.v[1]);
} else {
JANET_THROW(args, "expected integer");
}
/* Get end */
if (args.n < 3) {
end = -1;
} else if (janet_checktype(args.v[2], JANET_INTEGER)) {
end = janet_unwrap_integer(args.v[2]);
} else {
JANET_THROW(args, "expected integer");
}
if (start < 0) start = len + start;
if (end < 0) end = len + end + 1;
if (end < 0 || start < 0 || end > len || start > len)
JANET_THROW(args, "slice range out of bounds");
if (end >= start) {
ret = janet_buffer(end - start);
memcpy(ret->data, data + start, end - start);
ret->count = end - start;
} else {
ret = janet_buffer(0);
}
JANET_RETURN_BUFFER(args, ret);
static Janet cfun_buffer_slice(int32_t argc, Janet *argv) {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
JanetBuffer *buffer = janet_buffer(range.end - range.start);
if (buffer->data)
memcpy(buffer->data, view.bytes + range.start, range.end - range.start);
buffer->count = range.end - range.start;
return janet_wrap_buffer(buffer);
}
static const JanetReg cfuns[] = {
{"buffer/new", cfun_new,
"(buffer/new capacity)\n\n"
"Creates a new, empty buffer with enough memory for capacity bytes. "
"Returns a new buffer."
static void bitloc(int32_t argc, Janet *argv, JanetBuffer **b, int32_t *index, int *bit) {
janet_fixarity(argc, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
double x = janet_getnumber(argv, 1);
int64_t bitindex = (int64_t) x;
int64_t byteindex = bitindex >> 3;
int which_bit = bitindex & 7;
if (bitindex != x || bitindex < 0 || byteindex >= buffer->count)
janet_panicf("invalid bit index %v", argv[1]);
*b = buffer;
*index = (int32_t) byteindex;
*bit = which_bit;
}
static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
int bit;
int32_t index;
JanetBuffer *buffer;
bitloc(argc, argv, &buffer, &index, &bit);
buffer->data[index] |= 1 << bit;
return argv[0];
}
static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
int bit;
int32_t index;
JanetBuffer *buffer;
bitloc(argc, argv, &buffer, &index, &bit);
buffer->data[index] &= ~(1 << bit);
return argv[0];
}
static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
int bit;
int32_t index;
JanetBuffer *buffer;
bitloc(argc, argv, &buffer, &index, &bit);
return janet_wrap_boolean(buffer->data[index] & (1 << bit));
}
static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
int bit;
int32_t index;
JanetBuffer *buffer;
bitloc(argc, argv, &buffer, &index, &bit);
buffer->data[index] ^= (1 << bit);
return argv[0];
}
static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 5);
JanetBuffer *dest = janet_getbuffer(argv, 0);
JanetByteView src = janet_getbytes(argv, 1);
int same_buf = src.bytes == dest->data;
int32_t offset_dest = 0;
int32_t offset_src = 0;
if (argc > 2)
offset_dest = janet_gethalfrange(argv, 2, dest->count, "dest-start");
if (argc > 3)
offset_src = janet_gethalfrange(argv, 3, src.len, "src-start");
int32_t length_src;
if (argc > 4) {
int32_t src_end = janet_gethalfrange(argv, 4, src.len, "src-end");
length_src = src_end - offset_src;
if (length_src < 0) length_src = 0;
} else {
length_src = src.len - offset_src;
}
int64_t last = (int64_t) offset_dest + length_src;
if (last > INT32_MAX)
janet_panic("buffer blit out of range");
int32_t last32 = (int32_t) last;
janet_buffer_ensure(dest, last32, 2);
if (last32 > dest->count) dest->count = last32;
if (length_src) {
if (same_buf) {
/* janet_buffer_ensure may have invalidated src */
src.bytes = dest->data;
memmove(dest->data + offset_dest, src.bytes + offset_src, length_src);
} else {
memcpy(dest->data + offset_dest, src.bytes + offset_src, length_src);
}
}
return argv[0];
}
static Janet cfun_buffer_format(int32_t argc, Janet *argv) {
janet_arity(argc, 2, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
const char *strfrmt = (const char *) janet_getstring(argv, 1);
janet_buffer_format(buffer, strfrmt, 1, argc, argv);
return argv[0];
}
static const JanetReg buffer_cfuns[] = {
{
"buffer/new", cfun_buffer_new,
JDOC("(buffer/new capacity)\n\n"
"Creates a new, empty buffer with enough backing memory for capacity bytes. "
"Returns a new buffer of length 0.")
},
{"buffer/push-byte", cfun_u8,
"(buffer/push-byte buffer x)\n\n"
"Append a byte to a buffer. Will expand the buffer as necessary. "
"Returns the modified buffer. Will throw an error if the buffer overflows."
{
"buffer/new-filled", cfun_buffer_new_filled,
JDOC("(buffer/new-filled count &opt byte)\n\n"
"Creates a new buffer of length count filled with byte. By default, byte is 0. "
"Returns the new buffer.")
},
{"buffer/push-integer", cfun_int,
"(buffer/push-integer buffer x)\n\n"
"Append an integer to a buffer. The 4 bytes of the integer are appended "
"in twos complement, big endian order. Returns the modified buffer. Will "
"throw an error if the buffer overflows."
{
"buffer/fill", cfun_buffer_fill,
JDOC("(buffer/fill buffer &opt byte)\n\n"
"Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. "
"Returns the modified buffer.")
},
{"buffer/push-string", cfun_chars,
"(buffer/push-string buffer str)\n\n"
"Push a string onto the end of a buffer. Non string values will be converted "
"to strings before being pushed. Returns the modified buffer. "
"Will throw an error if the buffer overflows."
{
"buffer/trim", cfun_buffer_trim,
JDOC("(buffer/trim buffer)\n\n"
"Set the backing capacity of the buffer to the current length of the buffer. Returns the "
"modified buffer.")
},
{"buffer/popn", cfun_popn,
"(buffer/popn buffer n)\n\n"
"Removes the last n bytes from the buffer. Returns the modified buffer."
{
"buffer/push-byte", cfun_buffer_u8,
JDOC("(buffer/push-byte buffer x)\n\n"
"Append a byte to a buffer. Will expand the buffer as necessary. "
"Returns the modified buffer. Will throw an error if the buffer overflows.")
},
{"buffer/clear", cfun_clear,
"(buffer/clear buffer)\n\n"
"Sets the size of a buffer to 0 and empties it. The buffer retains "
"its memory so it can be efficiently refilled. Returns the modified buffer."
{
"buffer/push-word", cfun_buffer_word,
JDOC("(buffer/push-word buffer x)\n\n"
"Append a machine word to a buffer. The 4 bytes of the integer are appended "
"in twos complement, little endian order, unsigned. Returns the modified buffer. Will "
"throw an error if the buffer overflows.")
},
{"buffer/slice", cfun_slice,
"(buffer/slice bytes [, start=0 [, end=(length bytes)]])\n\n"
"Takes a slice of a byte sequence from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the buffer. "
"Returns a new buffer."
{
"buffer/push-string", cfun_buffer_chars,
JDOC("(buffer/push-string buffer str)\n\n"
"Push a string onto the end of a buffer. Non string values will be converted "
"to strings before being pushed. Returns the modified buffer. "
"Will throw an error if the buffer overflows.")
},
{
"buffer/popn", cfun_buffer_popn,
JDOC("(buffer/popn buffer n)\n\n"
"Removes the last n bytes from the buffer. Returns the modified buffer.")
},
{
"buffer/clear", cfun_buffer_clear,
JDOC("(buffer/clear buffer)\n\n"
"Sets the size of a buffer to 0 and empties it. The buffer retains "
"its memory so it can be efficiently refilled. Returns the modified buffer.")
},
{
"buffer/slice", cfun_buffer_slice,
JDOC("(buffer/slice bytes &opt start end)\n\n"
"Takes a slice of a byte sequence from start to end. The range is half open, "
"[start, end). Indexes can also be negative, indicating indexing from the end of the "
"end of the array. By default, start is 0 and end is the length of the buffer. "
"Returns a new buffer.")
},
{
"buffer/bit-set", cfun_buffer_bitset,
JDOC("(buffer/bit-set buffer index)\n\n"
"Sets the bit at the given bit-index. Returns the buffer.")
},
{
"buffer/bit-clear", cfun_buffer_bitclear,
JDOC("(buffer/bit-clear buffer index)\n\n"
"Clears the bit at the given bit-index. Returns the buffer.")
},
{
"buffer/bit", cfun_buffer_bitget,
JDOC("(buffer/bit buffer index)\n\n"
"Gets the bit at the given bit-index. Returns true if the bit is set, false if not.")
},
{
"buffer/bit-toggle", cfun_buffer_bittoggle,
JDOC("(buffer/bit-toggle buffer index)\n\n"
"Toggles the bit at the given bit index in buffer. Returns the buffer.")
},
{
"buffer/blit", cfun_buffer_blit,
JDOC("(buffer/blit dest src &opt dest-start src-start src-end)\n\n"
"Insert the contents of src into dest. Can optionally take indices that "
"indicate which part of src to copy into which part of dest. Indices can be "
"negative to index from the end of src or dest. Returns dest.")
},
{
"buffer/format", cfun_buffer_format,
JDOC("(buffer/format buffer format & args)\n\n"
"Snprintf like functionality for printing values into a buffer. Returns "
" the modified buffer.")
},
{NULL, NULL, NULL}
};
int janet_lib_buffer(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
return 0;
void janet_lib_buffer(JanetTable *env) {
janet_core_cfuns(env, NULL, buffer_cfuns);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,8 +20,12 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "gc.h"
#include "util.h"
#endif
/* Look up table for instructions */
enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
@@ -30,21 +34,15 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_ST, /* JOP_TYPECHECK, */
JINT_S, /* JOP_RETURN, */
JINT_0, /* JOP_RETURN_NIL, */
JINT_SSS, /* JOP_ADD_INTEGER, */
JINT_SSI, /* JOP_ADD_IMMEDIATE, */
JINT_SSS, /* JOP_ADD_REAL, */
JINT_SSS, /* JOP_ADD, */
JINT_SSS, /* JOP_SUBTRACT_INTEGER, */
JINT_SSS, /* JOP_SUBTRACT_REAL, */
JINT_SSS, /* JOP_SUBTRACT, */
JINT_SSS, /* JOP_MULTIPLY_INTEGER, */
JINT_SSI, /* JOP_MULTIPLY_IMMEDIATE, */
JINT_SSS, /* JOP_MULTIPLY_REAL, */
JINT_SSS, /* JOP_MULTIPLY, */
JINT_SSS, /* JOP_DIVIDE_INTEGER, */
JINT_SSI, /* JOP_DIVIDE_IMMEDIATE, */
JINT_SSS, /* JOP_DIVIDE_REAL, */
JINT_SSS, /* JOP_DIVIDE, */
JINT_SSS, /* JOP_MODULO, */
JINT_SSS, /* JOP_REMAINDER, */
JINT_SSS, /* JOP_BAND, */
JINT_SSS, /* JOP_BOR, */
JINT_SSS, /* JOP_BXOR, */
@@ -60,20 +58,14 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_L, /* JOP_JUMP, */
JINT_SL, /* JOP_JUMP_IF, */
JINT_SL, /* JOP_JUMP_IF_NOT, */
JINT_SL, /* JOP_JUMP_IF_NIL, */
JINT_SL, /* JOP_JUMP_IF_NOT_NIL, */
JINT_SSS, /* JOP_GREATER_THAN, */
JINT_SSS, /* JOP_GREATER_THAN_INTEGER, */
JINT_SSI, /* JOP_GREATER_THAN_IMMEDIATE, */
JINT_SSS, /* JOP_GREATER_THAN_REAL, */
JINT_SSS, /* JOP_GREATER_THAN_EQUAL_REAL, */
JINT_SSS, /* JOP_LESS_THAN, */
JINT_SSS, /* JOP_LESS_THAN_INTEGER, */
JINT_SSI, /* JOP_LESS_THAN_IMMEDIATE, */
JINT_SSS, /* JOP_LESS_THAN_REAL, */
JINT_SSS, /* JOP_LESS_THAN_EQUAL_REAL, */
JINT_SSS, /* JOP_EQUALS, */
JINT_SSS, /* JOP_EQUALS_INTEGER, */
JINT_SSI, /* JOP_EQUALS_IMMEDIATE, */
JINT_SSS, /* JOP_EQUALS_REAL, */
JINT_SSS, /* JOP_COMPARE, */
JINT_S, /* JOP_LOAD_NIL, */
JINT_S, /* JOP_LOAD_TRUE, */
@@ -92,6 +84,8 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_S, /* JOP_TAILCALL, */
JINT_SSS, /* JOP_RESUME, */
JINT_SSU, /* JOP_SIGNAL, */
JINT_SSS, /* JOP_PROPAGATE */
JINT_SSS, /* JOP_IN, */
JINT_SSS, /* JOP_GET, */
JINT_SSS, /* JOP_PUT, */
JINT_SSU, /* JOP_GET_INDEX, */
@@ -99,19 +93,21 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_SS, /* JOP_LENGTH */
JINT_S, /* JOP_MAKE_ARRAY */
JINT_S, /* JOP_MAKE_BUFFER */
JINT_S, /* JOP_MAKE_TUPLE */
JINT_S, /* JOP_MAKE_STRING */
JINT_S, /* JOP_MAKE_STRUCT */
JINT_S, /* JOP_MAKE_TABLE */
JINT_S, /* JOP_MAKE_STRING */
JINT_SSS, /* JOP_NUMERIC_LESS_THAN */
JINT_SSS, /* JOP_NUMERIC_LESS_THAN_EQUAL */
JINT_SSS, /* JOP_NUMERIC_GREATER_THAN */
JINT_SSS, /* JOP_NUMERIC_GREATER_THAN_EQUAL */
JINT_SSS /* JOP_NUMERIC_EQUAL */
JINT_S, /* JOP_MAKE_TUPLE */
JINT_S, /* JOP_MAKE_BRACKET_TUPLE */
JINT_SSS, /* JOP_GREATER_THAN_EQUAL */
JINT_SSS, /* JOP_LESS_THAN_EQUAL */
JINT_SSS, /* JOP_NEXT */
JINT_SSS, /* JOP_NOT_EQUALS, */
JINT_SSI, /* JOP_NOT_EQUALS_IMMEDIATE, */
JINT_SSS /* JOP_CANCEL, */
};
/* Verify some bytecode */
int32_t janet_verify(JanetFuncDef *def) {
int janet_verify(JanetFuncDef *def) {
int vargs = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG);
int32_t i;
int32_t maxslot = def->arity + vargs;
@@ -132,72 +128,62 @@ int32_t janet_verify(JanetFuncDef *def) {
switch (type) {
case JINT_0:
continue;
case JINT_S:
{
if ((int32_t)(instr >> 8) >= sc) return 4;
continue;
}
case JINT_S: {
if ((int32_t)(instr >> 8) >= sc) return 4;
continue;
}
case JINT_SI:
case JINT_SU:
case JINT_ST:
{
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
continue;
}
case JINT_L:
{
int32_t jumpdest = i + (((int32_t)instr) >> 8);
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
continue;
}
case JINT_SS:
{
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
case JINT_ST: {
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
continue;
}
case JINT_L: {
int32_t jumpdest = i + (((int32_t)instr) >> 8);
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
continue;
}
case JINT_SS: {
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
(int32_t)(instr >> 16) >= sc) return 4;
continue;
}
continue;
}
case JINT_SSI:
case JINT_SSU:
{
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
case JINT_SSU: {
if ((int32_t)((instr >> 8) & 0xFF) >= sc ||
(int32_t)((instr >> 16) & 0xFF) >= sc) return 4;
continue;
}
case JINT_SL:
{
int32_t jumpdest = i + (((int32_t)instr) >> 16);
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
continue;
}
case JINT_SSS:
{
if (((int32_t)(instr >> 8) & 0xFF) >= sc ||
continue;
}
case JINT_SL: {
int32_t jumpdest = i + (((int32_t)instr) >> 16);
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if (jumpdest < 0 || jumpdest >= def->bytecode_length) return 5;
continue;
}
case JINT_SSS: {
if (((int32_t)(instr >> 8) & 0xFF) >= sc ||
((int32_t)(instr >> 16) & 0xFF) >= sc ||
((int32_t)(instr >> 24) & 0xFF) >= sc) return 4;
continue;
}
case JINT_SD:
{
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)(instr >> 16) >= def->defs_length) return 6;
continue;
}
case JINT_SC:
{
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)(instr >> 16) >= def->constants_length) return 7;
continue;
}
case JINT_SES:
{
/* How can we check the last slot index? We need info parent funcdefs. Resort
* to runtime checks for now. Maybe invalid upvalue references could be defaulted
* to nil? (don't commit to this in the long term, though) */
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)((instr >> 16) & 0xFF) >= def->environments_length) return 8;
continue;
}
continue;
}
case JINT_SD: {
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)(instr >> 16) >= def->defs_length) return 6;
continue;
}
case JINT_SC: {
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)(instr >> 16) >= def->constants_length) return 7;
continue;
}
case JINT_SES: {
/* How can we check the last slot index? We need info parent funcdefs. Resort
* to runtime checks for now. Maybe invalid upvalue references could be defaulted
* to nil? (don't commit to this in the long term, though) */
if ((int32_t)((instr >> 8) & 0xFF) >= sc) return 4;
if ((int32_t)((instr >> 16) & 0xFF) >= def->environments_length) return 8;
continue;
}
}
}
@@ -224,14 +210,17 @@ int32_t janet_verify(JanetFuncDef *def) {
/* Allocate an empty funcdef. This function may have added functionality
* as commonalities between asm and compile arise. */
JanetFuncDef *janet_funcdef_alloc() {
JanetFuncDef *janet_funcdef_alloc(void) {
JanetFuncDef *def = janet_gcalloc(JANET_MEMORY_FUNCDEF, sizeof(JanetFuncDef));
def->environments = NULL;
def->constants = NULL;
def->bytecode = NULL;
def->closure_bitset = NULL;
def->flags = 0;
def->slotcount = 0;
def->arity = 0;
def->min_arity = 0;
def->max_arity = INT32_MAX;
def->source = NULL;
def->sourcemap = NULL;
def->name = NULL;

433
src/core/capi.c Normal file
View File

@@ -0,0 +1,433 @@
/*
* Copyright (c) 2020 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "state.h"
#include "fiber.h"
#endif
#ifndef JANET_SINGLE_THREADED
#ifndef JANET_WINDOWS
#include <pthread.h>
#else
#include <windows.h>
#endif
#endif
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
#ifdef JANET_TOP_LEVEL_SIGNAL
JANET_TOP_LEVEL_SIGNAL(msg);
#else
fputs(msg, stdout);
# ifdef JANET_SINGLE_THREADED
exit(-1);
# elif defined(JANET_WINDOWS)
ExitThread(-1);
# else
pthread_exit(NULL);
# endif
#endif
}
void janet_signalv(JanetSignal sig, Janet message) {
if (janet_vm_return_reg != NULL) {
*janet_vm_return_reg = message;
janet_vm_fiber->flags |= JANET_FIBER_DID_LONGJUMP;
#if defined(JANET_BSD) || defined(JANET_APPLE)
_longjmp(*janet_vm_jmp_buf, sig);
#else
longjmp(*janet_vm_jmp_buf, sig);
#endif
} else {
const char *str = (const char *)janet_formatc("janet top level signal - %v\n", message);
janet_top_level_signal(str);
}
}
void janet_panicv(Janet message) {
janet_signalv(JANET_SIGNAL_ERROR, message);
}
void janet_panicf(const char *format, ...) {
va_list args;
const uint8_t *ret;
JanetBuffer buffer;
int32_t len = 0;
while (format[len]) len++;
janet_buffer_init(&buffer, len);
va_start(args, format);
janet_formatbv(&buffer, format, args);
va_end(args);
ret = janet_string(buffer.data, buffer.count);
janet_buffer_deinit(&buffer);
janet_panics(ret);
}
void janet_panic(const char *message) {
janet_panicv(janet_cstringv(message));
}
void janet_panics(const uint8_t *message) {
janet_panicv(janet_wrap_string(message));
}
void janet_panic_type(Janet x, int32_t n, int expected) {
janet_panicf("bad slot #%d, expected %T, got %v", n, expected, x);
}
void janet_panic_abstract(Janet x, int32_t n, const JanetAbstractType *at) {
janet_panicf("bad slot #%d, expected %s, got %v", n, at->name, x);
}
void janet_fixarity(int32_t arity, int32_t fix) {
if (arity != fix)
janet_panicf("arity mismatch, expected %d, got %d", fix, arity);
}
void janet_arity(int32_t arity, int32_t min, int32_t max) {
if (min >= 0 && arity < min)
janet_panicf("arity mismatch, expected at least %d, got %d", min, arity);
if (max >= 0 && arity > max)
janet_panicf("arity mismatch, expected at most %d, got %d", max, arity);
}
#define DEFINE_GETTER(name, NAME, type) \
type janet_get##name(const Janet *argv, int32_t n) { \
Janet x = argv[n]; \
if (!janet_checktype(x, JANET_##NAME)) { \
janet_panic_type(x, n, JANET_TFLAG_##NAME); \
} \
return janet_unwrap_##name(x); \
}
#define DEFINE_OPT(name, NAME, type) \
type janet_opt##name(const Janet *argv, int32_t argc, int32_t n, type dflt) { \
if (n >= argc) return dflt; \
if (janet_checktype(argv[n], JANET_NIL)) return dflt; \
return janet_get##name(argv, n); \
}
#define DEFINE_OPTLEN(name, NAME, type) \
type janet_opt##name(const Janet *argv, int32_t argc, int32_t n, int32_t dflt_len) { \
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {\
return janet_##name(dflt_len); \
}\
return janet_get##name(argv, n); \
}
int janet_getmethod(const uint8_t *method, const JanetMethod *methods, Janet *out) {
while (methods->name) {
if (!janet_cstrcmp(method, methods->name)) {
*out = janet_wrap_cfunction(methods->cfun);
return 1;
}
methods++;
}
return 0;
}
DEFINE_GETTER(number, NUMBER, double)
DEFINE_GETTER(array, ARRAY, JanetArray *)
DEFINE_GETTER(tuple, TUPLE, const Janet *)
DEFINE_GETTER(table, TABLE, JanetTable *)
DEFINE_GETTER(struct, STRUCT, const JanetKV *)
DEFINE_GETTER(string, STRING, const uint8_t *)
DEFINE_GETTER(keyword, KEYWORD, const uint8_t *)
DEFINE_GETTER(symbol, SYMBOL, const uint8_t *)
DEFINE_GETTER(buffer, BUFFER, JanetBuffer *)
DEFINE_GETTER(fiber, FIBER, JanetFiber *)
DEFINE_GETTER(function, FUNCTION, JanetFunction *)
DEFINE_GETTER(cfunction, CFUNCTION, JanetCFunction)
DEFINE_GETTER(boolean, BOOLEAN, int)
DEFINE_GETTER(pointer, POINTER, void *)
DEFINE_OPT(number, NUMBER, double)
DEFINE_OPT(tuple, TUPLE, const Janet *)
DEFINE_OPT(struct, STRUCT, const JanetKV *)
DEFINE_OPT(string, STRING, const uint8_t *)
DEFINE_OPT(keyword, KEYWORD, const uint8_t *)
DEFINE_OPT(symbol, SYMBOL, const uint8_t *)
DEFINE_OPT(fiber, FIBER, JanetFiber *)
DEFINE_OPT(function, FUNCTION, JanetFunction *)
DEFINE_OPT(cfunction, CFUNCTION, JanetCFunction)
DEFINE_OPT(boolean, BOOLEAN, int)
DEFINE_OPT(pointer, POINTER, void *)
DEFINE_OPTLEN(buffer, BUFFER, JanetBuffer *)
DEFINE_OPTLEN(table, TABLE, JanetTable *)
DEFINE_OPTLEN(array, ARRAY, JanetArray *)
const char *janet_optcstring(const Janet *argv, int32_t argc, int32_t n, const char *dflt) {
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
return dflt;
}
return janet_getcstring(argv, n);
}
#undef DEFINE_GETTER
#undef DEFINE_OPT
#undef DEFINE_OPTLEN
const char *janet_getcstring(const Janet *argv, int32_t n) {
const uint8_t *jstr = janet_getstring(argv, n);
const char *cstr = (const char *)jstr;
if (strlen(cstr) != (size_t) janet_string_length(jstr)) {
janet_panicf("string %v contains embedded 0s");
}
return cstr;
}
int32_t janet_getnat(const Janet *argv, int32_t n) {
Janet x = argv[n];
if (!janet_checkint(x)) goto bad;
int32_t ret = janet_unwrap_integer(x);
if (ret < 0) goto bad;
return ret;
bad:
janet_panicf("bad slot #%d, expected non-negative 32 bit signed integer, got %v", n, x);
}
JanetAbstract janet_checkabstract(Janet x, const JanetAbstractType *at) {
if (!janet_checktype(x, JANET_ABSTRACT)) return NULL;
JanetAbstract a = janet_unwrap_abstract(x);
if (janet_abstract_type(a) != at) return NULL;
return a;
}
static int janet_strlike_cmp(JanetType type, Janet x, const char *cstring) {
if (janet_type(x) != type) return 0;
return !janet_cstrcmp(janet_unwrap_string(x), cstring);
}
int janet_keyeq(Janet x, const char *cstring) {
return janet_strlike_cmp(JANET_KEYWORD, x, cstring);
}
int janet_streq(Janet x, const char *cstring) {
return janet_strlike_cmp(JANET_STRING, x, cstring);
}
int janet_symeq(Janet x, const char *cstring) {
return janet_strlike_cmp(JANET_SYMBOL, x, cstring);
}
int32_t janet_getinteger(const Janet *argv, int32_t n) {
Janet x = argv[n];
if (!janet_checkint(x)) {
janet_panicf("bad slot #%d, expected 32 bit signed integer, got %v", n, x);
}
return janet_unwrap_integer(x);
}
int64_t janet_getinteger64(const Janet *argv, int32_t n) {
Janet x = argv[n];
if (!janet_checkint64(x)) {
janet_panicf("bad slot #%d, expected 64 bit signed integer, got %v", n, x);
}
return (int64_t) janet_unwrap_number(x);
}
size_t janet_getsize(const Janet *argv, int32_t n) {
Janet x = argv[n];
if (!janet_checksize(x)) {
janet_panicf("bad slot #%d, expected size, got %v", n, x);
}
return (size_t) janet_unwrap_number(x);
}
int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which) {
int32_t raw = janet_getinteger(argv, n);
int32_t not_raw = raw;
if (not_raw < 0) not_raw += length + 1;
if (not_raw < 0 || not_raw > length)
janet_panicf("%s index %d out of range [%d,%d]", which, raw, -length - 1, length);
return not_raw;
}
int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which) {
int32_t raw = janet_getinteger(argv, n);
int32_t not_raw = raw;
if (not_raw < 0) not_raw += length;
if (not_raw < 0 || not_raw > length)
janet_panicf("%s index %d out of range [%d,%d)", which, raw, -length, length);
return not_raw;
}
JanetView janet_getindexed(const Janet *argv, int32_t n) {
Janet x = argv[n];
JanetView view;
if (!janet_indexed_view(x, &view.items, &view.len)) {
janet_panic_type(x, n, JANET_TFLAG_INDEXED);
}
return view;
}
JanetByteView janet_getbytes(const Janet *argv, int32_t n) {
Janet x = argv[n];
JanetByteView view;
if (!janet_bytes_view(x, &view.bytes, &view.len)) {
janet_panic_type(x, n, JANET_TFLAG_BYTES);
}
return view;
}
JanetDictView janet_getdictionary(const Janet *argv, int32_t n) {
Janet x = argv[n];
JanetDictView view;
if (!janet_dictionary_view(x, &view.kvs, &view.len, &view.cap)) {
janet_panic_type(x, n, JANET_TFLAG_DICTIONARY);
}
return view;
}
void *janet_getabstract(const Janet *argv, int32_t n, const JanetAbstractType *at) {
Janet x = argv[n];
if (!janet_checktype(x, JANET_ABSTRACT)) {
janet_panic_abstract(x, n, at);
}
void *abstractx = janet_unwrap_abstract(x);
if (janet_abstract_type(abstractx) != at) {
janet_panic_abstract(x, n, at);
}
return abstractx;
}
JanetRange janet_getslice(int32_t argc, const Janet *argv) {
janet_arity(argc, 1, 3);
JanetRange range;
int32_t length = janet_length(argv[0]);
if (argc == 1) {
range.start = 0;
range.end = length;
} else if (argc == 2) {
range.start = janet_checktype(argv[1], JANET_NIL)
? 0
: janet_gethalfrange(argv, 1, length, "start");
range.end = length;
} else {
range.start = janet_checktype(argv[1], JANET_NIL)
? 0
: janet_gethalfrange(argv, 1, length, "start");
range.end = janet_checktype(argv[2], JANET_NIL)
? length
: janet_gethalfrange(argv, 2, length, "end");
if (range.end < range.start)
range.end = range.start;
}
return range;
}
Janet janet_dyn(const char *name) {
if (!janet_vm_fiber) {
if (!janet_vm_top_dyns) return janet_wrap_nil();
return janet_table_get(janet_vm_top_dyns, janet_ckeywordv(name));
}
if (janet_vm_fiber->env) {
return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name));
} else {
return janet_wrap_nil();
}
}
void janet_setdyn(const char *name, Janet value) {
if (!janet_vm_fiber) {
if (!janet_vm_top_dyns) janet_vm_top_dyns = janet_table(10);
janet_table_put(janet_vm_top_dyns, janet_ckeywordv(name), value);
} else {
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(1);
}
janet_table_put(janet_vm_fiber->env, janet_ckeywordv(name), value);
}
}
uint64_t janet_getflags(const Janet *argv, int32_t n, const char *flags) {
uint64_t ret = 0;
const uint8_t *keyw = janet_getkeyword(argv, n);
int32_t klen = janet_string_length(keyw);
int32_t flen = (int32_t) strlen(flags);
if (flen > 64) {
flen = 64;
}
for (int32_t j = 0; j < klen; j++) {
for (int32_t i = 0; i < flen; i++) {
if (((uint8_t) flags[i]) == keyw[j]) {
ret |= 1ULL << i;
goto found;
}
}
janet_panicf("unexpected flag %c, expected one of \"%s\"", (char) keyw[j], flags);
found:
;
}
return ret;
}
int32_t janet_optnat(const Janet *argv, int32_t argc, int32_t n, int32_t dflt) {
if (argc <= n) return dflt;
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
return janet_getnat(argv, n);
}
int32_t janet_optinteger(const Janet *argv, int32_t argc, int32_t n, int32_t dflt) {
if (argc <= n) return dflt;
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
return janet_getinteger(argv, n);
}
int64_t janet_optinteger64(const Janet *argv, int32_t argc, int32_t n, int64_t dflt) {
if (argc <= n) return dflt;
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
return janet_getinteger64(argv, n);
}
size_t janet_optsize(const Janet *argv, int32_t argc, int32_t n, size_t dflt) {
if (argc <= n) return dflt;
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
return janet_getsize(argv, n);
}
void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetAbstractType *at, void *dflt) {
if (argc <= n) return dflt;
if (janet_checktype(argv[n], JANET_NIL)) return dflt;
return janet_getabstract(argv, n, at);
}
/* Some definitions for function-like macros */
JANET_API JanetStructHead *(janet_struct_head)(const JanetKV *st) {
return janet_struct_head(st);
}
JANET_API JanetAbstractHead *(janet_abstract_head)(const void *abstract) {
return janet_abstract_head(abstract);
}
JANET_API JanetStringHead *(janet_string_head)(const uint8_t *s) {
return janet_string_head(s);
}
JANET_API JanetTupleHead *(janet_tuple_head)(const Janet *tuple) {
return janet_tuple_head(tuple);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Calvin Rose
* Copyright (c) 2020 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
@@ -20,19 +20,32 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "compile.h"
#include "emit.h"
#include "vector.h"
#endif
static int fixarity0(JanetFopts opts, JanetSlot *args) {
static int arity1or2(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) == 0;
int32_t arity = janet_v_count(args);
return arity == 1 || arity == 2;
}
static int arity2or3(JanetFopts opts, JanetSlot *args) {
(void) opts;
int32_t arity = janet_v_count(args);
return arity == 2 || arity == 3;
}
static int fixarity1(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) == 1;
}
static int maxarity1(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) <= 1;
}
static int minarity2(JanetFopts opts, JanetSlot *args) {
(void) opts;
return janet_v_count(args) >= 2;
@@ -46,79 +59,189 @@ static int fixarity3(JanetFopts opts, JanetSlot *args) {
return janet_v_count(args) == 3;
}
/* Generic hanldling for $A = op $B */
/* Generic handling for $A = op $B */
static JanetSlot genericSS(JanetFopts opts, int op, JanetSlot s) {
JanetSlot target = janetc_gettarget(opts);
janetc_emit_ss(opts.compiler, op, target, s, 1);
return target;
}
/* Generic hanldling for $A = $B op I */
/* Generic handling for $A = $B op I */
static JanetSlot genericSSI(JanetFopts opts, int op, JanetSlot s, int32_t imm) {
JanetSlot target = janetc_gettarget(opts);
janetc_emit_ssi(opts.compiler, op, target, s, imm, 1);
return target;
}
/* Emit an insruction that implements a form by itself. */
static JanetSlot opfunction(
JanetFopts opts,
JanetSlot *args,
int op,
Janet defaultArg2) {
JanetCompiler *c = opts.compiler;
int32_t len;
len = janet_v_count(args);
JanetSlot t;
if (len == 1) {
t = janetc_gettarget(opts);
janetc_emit_sss(c, op, t, args[0], janetc_cslot(defaultArg2), 1);
return t;
} else {
/* len == 2 */
t = janetc_gettarget(opts);
janetc_emit_sss(c, op, t, args[0], args[1], 1);
}
return t;
}
/* Check if a value can be coerced to an immediate value */
static int can_be_imm(Janet x, int8_t *out) {
if (!janet_checkint(x)) return 0;
int32_t integer = janet_unwrap_integer(x);
if (integer > 127 || integer < -127) return 0;
*out = (int8_t) integer;
return 1;
}
/* Check if a slot can be coerced to an immediate value */
static int can_slot_be_imm(JanetSlot s, int8_t *out) {
if (!(s.flags & JANET_SLOT_CONSTANT)) return 0;
return can_be_imm(s.constant, out);
}
/* Emit a series of instructions instead of a function call to a math op */
static JanetSlot opreduce(
JanetFopts opts,
JanetSlot *args,
int op,
Janet nullary) {
JanetFopts opts,
JanetSlot *args,
int op,
int opim,
Janet nullary) {
JanetCompiler *c = opts.compiler;
int32_t i, len;
int8_t imm = 0;
int neg = opim < 0;
if (opim < 0) opim = -opim;
len = janet_v_count(args);
JanetSlot t;
if (len == 0) {
return janetc_cslot(nullary);
} else if (len == 1) {
t = janetc_gettarget(opts);
janetc_emit_sss(c, op, t, janetc_cslot(nullary), args[0], 1);
/* Special case subtract to be times -1 */
if (op == JOP_SUBTRACT) {
janetc_emit_ssi(c, JOP_MULTIPLY_IMMEDIATE, t, args[0], -1, 1);
} else {
janetc_emit_sss(c, op, t, janetc_cslot(nullary), args[0], 1);
}
return t;
}
t = janetc_gettarget(opts);
janetc_emit_sss(c, op, t, args[0], args[1], 1);
for (i = 2; i < len; i++)
janetc_emit_sss(c, op, t, t, args[i], 1);
if (opim && can_slot_be_imm(args[1], &imm)) {
janetc_emit_ssi(c, opim, t, args[0], neg ? -imm : imm, 1);
} else {
janetc_emit_sss(c, op, t, args[0], args[1], 1);
}
for (i = 2; i < len; i++) {
if (opim && can_slot_be_imm(args[i], &imm)) {
janetc_emit_ssi(c, opim, t, t, neg ? -imm : imm, 1);
} else {
janetc_emit_sss(c, op, t, t, args[i], 1);
}
}
return t;
}
/* Function optimizers */
static JanetSlot do_propagate(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_PROPAGATE, 0, janet_wrap_nil());
}
static JanetSlot do_error(JanetFopts opts, JanetSlot *args) {
janetc_emit_s(opts.compiler, JOP_ERROR, args[0], 0);
return janetc_cslot(janet_wrap_nil());
}
static JanetSlot do_debug(JanetFopts opts, JanetSlot *args) {
(void)args;
janetc_emit(opts.compiler, JOP_SIGNAL | (2 << 24));
return janetc_cslot(janet_wrap_nil());
int32_t len = janet_v_count(args);
JanetSlot t = janetc_gettarget(opts);
janetc_emit_ssu(opts.compiler, JOP_SIGNAL, t,
(len == 1) ? args[0] : janetc_cslot(janet_wrap_nil()),
JANET_SIGNAL_DEBUG,
1);
return t;
}
static JanetSlot do_in(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_IN, 0, janet_wrap_nil());
}
static JanetSlot do_get(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_GET, janet_wrap_nil());
if (janet_v_count(args) == 3) {
JanetCompiler *c = opts.compiler;
JanetSlot t = janetc_gettarget(opts);
int target_is_default = janetc_sequal(t, args[2]);
JanetSlot dflt_slot = args[2];
if (target_is_default) {
dflt_slot = janetc_farslot(c);
janetc_copy(c, dflt_slot, t);
}
janetc_emit_sss(c, JOP_GET, t, args[0], args[1], 1);
int32_t label = janetc_emit_si(c, JOP_JUMP_IF_NOT_NIL, t, 0, 0);
janetc_copy(c, t, dflt_slot);
if (target_is_default) janetc_freeslot(c, dflt_slot);
int32_t current = janet_v_count(c->buffer);
c->buffer[label] |= (current - label) << 16;
return t;
} else {
return opreduce(opts, args, JOP_GET, 0, janet_wrap_nil());
}
}
static JanetSlot do_next(JanetFopts opts, JanetSlot *args) {
return opfunction(opts, args, JOP_NEXT, janet_wrap_nil());
}
static JanetSlot do_modulo(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_MODULO, 0, janet_wrap_nil());
}
static JanetSlot do_remainder(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_REMAINDER, 0, janet_wrap_nil());
}
static JanetSlot do_cmp(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_COMPARE, 0, janet_wrap_nil());
}
static JanetSlot do_put(JanetFopts opts, JanetSlot *args) {
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
return args[0];
if (opts.flags & JANET_FOPTS_DROP) {
janetc_emit_sss(opts.compiler, JOP_PUT, args[0], args[1], args[2], 0);
return janetc_cslot(janet_wrap_nil());
} else {
JanetSlot t = janetc_gettarget(opts);
janetc_copy(opts.compiler, t, args[0]);
janetc_emit_sss(opts.compiler, JOP_PUT, t, args[1], args[2], 0);
return t;
}
}
static JanetSlot do_length(JanetFopts opts, JanetSlot *args) {
return genericSS(opts, JOP_LENGTH, args[0]);
}
static JanetSlot do_yield(JanetFopts opts, JanetSlot *args) {
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
if (janet_v_count(args) == 0) {
return genericSSI(opts, JOP_SIGNAL, janetc_cslot(janet_wrap_nil()), 3);
} else {
return genericSSI(opts, JOP_SIGNAL, args[0], 3);
}
}
static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_RESUME, janet_wrap_nil());
return opfunction(opts, args, JOP_RESUME, janet_wrap_nil());
}
static JanetSlot do_cancel(JanetFopts opts, JanetSlot *args) {
return opfunction(opts, args, JOP_CANCEL, janet_wrap_nil());
}
static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
/* Push phase */
JanetCompiler *c = opts.compiler;
int32_t i;
for (i = 1; i < janet_v_count(args) - 3; i += 3)
janetc_emit_sss(c, JOP_PUSH_3, args[i], args[i+1], args[i+2], 0);
janetc_emit_sss(c, JOP_PUSH_3, args[i], args[i + 1], args[i + 2], 0);
if (i == janet_v_count(args) - 3)
janetc_emit_ss(c, JOP_PUSH_2, args[i], args[i+1], 0);
janetc_emit_ss(c, JOP_PUSH_2, args[i], args[i + 1], 0);
else if (i == janet_v_count(args) - 2)
janetc_emit_s(c, JOP_PUSH, args[i], 0);
/* Push array phase */
@@ -136,37 +259,37 @@ static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
return target;
}
/* Varidadic operators specialization */
/* Variadic operators specialization */
static JanetSlot do_add(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_ADD, janet_wrap_integer(0));
return opreduce(opts, args, JOP_ADD, JOP_ADD_IMMEDIATE, janet_wrap_integer(0));
}
static JanetSlot do_sub(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SUBTRACT, janet_wrap_integer(0));
return opreduce(opts, args, JOP_SUBTRACT, -JOP_ADD_IMMEDIATE, janet_wrap_integer(0));
}
static JanetSlot do_mul(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_MULTIPLY, janet_wrap_integer(1));
return opreduce(opts, args, JOP_MULTIPLY, JOP_MULTIPLY_IMMEDIATE, janet_wrap_integer(1));
}
static JanetSlot do_div(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_DIVIDE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_DIVIDE, JOP_DIVIDE_IMMEDIATE, janet_wrap_integer(1));
}
static JanetSlot do_band(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BAND, janet_wrap_integer(-1));
return opreduce(opts, args, JOP_BAND, 0, janet_wrap_integer(-1));
}
static JanetSlot do_bor(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BOR, janet_wrap_integer(0));
return opreduce(opts, args, JOP_BOR, 0, janet_wrap_integer(0));
}
static JanetSlot do_bxor(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BXOR, janet_wrap_integer(0));
return opreduce(opts, args, JOP_BXOR, 0, janet_wrap_integer(0));
}
static JanetSlot do_lshift(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_LEFT, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_LEFT, JOP_SHIFT_LEFT_IMMEDIATE, janet_wrap_integer(1));
}
static JanetSlot do_rshift(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_RIGHT, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_RIGHT, JOP_SHIFT_RIGHT_IMMEDIATE, janet_wrap_integer(1));
}
static JanetSlot do_rshiftu(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_RIGHT, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_RIGHT_UNSIGNED, JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, janet_wrap_integer(1));
}
static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
return genericSS(opts, JOP_BNOT, args[0]);
@@ -174,35 +297,35 @@ static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
/* Specialization for comparators */
static JanetSlot compreduce(
JanetFopts opts,
JanetSlot *args,
int op,
int invert) {
JanetFopts opts,
JanetSlot *args,
int op,
int opim,
int invert) {
JanetCompiler *c = opts.compiler;
int32_t i, len;
int8_t imm = 0;
len = janet_v_count(args);
int32_t *labels = NULL;
JanetSlot t;
if (len < 2) {
return invert
? janetc_cslot(janet_wrap_false())
: janetc_cslot(janet_wrap_true());
? janetc_cslot(janet_wrap_false())
: janetc_cslot(janet_wrap_true());
}
t = janetc_gettarget(opts);
for (i = 1; i < len; i++) {
janetc_emit_sss(c, op, t, args[i - 1], args[i], 1);
if (opim && can_slot_be_imm(args[i], &imm)) {
janetc_emit_ssi(c, opim, t, args[i - 1], imm, 1);
} else {
janetc_emit_sss(c, op, t, args[i - 1], args[i], 1);
}
if (i != (len - 1)) {
int32_t label = janetc_emit_si(c, JOP_JUMP_IF_NOT, t, 0, 1);
int32_t label = janetc_emit_si(c, invert ? JOP_JUMP_IF : JOP_JUMP_IF_NOT, t, 0, 1);
janet_v_push(labels, label);
}
}
int32_t end = janet_v_count(c->buffer);
if (invert) {
janetc_emit_si(c, JOP_JUMP_IF, t, 3, 0);
janetc_emit_s(c, JOP_LOAD_TRUE, t, 1);
janetc_emit(c, JOP_JUMP | (2 << 8));
janetc_emit_s(c, JOP_LOAD_FALSE, t, 1);
}
for (i = 0; i < janet_v_count(labels); i++) {
int32_t label = labels[i];
c->buffer[label] |= ((end - label) << 16);
@@ -211,51 +334,33 @@ static JanetSlot compreduce(
return t;
}
static JanetSlot do_order_gt(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_GREATER_THAN, 0);
}
static JanetSlot do_order_lt(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_LESS_THAN, 0);
}
static JanetSlot do_order_gte(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_LESS_THAN, 1);
}
static JanetSlot do_order_lte(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_GREATER_THAN, 1);
}
static JanetSlot do_order_eq(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_EQUALS, 0);
}
static JanetSlot do_order_neq(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_EQUALS, 1);
}
static JanetSlot do_gt(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_GREATER_THAN, 0);
return compreduce(opts, args, JOP_GREATER_THAN, JOP_GREATER_THAN_IMMEDIATE, 0);
}
static JanetSlot do_lt(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_LESS_THAN, 0);
return compreduce(opts, args, JOP_LESS_THAN, JOP_LESS_THAN_IMMEDIATE, 0);
}
static JanetSlot do_gte(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_GREATER_THAN_EQUAL, 0);
return compreduce(opts, args, JOP_GREATER_THAN_EQUAL, 0, 0);
}
static JanetSlot do_lte(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_LESS_THAN_EQUAL, 0);
return compreduce(opts, args, JOP_LESS_THAN_EQUAL, 0, 0);
}
static JanetSlot do_eq(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_EQUAL, 0);
return compreduce(opts, args, JOP_EQUALS, JOP_EQUALS_IMMEDIATE, 0);
}
static JanetSlot do_neq(JanetFopts opts, JanetSlot *args) {
return compreduce(opts, args, JOP_NUMERIC_EQUAL, 1);
return compreduce(opts, args, JOP_NOT_EQUALS, JOP_NOT_EQUALS_IMMEDIATE, 1);
}
/* Arranged by tag */
static const JanetFunOptimizer optimizers[] = {
{fixarity0, do_debug},
{maxarity1, do_debug},
{fixarity1, do_error},
{minarity2, do_apply},
{fixarity1, do_yield},
{fixarity2, do_resume},
{fixarity2, do_get},
{maxarity1, do_yield},
{arity1or2, do_resume},
{fixarity2, do_in},
{fixarity3, do_put},
{fixarity1, do_length},
{NULL, do_add},
@@ -269,18 +374,19 @@ static const JanetFunOptimizer optimizers[] = {
{NULL, do_rshift},
{NULL, do_rshiftu},
{fixarity1, do_bnot},
{NULL, do_order_gt},
{NULL, do_order_lt},
{NULL, do_order_gte},
{NULL, do_order_lte},
{NULL, do_order_eq},
{NULL, do_order_neq},
{NULL, do_gt},
{NULL, do_lt},
{NULL, do_gte},
{NULL, do_lte},
{NULL, do_eq},
{NULL, do_neq}
{NULL, do_neq},
{fixarity2, do_propagate},
{arity2or3, do_get},
{arity1or2, do_next},
{fixarity2, do_modulo},
{fixarity2, do_remainder},
{fixarity2, do_cmp},
{fixarity2, do_cancel},
};
const JanetFunOptimizer *janetc_funopt(uint32_t flags) {
@@ -288,7 +394,7 @@ const JanetFunOptimizer *janetc_funopt(uint32_t flags) {
if (tag == 0)
return NULL;
uint32_t index = tag - 1;
if (index >= (sizeof(optimizers)/sizeof(optimizers[0])))
if (index >= (sizeof(optimizers) / sizeof(optimizers[0])))
return NULL;
return optimizers + index;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,10 +20,15 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "compile.h"
#include "emit.h"
#include "vector.h"
#include "util.h"
#include "state.h"
#endif
JanetFopts janetc_fopts_default(JanetCompiler *c) {
JanetFopts ret;
@@ -94,10 +99,10 @@ void janetc_scope(JanetScope *s, JanetCompiler *c, int flags, const char *name)
scope.syms = NULL;
scope.envs = NULL;
scope.defs = NULL;
scope.selfconst = -1;
scope.bytecode_start = janet_v_count(c->buffer);
scope.flags = flags;
scope.parent = c->scope;
janetc_regalloc_init(&scope.ua);
/* Inherit slots */
if ((!(flags & JANET_SCOPE_FUNCTION)) && c->scope) {
janetc_regalloc_clone(&scope.ra, &(c->scope->ra));
@@ -145,6 +150,7 @@ void janetc_popscope(JanetCompiler *c) {
janet_v_free(oldscope->envs);
janet_v_free(oldscope->defs);
janetc_regalloc_deinit(&oldscope->ra);
janetc_regalloc_deinit(&oldscope->ua);
/* Update pointer */
if (newscope)
newscope->child = NULL;
@@ -163,8 +169,8 @@ void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
/* Allow searching for symbols. Return information about the symbol */
JanetSlot janetc_resolve(
JanetCompiler *c,
const uint8_t *sym) {
JanetCompiler *c,
const uint8_t *sym) {
JanetSlot ret = janetc_cslot(janet_wrap_nil());
JanetScope *scope = c->scope;
@@ -198,13 +204,12 @@ JanetSlot janetc_resolve(
switch (btype) {
default:
case JANET_BINDING_NONE:
janetc_error(c, janet_formatc("unknown symbol %q", sym));
janetc_error(c, janet_formatc("unknown symbol %q", janet_wrap_symbol(sym)));
return janetc_cslot(janet_wrap_nil());
case JANET_BINDING_DEF:
case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */
return janetc_cslot(check);
case JANET_BINDING_VAR:
{
case JANET_BINDING_VAR: {
JanetSlot ret = janetc_cslot(check);
/* TODO save type info */
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
@@ -215,7 +220,7 @@ JanetSlot janetc_resolve(
}
/* Symbol was found */
found:
found:
/* Constants can be returned immediately (they are stateless) */
if (ret.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF))
@@ -233,9 +238,14 @@ JanetSlot janetc_resolve(
scope = scope->parent;
janet_assert(scope, "invalid scopes");
scope->flags |= JANET_SCOPE_ENV;
/* In the function scope, allocate the slot as an upvalue */
janetc_regalloc_touch(&scope->ua, ret.index);
/* Iterate through child scopes and make sure environment is propagated */
scope = scope->child;
/* Propogate env up to current scope */
/* Propagate env up to current scope */
int32_t envindex = -1;
while (scope) {
if (scope->flags & JANET_SCOPE_FUNCTION) {
@@ -280,8 +290,8 @@ JanetSlot janetc_return(JanetCompiler *c, JanetSlot s) {
JanetSlot janetc_gettarget(JanetFopts opts) {
JanetSlot slot;
if ((opts.flags & JANET_FOPTS_HINT) &&
(opts.hint.envindex < 0) &&
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
(opts.hint.envindex < 0) &&
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
slot = opts.hint;
} else {
slot.envindex = -1;
@@ -308,9 +318,9 @@ JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
const JanetKV *kvs = NULL;
int32_t cap, i, len;
int32_t cap = 0, len = 0;
janet_dictionary_view(ds, &kvs, &len, &cap);
for (i = 0; i < cap; i++) {
for (int32_t i = 0; i < cap; i++) {
if (janet_checktype(kvs[i].key, JANET_NIL)) continue;
janet_v_push(ret, janetc_value(subopts, kvs[i].key));
janet_v_push(ret, janetc_value(subopts, kvs[i].value));
@@ -318,33 +328,46 @@ JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
return ret;
}
/* Push slots load via janetc_toslots. */
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots) {
/* Push slots loaded via janetc_toslots. Return the minimum number of slots pushed,
* or -1 - min_arity if there is a splice. (if there is no splice, min_arity is also
* the maximum possible arity). */
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots) {
int32_t i;
int32_t count = janet_v_count(slots);
int32_t min_arity = 0;
int has_splice = 0;
for (i = 0; i < count;) {
if (slots[i].flags & JANET_SLOT_SPLICED) {
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i], 0);
i++;
has_splice = 1;
} else if (i + 1 == count) {
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
i++;
min_arity++;
} else if (slots[i + 1].flags & JANET_SLOT_SPLICED) {
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+1], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i + 1], 0);
i += 2;
min_arity++;
has_splice = 1;
} else if (i + 2 == count) {
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i + 1], 0);
i += 2;
min_arity += 2;
} else if (slots[i + 2].flags & JANET_SLOT_SPLICED) {
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+2], 0);
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i + 1], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i + 2], 0);
i += 3;
min_arity += 2;
has_splice = 1;
} else {
janetc_emit_sss(c, JOP_PUSH_3, slots[i], slots[i+1], slots[i+2], 0);
janetc_emit_sss(c, JOP_PUSH_3, slots[i], slots[i + 1], slots[i + 2], 0);
i += 3;
min_arity += 3;
}
}
return has_splice ? (-1 - min_arity) : min_arity;
}
/* Check if a list of slots has any spliced slots */
@@ -401,8 +424,71 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
/* TODO janet function inlining (no c functions)*/
}
if (!specialized) {
janetc_pushslots(c, slots);
if (opts.flags & JANET_FOPTS_TAIL) {
int32_t min_arity = janetc_pushslots(c, slots);
/* Check for provably incorrect function calls */
if (fun.flags & JANET_SLOT_CONSTANT) {
/* Check for bad arity type if fun is a constant */
switch (janet_type(fun.constant)) {
case JANET_FUNCTION: {
JanetFunction *f = janet_unwrap_function(fun.constant);
int32_t min = f->def->min_arity;
int32_t max = f->def->max_arity;
if (min_arity < 0) {
/* Call has splices */
min_arity = -1 - min_arity;
if (min_arity > max && max >= 0) {
const uint8_t *es = janet_formatc(
"%v expects at most %d argument, got at least %d",
fun.constant, max, min_arity);
janetc_error(c, es);
}
} else {
/* Call has no splices */
if (min_arity > max && max >= 0) {
const uint8_t *es = janet_formatc(
"%v expects at most %d argument, got %d",
fun.constant, max, min_arity);
janetc_error(c, es);
}
if (min_arity < min) {
const uint8_t *es = janet_formatc(
"%v expects at least %d argument, got %d",
fun.constant, min, min_arity);
janetc_error(c, es);
}
}
}
break;
case JANET_CFUNCTION:
case JANET_ABSTRACT:
case JANET_NIL:
break;
case JANET_KEYWORD:
if (min_arity == 0) {
const uint8_t *es = janet_formatc("%v expects at least 1 argument, got 0",
fun.constant);
janetc_error(c, es);
}
break;
default:
if (min_arity > 1 || min_arity == 0) {
const uint8_t *es = janet_formatc("%v expects 1 argument, got %d",
fun.constant, min_arity);
janetc_error(c, es);
}
if (min_arity < -2) {
const uint8_t *es = janet_formatc("%v expects 1 argument, got at least %d",
fun.constant, -1 - min_arity);
janetc_error(c, es);
}
break;
}
}
if ((opts.flags & JANET_FOPTS_TAIL) &&
/* Prevent top level tail calls for better errors */
!(c->scope->flags & JANET_SCOPE_TOP)) {
janetc_emit_s(c, JOP_TAILCALL, fun, 0);
retslot = janetc_cslot(janet_wrap_nil());
retslot.flags = JANET_SLOT_RETURNED;
@@ -429,15 +515,23 @@ static JanetSlot janetc_array(JanetFopts opts, Janet x) {
JanetCompiler *c = opts.compiler;
JanetArray *a = janet_unwrap_array(x);
return janetc_maker(opts,
janetc_toslots(c, a->data, a->count),
JOP_MAKE_ARRAY);
janetc_toslots(c, a->data, a->count),
JOP_MAKE_ARRAY);
}
static JanetSlot janetc_tuple(JanetFopts opts, Janet x) {
JanetCompiler *c = opts.compiler;
const Janet *t = janet_unwrap_tuple(x);
return janetc_maker(opts,
janetc_toslots(c, t, janet_tuple_length(t)),
JOP_MAKE_TUPLE);
}
static JanetSlot janetc_tablector(JanetFopts opts, Janet x, int op) {
JanetCompiler *c = opts.compiler;
return janetc_maker(opts,
janetc_toslotskv(c, x),
op);
janetc_toslotskv(c, x),
op);
}
static JanetSlot janetc_bufferctor(JanetFopts opts, Janet x) {
@@ -445,27 +539,30 @@ static JanetSlot janetc_bufferctor(JanetFopts opts, Janet x) {
JanetBuffer *b = janet_unwrap_buffer(x);
Janet onearg = janet_stringv(b->data, b->count);
return janetc_maker(opts,
janetc_toslots(c, &onearg, 1),
JOP_MAKE_BUFFER);
janetc_toslots(c, &onearg, 1),
JOP_MAKE_BUFFER);
}
/* Expand a macro one time. Also get the special form compiler if we
* find that instead. */
static int macroexpand1(
JanetCompiler *c,
Janet x,
Janet *out,
const JanetSpecial **spec) {
JanetCompiler *c,
Janet x,
Janet *out,
const JanetSpecial **spec) {
if (!janet_checktype(x, JANET_TUPLE))
return 0;
const Janet *form = janet_unwrap_tuple(x);
if (janet_tuple_length(form) == 0)
return 0;
/* Source map - only set when we get a tuple */
if (janet_tuple_sm_start(form) >= 0) {
c->current_mapping.start = janet_tuple_sm_start(form);
c->current_mapping.end = janet_tuple_sm_end(form);
if (janet_tuple_sm_line(form) >= 0) {
c->current_mapping.line = janet_tuple_sm_line(form);
c->current_mapping.column = janet_tuple_sm_column(form);
}
/* Bracketed tuples are not specials or macros! */
if (janet_tuple_flag(form) & JANET_TUPLE_FLAG_BRACKETCTOR)
return 0;
if (!janet_checktype(form[0], JANET_SYMBOL))
return 0;
const uint8_t *name = janet_unwrap_symbol(form[0]);
@@ -480,24 +577,38 @@ static int macroexpand1(
!janet_checktype(macroval, JANET_FUNCTION))
return 0;
/* Evaluate macro */
JanetFiber *fiberp;
JanetFunction *macro = janet_unwrap_function(macroval);
int32_t arity = janet_tuple_length(form) - 1;
JanetFiber *fiberp = janet_fiber(macro, 64, arity, form + 1);
if (NULL == fiberp) {
int32_t minar = macro->def->min_arity;
int32_t maxar = macro->def->max_arity;
const uint8_t *es = NULL;
if (minar >= 0 && arity < minar)
es = janet_formatc("macro arity mismatch, expected at least %d, got %d", minar, arity);
if (maxar >= 0 && arity > maxar)
es = janet_formatc("macro arity mismatch, expected at most %d, got %d", maxar, arity);
c->result.macrofiber = NULL;
janetc_error(c, es);
return 0;
}
/* Set env */
fiberp->env = c->env;
int lock = janet_gclock();
JanetSignal status = janet_call(
macro,
janet_tuple_length(form) - 1,
form + 1,
&x,
&fiberp);
Janet mf_kw = janet_ckeywordv("macro-form");
janet_table_put(c->env, mf_kw, x);
Janet tempOut;
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
janet_table_put(c->env, mf_kw, janet_wrap_nil());
janet_gcunlock(lock);
if (status != JANET_SIGNAL_OK) {
const uint8_t *es = janet_formatc("(macro) %V", x);
const uint8_t *es = janet_formatc("(macro) %V", tempOut);
c->result.macrofiber = fiberp;
janetc_error(c, es);
return 0;
} else {
*out = x;
*out = tempOut;
}
return 1;
@@ -536,24 +647,25 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
ret = spec->compile(opts, janet_tuple_length(tup) - 1, tup + 1);
} else {
switch (janet_type(x)) {
case JANET_TUPLE:
{
JanetFopts subopts = janetc_fopts_default(c);
const Janet *tup = janet_unwrap_tuple(x);
/* Empty tuple is tuple literal */
if (janet_tuple_length(tup) == 0) {
ret = janetc_cslot(x);
} else {
JanetSlot head = janetc_value(subopts, tup[0]);
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
ret = janetc_call(opts, janetc_toslots(c, tup + 1, janet_tuple_length(tup) - 1), head);
janetc_freeslot(c, head);
}
ret.flags &= ~JANET_SLOT_SPLICED;
case JANET_TUPLE: {
JanetFopts subopts = janetc_fopts_default(c);
const Janet *tup = janet_unwrap_tuple(x);
/* Empty tuple is tuple literal */
if (janet_tuple_length(tup) == 0) {
ret = janetc_cslot(janet_wrap_tuple(janet_tuple_n(NULL, 0)));
} else if (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR) { /* [] tuples are not function call */
ret = janetc_tuple(opts, x);
} else {
JanetSlot head = janetc_value(subopts, tup[0]);
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
ret = janetc_call(opts, janetc_toslots(c, tup + 1, janet_tuple_length(tup) - 1), head);
janetc_freeslot(c, head);
}
break;
ret.flags &= ~JANET_SLOT_SPLICED;
}
break;
case JANET_SYMBOL:
ret = janetc_sym_rvalue(opts, janet_unwrap_symbol(x));
ret = janetc_resolve(c, janet_unwrap_symbol(x));
break;
case JANET_ARRAY:
ret = janetc_array(opts, x);
@@ -576,17 +688,42 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
if (c->result.status == JANET_COMPILE_ERROR)
return janetc_cslot(janet_wrap_nil());
if (opts.flags & JANET_FOPTS_TAIL)
ret = janetc_return(opts.compiler, ret);
ret = janetc_return(c, ret);
if (opts.flags & JANET_FOPTS_HINT) {
janetc_copy(opts.compiler, opts.hint, ret);
janetc_copy(c, opts.hint, ret);
ret = opts.hint;
}
c->current_mapping = last_mapping;
opts.compiler->recursion_guard++;
c->recursion_guard++;
return ret;
}
/* Add function flags to janet functions */
void janet_def_addflags(JanetFuncDef *def) {
int32_t set_flags = 0;
int32_t unset_flags = 0;
/* pos checks */
if (def->name) set_flags |= JANET_FUNCDEF_FLAG_HASNAME;
if (def->source) set_flags |= JANET_FUNCDEF_FLAG_HASSOURCE;
if (def->defs) set_flags |= JANET_FUNCDEF_FLAG_HASDEFS;
if (def->environments) set_flags |= JANET_FUNCDEF_FLAG_HASENVS;
if (def->sourcemap) set_flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
if (def->closure_bitset) set_flags |= JANET_FUNCDEF_FLAG_HASCLOBITSET;
/* negative checks */
if (!def->name) unset_flags |= JANET_FUNCDEF_FLAG_HASNAME;
if (!def->source) unset_flags |= JANET_FUNCDEF_FLAG_HASSOURCE;
if (!def->defs) unset_flags |= JANET_FUNCDEF_FLAG_HASDEFS;
if (!def->environments) unset_flags |= JANET_FUNCDEF_FLAG_HASENVS;
if (!def->sourcemap) unset_flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
if (!def->closure_bitset) unset_flags |= JANET_FUNCDEF_FLAG_HASCLOBITSET;
/* Update flags */
def->flags |= set_flags;
def->flags &= ~unset_flags;
}
/* Compile a funcdef */
/* Once the various other settings of the FuncDef have been tweaked,
* call janet_def_addflags to set the proper flags for the funcdef */
JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
JanetScope *scope = c->scope;
JanetFuncDef *def = janet_funcdef_alloc();
@@ -607,20 +744,20 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
/* Copy bytecode (only last chunk) */
def->bytecode_length = janet_v_count(c->buffer) - scope->bytecode_start;
if (def->bytecode_length) {
size_t s = sizeof(int32_t) * def->bytecode_length;
size_t s = sizeof(int32_t) * (size_t) def->bytecode_length;
def->bytecode = malloc(s);
if (NULL == def->bytecode) {
JANET_OUT_OF_MEMORY;
}
memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
safe_memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
janet_v__cnt(c->buffer) = scope->bytecode_start;
if (NULL != c->mapbuffer) {
size_t s = sizeof(JanetSourceMapping) * def->bytecode_length;
if (NULL != c->mapbuffer && c->source) {
size_t s = sizeof(JanetSourceMapping) * (size_t) def->bytecode_length;
def->sourcemap = malloc(s);
if (NULL == def->sourcemap) {
JANET_OUT_OF_MEMORY;
}
memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
safe_memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
janet_v__cnt(c->mapbuffer) = scope->bytecode_start;
}
}
@@ -629,11 +766,28 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
def->source = c->source;
def->arity = 0;
def->min_arity = 0;
def->flags = 0;
if (scope->flags & JANET_SCOPE_ENV) {
def->flags |= JANET_FUNCDEF_FLAG_NEEDSENV;
}
/* Copy upvalue bitset */
if (scope->ua.count) {
/* Number of u32s we need to create a bitmask for all slots */
int32_t slotchunks = (def->slotcount + 31) >> 5;
/* numchunks is min of slotchunks and scope->ua.count */
int32_t numchunks = slotchunks > scope->ua.count ? scope->ua.count : slotchunks;
uint32_t *chunks = calloc(sizeof(uint32_t), slotchunks);
if (NULL == chunks) {
JANET_OUT_OF_MEMORY;
}
memcpy(chunks, scope->ua.chunks, sizeof(uint32_t) * numchunks);
/* Register allocator preallocates some registers [240-255, high 16 bits of chunk index 7], we can ignore those. */
if (scope->ua.count > 7) chunks[7] &= 0xFFFFU;
def->closure_bitset = chunks;
}
/* Pop the scope */
janetc_popscope(c);
@@ -648,15 +802,15 @@ static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where)
c->recursion_guard = JANET_RECURSION_GUARD;
c->env = env;
c->source = where;
c->current_mapping.start = -1;
c->current_mapping.end = -1;
c->current_mapping.line = -1;
c->current_mapping.column = -1;
/* Init result */
c->result.error = NULL;
c->result.status = JANET_COMPILE_OK;
c->result.funcdef = NULL;
c->result.macrofiber = NULL;
c->result.error_mapping.start = -1;
c->result.error_mapping.end = -1;
c->result.error_mapping.line = -1;
c->result.error_mapping.column = -1;
}
/* Deinitialize a compiler struct */
@@ -688,6 +842,7 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
if (c.result.status == JANET_COMPILE_OK) {
JanetFuncDef *def = janetc_pop_funcdef(&c);
def->name = janet_cstring("_thunk");
janet_def_addflags(def);
c.result.funcdef = def;
} else {
c.result.error_mapping = c.current_mapping;
@@ -700,45 +855,44 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
}
/* C Function for compiling */
static int cfun(JanetArgs args) {
JanetCompileResult res;
JanetTable *t;
JanetTable *env;
JANET_MINARITY(args, 2);
JANET_MAXARITY(args, 3);
JANET_ARG_TABLE(env, args, 1);
const uint8_t *source = NULL;
if (args.n == 3) {
JANET_ARG_STRING(source, args, 2);
static Janet cfun(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 3);
JanetTable *env = argc > 1 ? janet_gettable(argv, 1) : janet_vm_fiber->env;
if (NULL == env) {
env = janet_table(0);
janet_vm_fiber->env = env;
}
res = janet_compile(args.v[0], env, source);
const uint8_t *source = NULL;
if (argc == 3) {
source = janet_getstring(argv, 2);
}
JanetCompileResult res = janet_compile(argv[0], env, source);
if (res.status == JANET_COMPILE_OK) {
JANET_RETURN_FUNCTION(args, janet_thunk(res.funcdef));
return janet_wrap_function(janet_thunk(res.funcdef));
} else {
t = janet_table(4);
janet_table_put(t, janet_csymbolv(":error"), janet_wrap_string(res.error));
janet_table_put(t, janet_csymbolv(":start"), janet_wrap_integer(res.error_mapping.start));
janet_table_put(t, janet_csymbolv(":end"), janet_wrap_integer(res.error_mapping.end));
JanetTable *t = janet_table(4);
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error));
janet_table_put(t, janet_ckeywordv("line"), janet_wrap_integer(res.error_mapping.line));
janet_table_put(t, janet_ckeywordv("column"), janet_wrap_integer(res.error_mapping.column));
if (res.macrofiber) {
janet_table_put(t, janet_csymbolv(":fiber"), janet_wrap_fiber(res.macrofiber));
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
}
JANET_RETURN_TABLE(args, t);
return janet_wrap_table(t);
}
}
static const JanetReg cfuns[] = {
{"compile", cfun,
"(compile ast env [, source])\n\n"
"Compiles an Abstract Sytnax Tree (ast) into a janet function. "
"Pair the compile function with parsing functionality to implement "
"eval. Returns a janet function and does not modify ast. Throws an "
"error if the ast cannot be compiled."
static const JanetReg compile_cfuns[] = {
{
"compile", cfun,
JDOC("(compile ast &opt env source)\n\n"
"Compiles an Abstract Syntax Tree (ast) into a function. "
"Pair the compile function with parsing functionality to implement "
"eval. Returns a new function and does not modify ast. Returns an error "
"struct with keys :line, :column, and :error if compilation fails.")
},
{NULL, NULL, NULL}
};
int janet_lib_compile(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
return 0;
void janet_lib_compile(JanetTable *env) {
janet_core_cfuns(env, NULL, compile_cfuns);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Calvin Rose
* Copyright (c) 2020 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,8 +23,11 @@
#ifndef JANET_COMPILE_H
#define JANET_COMPILE_H
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "regalloc.h"
#endif
/* Tags for some functions for the prepared inliner */
#define JANET_FUN_DEBUG 1
@@ -32,7 +35,7 @@
#define JANET_FUN_APPLY 3
#define JANET_FUN_YIELD 4
#define JANET_FUN_RESUME 5
#define JANET_FUN_GET 6
#define JANET_FUN_IN 6
#define JANET_FUN_PUT 7
#define JANET_FUN_LENGTH 8
#define JANET_FUN_ADD 9
@@ -46,18 +49,19 @@
#define JANET_FUN_RSHIFT 17
#define JANET_FUN_RSHIFTU 18
#define JANET_FUN_BNOT 19
#define JANET_FUN_ORDER_GT 20
#define JANET_FUN_ORDER_LT 21
#define JANET_FUN_ORDER_GTE 22
#define JANET_FUN_ORDER_LTE 23
#define JANET_FUN_ORDER_EQ 24
#define JANET_FUN_ORDER_NEQ 25
#define JANET_FUN_GT 26
#define JANET_FUN_LT 27
#define JANET_FUN_GTE 28
#define JANET_FUN_LTE 29
#define JANET_FUN_EQ 30
#define JANET_FUN_NEQ 31
#define JANET_FUN_GT 20
#define JANET_FUN_LT 21
#define JANET_FUN_GTE 22
#define JANET_FUN_LTE 23
#define JANET_FUN_EQ 24
#define JANET_FUN_NEQ 25
#define JANET_FUN_PROP 26
#define JANET_FUN_GET 27
#define JANET_FUN_NEXT 28
#define JANET_FUN_MODULO 29
#define JANET_FUN_REMAINDER 30
#define JANET_FUN_CMP 31
#define JANET_FUN_CANCEL 32
/* Compiler typedefs */
typedef struct JanetCompiler JanetCompiler;
@@ -94,6 +98,7 @@ struct JanetSlot {
#define JANET_SCOPE_TOP 4
#define JANET_SCOPE_UNUSED 8
#define JANET_SCOPE_CLOSURE 16
#define JANET_SCOPE_WHILE 32
/* A symbol and slot pair */
typedef struct SymPair {
@@ -124,14 +129,14 @@ struct JanetScope {
/* Regsiter allocator */
JanetcRegisterAllocator ra;
/* Referenced closure environents. The values at each index correspond
/* Upvalue allocator */
JanetcRegisterAllocator ua;
/* Referenced closure environments. The values at each index correspond
* to which index to get the environment from in the parent. The environment
* that corresponds to the direct parent's stack will always have value 0. */
int32_t *envs;
/* Where to add reference to self in constants */
int32_t selfconst;
int32_t bytecode_start;
int flags;
};
@@ -178,13 +183,13 @@ JanetFopts janetc_fopts_default(JanetCompiler *c);
/* For optimizing builtin normal functions. */
struct JanetFunOptimizer {
int (*can_optimize)(JanetFopts opts, JanetSlot *args);
JanetSlot (*optimize)(JanetFopts opts, JanetSlot *args);
JanetSlot(*optimize)(JanetFopts opts, JanetSlot *args);
};
/* A grouping of a named special and the corresponding compiler fragment */
struct JanetSpecial {
const char *name;
JanetSlot (*compile)(JanetFopts opts, int32_t argn, const Janet *argv);
JanetSlot(*compile)(JanetFopts opts, int32_t argn, const Janet *argv);
};
/****************************************************/
@@ -213,7 +218,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len);
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds);
/* Push slots load via janetc_toslots. */
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
/* Free slots loaded via janetc_toslots */
void janetc_freeslots(JanetCompiler *c, JanetSlot *slots);
@@ -240,10 +245,4 @@ JanetSlot janetc_cslot(Janet x);
/* Search for a symbol */
JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
/* Compile a symbol (or mutltisym) when used as an rvalue. */
JanetSlot janetc_sym_rvalue(JanetFopts opts, const uint8_t *sym);
/* Compile an assignment to a symbol (or multisym) */
JanetSlot janetc_sym_lvalue(JanetFopts opts, const uint8_t *sym, Janet value);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,61 +20,68 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "gc.h"
#include "state.h"
#include "util.h"
#include "vector.h"
#endif
/* Implements functionality to build a debugger from within janet.
* The repl should also be able to serve as pretty featured debugger
* out of the box. */
/* Add a break point to a function */
int janet_debug_break(JanetFuncDef *def, int32_t pc) {
void janet_debug_break(JanetFuncDef *def, int32_t pc) {
if (pc >= def->bytecode_length || pc < 0)
return 1;
janet_panic("invalid bytecode offset");
def->bytecode[pc] |= 0x80;
return 0;
}
/* Remove a break point from a function */
int janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
if (pc >= def->bytecode_length || pc < 0)
return 1;
janet_panic("invalid bytecode offset");
def->bytecode[pc] &= ~((uint32_t)0x80);
return 0;
}
/*
* Find a location for a breakpoint given a source file an
* location.
*/
int janet_debug_find(
JanetFuncDef **def_out, int32_t *pc_out,
const uint8_t *source, int32_t offset) {
void janet_debug_find(
JanetFuncDef **def_out, int32_t *pc_out,
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
/* Scan the heap for right func def */
JanetGCMemoryHeader *current = janet_vm_blocks;
JanetGCObject *current = janet_vm_blocks;
/* Keep track of the best source mapping we have seen so far */
int32_t besti = -1;
int32_t best_range = INT32_MAX;
int32_t best_line = -1;
int32_t best_column = -1;
JanetFuncDef *best_def = NULL;
while (NULL != current) {
if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
JanetFuncDef *def = (JanetFuncDef *)(current + 1);
JanetFuncDef *def = (JanetFuncDef *)(current);
if (def->sourcemap &&
def->source &&
!janet_string_compare(source, def->source)) {
/* Correct source file, check mappings. The chosen
* pc index is the first match with the smallest range. */
* pc index is the instruction closest to the given line column, but
* not after. */
int32_t i;
for (i = 0; i < def->bytecode_length; i++) {
int32_t start = def->sourcemap[i].start;
int32_t end = def->sourcemap[i].end;
if (end - start < best_range &&
start <= offset &&
end >= offset) {
best_range = end - start;
besti = i;
best_def = def;
int32_t line = def->sourcemap[i].line;
int32_t column = def->sourcemap[i].column;
if (line <= sourceLine && line >= best_line) {
if (column <= sourceColumn &&
(line > best_line || column > best_column)) {
best_line = line;
best_column = column;
besti = i;
best_def = def;
}
}
}
}
@@ -84,98 +91,149 @@ int janet_debug_find(
if (best_def) {
*def_out = best_def;
*pc_out = besti;
return 0;
} else {
return 1;
janet_panic("could not find breakpoint");
}
}
/* 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) {
int32_t fi;
const char *errstr = (const char *)janet_to_string(err);
JanetFiber **fibers = NULL;
int wrote_error = 0;
int print_color = janet_truthy(janet_dyn("err-color"));
if (print_color) janet_eprintf("\x1b[31m");
while (fiber) {
janet_v_push(fibers, fiber);
fiber = fiber->child;
}
for (fi = janet_v_count(fibers) - 1; fi >= 0; fi--) {
fiber = fibers[fi];
int32_t i = fiber->frame;
while (i > 0) {
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
JanetFuncDef *def = NULL;
i = frame->prevframe;
/* 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],
errstr);
wrote_error = 1;
}
janet_eprintf(" in");
if (frame->func) {
def = frame->func->def;
janet_eprintf(" %s", def->name ? (const char *)def->name : "<anonymous>");
if (def->source) {
janet_eprintf(" [%s]", (const char *)def->source);
}
} else {
JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) {
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
if (!janet_checktype(name, JANET_NIL))
janet_eprintf(" %s", (const char *)janet_to_string(name));
else
janet_eprintf(" <cfunction>");
}
}
if (frame->flags & JANET_STACKFRAME_TAILCALL)
janet_eprintf(" (tailcall)");
if (frame->func && frame->pc) {
int32_t off = (int32_t)(frame->pc - def->bytecode);
if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off];
janet_eprintf(" on line %d, column %d", mapping.line, mapping.column);
} else {
janet_eprintf(" pc=%d", off);
}
}
janet_eprintf("\n");
}
}
if (print_color) janet_eprintf("\x1b[0m");
janet_v_free(fibers);
}
/*
* CFuns
*/
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
* Takes a source file name and byte offset. */
static int helper_find(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
const uint8_t *source;
int32_t source_offset;
JANET_FIXARITY(args, 2);
JANET_ARG_STRING(source, args, 0);
JANET_ARG_INTEGER(source_offset, args, 1);
if (janet_debug_find(
def, bytecode_offset, source, source_offset)) {
JANET_THROW(args, "could not find breakpoint");
}
JANET_RETURN_NIL(args);
static void helper_find(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_offset) {
janet_fixarity(argc, 3);
const uint8_t *source = janet_getstring(argv, 0);
int32_t line = janet_getinteger(argv, 1);
int32_t col = janet_getinteger(argv, 2);
janet_debug_find(def, bytecode_offset, source, line, col);
}
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
* Takes a function and byte offset*/
static int helper_find_fun(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
JanetFunction *func;
int32_t offset = 0;
JANET_MINARITY(args, 1);
JANET_MAXARITY(args, 2);
JANET_ARG_FUNCTION(func, args, 0);
if (args.n == 2) {
JANET_ARG_INTEGER(offset, args, 1);
}
static void helper_find_fun(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_offset) {
janet_arity(argc, 1, 2);
JanetFunction *func = janet_getfunction(argv, 0);
int32_t offset = (argc == 2) ? janet_getinteger(argv, 1) : 0;
*def = func->def;
*bytecode_offset = offset;
JANET_RETURN_NIL(args);
}
static int cfun_break(JanetArgs args) {
static Janet cfun_debug_break(int32_t argc, Janet *argv) {
JanetFuncDef *def;
int32_t offset;
int status = helper_find(args, &def, &offset);
if (status == 0) janet_debug_break(def, offset);
return status;
helper_find(argc, argv, &def, &offset);
janet_debug_break(def, offset);
return janet_wrap_nil();
}
static int cfun_unbreak(JanetArgs args) {
static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) {
JanetFuncDef *def;
int32_t offset = 0;
helper_find(argc, argv, &def, &offset);
janet_debug_unbreak(def, offset);
return janet_wrap_nil();
}
static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) {
JanetFuncDef *def;
int32_t offset = 0;
helper_find_fun(argc, argv, &def, &offset);
janet_debug_break(def, offset);
return janet_wrap_nil();
}
static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) {
JanetFuncDef *def;
int32_t offset;
int status = helper_find(args, &def, &offset);
if (status == 0) janet_debug_unbreak(def, offset);
return status;
helper_find_fun(argc, argv, &def, &offset);
janet_debug_unbreak(def, offset);
return janet_wrap_nil();
}
static int cfun_fbreak(JanetArgs args) {
JanetFuncDef *def;
int32_t offset;
int status = helper_find_fun(args, &def, &offset);
if (status == 0) {
if (janet_debug_break(def, offset)) {
JANET_THROW(args, "could not find breakpoint");
}
}
return status;
}
static int cfun_unfbreak(JanetArgs args) {
JanetFuncDef *def;
int32_t offset;
int status = helper_find_fun(args, &def, &offset);
if (status == 0) {
if (janet_debug_unbreak(def, offset)) {
JANET_THROW(args, "could not find breakpoint");
}
}
return status;
}
static int cfun_lineage(JanetArgs args) {
JanetFiber *fiber;
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
array = janet_array(0);
static Janet cfun_debug_lineage(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(0);
while (fiber) {
janet_array_push(array, janet_wrap_fiber(fiber));
fiber = fiber->child;
}
JANET_RETURN_ARRAY(args, array);
return janet_wrap_array(array);
}
/* Extract info from one stack frame */
@@ -184,52 +242,50 @@ static Janet doframe(JanetStackFrame *frame) {
JanetTable *t = janet_table(3);
JanetFuncDef *def = NULL;
if (frame->func) {
janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
janet_table_put(t, janet_ckeywordv("function"), janet_wrap_function(frame->func));
def = frame->func->def;
if (def->name) {
janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
janet_table_put(t, janet_ckeywordv("name"), janet_wrap_string(def->name));
}
} else {
JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) {
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
if (!janet_checktype(name, JANET_NIL)) {
janet_table_put(t, janet_csymbolv(":name"), name);
janet_table_put(t, janet_ckeywordv("name"), name);
}
}
janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
janet_table_put(t, janet_ckeywordv("c"), janet_wrap_true());
}
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
janet_table_put(t, janet_ckeywordv("tail"), janet_wrap_true());
}
if (frame->func && frame->pc) {
Janet *stack = (Janet *)frame + JANET_FRAME_SIZE;
JanetArray *slots;
off = (int32_t) (frame->pc - def->bytecode);
janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
off = (int32_t)(frame->pc - def->bytecode);
janet_table_put(t, janet_ckeywordv("pc"), janet_wrap_integer(off));
if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off];
janet_table_put(t, janet_csymbolv(":source-start"), janet_wrap_integer(mapping.start));
janet_table_put(t, janet_csymbolv(":source-end"), janet_wrap_integer(mapping.end));
janet_table_put(t, janet_ckeywordv("source-line"), janet_wrap_integer(mapping.line));
janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(mapping.column));
}
if (def->source) {
janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
janet_table_put(t, janet_ckeywordv("source"), janet_wrap_string(def->source));
}
/* Add stack arguments */
slots = janet_array(def->slotcount);
memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
safe_memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
slots->count = def->slotcount;
janet_table_put(t, janet_csymbolv(":slots"), janet_wrap_array(slots));
janet_table_put(t, janet_ckeywordv("slots"), janet_wrap_array(slots));
}
return janet_wrap_table(t);
}
static int cfun_stack(JanetArgs args) {
JanetFiber *fiber;
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
array = janet_array(0);
static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(0);
{
int32_t i = fiber->frame;
JanetStackFrame *frame;
@@ -239,75 +295,112 @@ static int cfun_stack(JanetArgs args) {
i = frame->prevframe;
}
}
JANET_RETURN_ARRAY(args, array);
return janet_wrap_array(array);
}
static int cfun_argstack(JanetArgs args) {
JanetFiber *fiber;
JanetArray *array;
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
array = janet_array(fiber->stacktop - fiber->stackstart);
static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
janet_stacktrace(fiber, argv[1]);
return argv[0];
}
static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(fiber->stacktop - fiber->stackstart);
memcpy(array->data, fiber->data + fiber->stackstart, array->capacity * sizeof(Janet));
array->count = array->capacity;
JANET_RETURN_ARRAY(args, array);
return janet_wrap_array(array);
}
static const JanetReg cfuns[] = {
{"debug/break", cfun_break,
"(debug/break source byte-offset)\n\n"
"Sets a breakpoint with source a key at a given byte offset. An offset "
"of 0 is the first byte in a file. Will throw an error if the breakpoint location "
"cannot be found. For example\n\n"
"\t(debug/break \"core.janet\" 1000)\n\n"
"wil set a breakpoint at the 1000th byte of the file core.janet."},
{"debug/unbreak", cfun_unbreak,
"(debug/unbreak source byte-offset)\n\n"
"Remove a breakpoint with a source key at a given byte offset. An offset "
"of 0 is the first byte in a file. Will throw an error if the breakpoint "
"cannot be found."},
{"debug/fbreak", cfun_fbreak,
"(debug/fbreak fun [,pc=0])\n\n"
"Set a breakpoint in a given function. pc is an optional offset, which "
"is in bytecode instructions. fun is a function value. Will throw an error "
"if the offset is too large or negative."},
{"debug/unfbreak", cfun_unfbreak,
"(debug/unfbreak fun [,pc=0])\n\n"
"Unset a breakpoint set with debug/fbreak."},
{"debug/arg-stack", cfun_argstack,
"(debug/arg-stack fiber)\n\n"
"Gets all values currently on the fiber's argument stack. Normally, "
"this should be empty unless the fiber signals while pushing arguments "
"to make a function call. Returns a new array."},
{"debug/stack", cfun_stack,
"(debug/stack fib)\n\n"
"Gets information about the stack as an array of tables. Each table "
"in the array contains information about a stack frame. The top most, current "
"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"
"\t:c - true if the stack frame is a c function invocation\n"
"\t:column - the current source column of the stack frame\n"
"\t:function - the function that the stack frame represents\n"
"\t:line - the current source line of the stack frame\n"
"\t:name - the human friendly name of the function\n"
"\t:pc - integer indicating the location of the program counter\n"
"\t:source - string with filename or other identifier for the source code\n"
"\t:slots - array of all values in each slot\n"
"\t:tail - boolean indicating a tail call"
static Janet cfun_debug_step(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
Janet out = janet_wrap_nil();
janet_step(fiber, argc == 1 ? janet_wrap_nil() : argv[1], &out);
return out;
}
static const JanetReg debug_cfuns[] = {
{
"debug/break", cfun_debug_break,
JDOC("(debug/break source byte-offset)\n\n"
"Sets a breakpoint with source a key at a given line and column. "
"Will throw an error if the breakpoint location "
"cannot be found. For example\n\n"
"\t(debug/break \"core.janet\" 1000)\n\n"
"wil set a breakpoint at the 1000th byte of the file core.janet.")
},
{"debug/lineage", cfun_lineage,
"(debug/lineage fib)\n\n"
"Returns an array of all child fibers from a root fiber. This function "
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
"the fiber handling the error can see which fiber raised the signal. This function should "
"be used mostly for debugging purposes."
{
"debug/unbreak", cfun_debug_unbreak,
JDOC("(debug/unbreak source line column)\n\n"
"Remove a breakpoint with a source key at a given line and column. "
"Will throw an error if the breakpoint "
"cannot be found.")
},
{
"debug/fbreak", cfun_debug_fbreak,
JDOC("(debug/fbreak fun &opt pc)\n\n"
"Set a breakpoint in a given function. pc is an optional offset, which "
"is in bytecode instructions. fun is a function value. Will throw an error "
"if the offset is too large or negative.")
},
{
"debug/unfbreak", cfun_debug_unfbreak,
JDOC("(debug/unfbreak fun &opt pc)\n\n"
"Unset a breakpoint set with debug/fbreak.")
},
{
"debug/arg-stack", cfun_debug_argstack,
JDOC("(debug/arg-stack fiber)\n\n"
"Gets all values currently on the fiber's argument stack. Normally, "
"this should be empty unless the fiber signals while pushing arguments "
"to make a function call. Returns a new array.")
},
{
"debug/stack", cfun_debug_stack,
JDOC("(debug/stack fib)\n\n"
"Gets information about the stack as an array of tables. Each table "
"in the array contains information about a stack frame. The top most, current "
"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"
"\t:c - true if the stack frame is a c function invocation\n"
"\t:column - the current source column of the stack frame\n"
"\t:function - the function that the stack frame represents\n"
"\t:line - the current source line of the stack frame\n"
"\t:name - the human friendly name of the function\n"
"\t:pc - integer indicating the location of the program counter\n"
"\t:source - string with the file path or other identifier for the source code\n"
"\t:slots - array of all values in each slot\n"
"\t:tail - boolean indicating a tail call")
},
{
"debug/stacktrace", cfun_debug_stacktrace,
JDOC("(debug/stacktrace fiber err)\n\n"
"Prints a nice looking stacktrace for a fiber. The error message "
"err must be passed to the function as fiber's do not keep track of "
"the last error they have thrown. Returns the fiber.")
},
{
"debug/lineage", cfun_debug_lineage,
JDOC("(debug/lineage fib)\n\n"
"Returns an array of all child fibers from a root fiber. This function "
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
"the fiber handling the error can see which fiber raised the signal. This function should "
"be used mostly for debugging purposes.")
},
{
"debug/step", cfun_debug_step,
JDOC("(debug/step fiber &opt x)\n\n"
"Run a fiber for one virtual instruction of the Janet machine. Can optionally "
"pass in a value that will be passed as the resuming value. Returns the signal value, "
"which will usually be nil, as breakpoints raise nil signals.")
},
{NULL, NULL, NULL}
};
/* Module entry point */
int janet_lib_debug(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
return 0;
void janet_lib_debug(JanetTable *env) {
janet_core_cfuns(env, NULL, debug_cfuns);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,10 +20,13 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "emit.h"
#include "vector.h"
#include "regalloc.h"
#endif
/* Get a register */
int32_t janetc_allocfar(JanetCompiler *c) {
@@ -34,7 +37,7 @@ int32_t janetc_allocfar(JanetCompiler *c) {
return reg;
}
/* Get a register less than 256 */
/* Get a register less than 256 for temporary use. */
int32_t janetc_allocnear(JanetCompiler *c, JanetcRegisterTemp tag) {
return janetc_regalloc_temp(&c->scope->ra, tag);
}
@@ -61,7 +64,7 @@ static int32_t janetc_const(JanetCompiler *c, Janet x) {
if (janet_equals(x, scope->consts[i]))
return i;
}
/* Ensure not too many constsants. */
/* Ensure not too many constants. */
if (len >= 0xFFFF) {
janetc_cerror(c, "too many constants");
return 0;
@@ -76,32 +79,31 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) {
case JANET_NIL:
janetc_emit(c, (reg << 8) | JOP_LOAD_NIL);
break;
case JANET_TRUE:
janetc_emit(c, (reg << 8) | JOP_LOAD_TRUE);
case JANET_BOOLEAN:
janetc_emit(c, (reg << 8) |
(janet_unwrap_boolean(k) ? JOP_LOAD_TRUE : JOP_LOAD_FALSE));
break;
case JANET_FALSE:
janetc_emit(c, (reg << 8) | JOP_LOAD_FALSE);
break;
case JANET_INTEGER:
{
int32_t i = janet_unwrap_integer(k);
if (i <= INT16_MAX && i >= INT16_MIN) {
janetc_emit(c,
(i << 16) |
(reg << 8) |
JOP_LOAD_INTEGER);
break;
}
case JANET_NUMBER: {
double dval = janet_unwrap_number(k);
if (dval < INT16_MIN || dval > INT16_MAX)
goto do_constant;
}
int32_t i = (int32_t) dval;
if (dval != i)
goto do_constant;
uint32_t iu = (uint32_t)i;
janetc_emit(c,
(iu << 16) |
(reg << 8) |
JOP_LOAD_INTEGER);
break;
}
default:
do_constant:
{
do_constant: {
int32_t cindex = janetc_const(c, k);
janetc_emit(c,
(cindex << 16) |
(reg << 8) |
JOP_LOAD_CONSTANT);
(cindex << 16) |
(reg << 8) |
JOP_LOAD_CONSTANT);
break;
}
}
@@ -109,53 +111,53 @@ static void janetc_loadconst(JanetCompiler *c, Janet k, int32_t reg) {
/* Move a slot to a near register */
static void janetc_movenear(JanetCompiler *c,
int32_t dest,
JanetSlot src) {
int32_t dest,
JanetSlot src) {
if (src.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF)) {
janetc_loadconst(c, src.constant, dest);
/* If we also are a reference, deref the one element array */
if (src.flags & JANET_SLOT_REF) {
janetc_emit(c,
(dest << 16) |
(dest << 8) |
JOP_GET_INDEX);
(dest << 16) |
(dest << 8) |
JOP_GET_INDEX);
}
} else if (src.envindex >= 0) {
janetc_emit(c,
((uint32_t)(src.index) << 24) |
((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) |
JOP_LOAD_UPVALUE);
((uint32_t)(src.index) << 24) |
((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) |
JOP_LOAD_UPVALUE);
} else if (src.index > 0xFF || src.index != dest) {
janetc_emit(c,
((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) |
((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) |
JOP_MOVE_NEAR);
}
}
/* Move a near register to a Slot. */
static void janetc_moveback(JanetCompiler *c,
JanetSlot dest,
int32_t src) {
JanetSlot dest,
int32_t src) {
if (dest.flags & JANET_SLOT_REF) {
int32_t refreg = janetc_regalloc_temp(&c->scope->ra, JANETC_REGTEMP_5);
janetc_loadconst(c, dest.constant, refreg);
janetc_emit(c,
(src << 16) |
(refreg << 8) |
JOP_PUT_INDEX);
(src << 16) |
(refreg << 8) |
JOP_PUT_INDEX);
janetc_regalloc_freetemp(&c->scope->ra, refreg, JANETC_REGTEMP_5);
} else if (dest.envindex >= 0) {
janetc_emit(c,
((uint32_t)(dest.index) << 24) |
((uint32_t)(dest.envindex) << 16) |
((uint32_t)(src) << 8) |
JOP_SET_UPVALUE);
((uint32_t)(dest.index) << 24) |
((uint32_t)(dest.envindex) << 16) |
((uint32_t)(src) << 8) |
JOP_SET_UPVALUE);
} else if (dest.index != src) {
janetc_emit(c,
((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) |
((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) |
JOP_MOVE_FAR);
}
}
@@ -203,7 +205,7 @@ static int32_t janetc_regnear(JanetCompiler *c, JanetSlot s, JanetcRegisterTemp
}
/* Check if two slots are equal */
static int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
if ((lhs.flags & ~JANET_SLOTTYPE_ANY) == (rhs.flags & ~JANET_SLOTTYPE_ANY) &&
lhs.index == rhs.index &&
lhs.envindex == rhs.envindex) {
@@ -219,9 +221,9 @@ static int janetc_sequal(JanetSlot lhs, JanetSlot rhs) {
/* Move values from one slot to another. The destination must
* be writeable (not a literal). */
void janetc_copy(
JanetCompiler *c,
JanetSlot dest,
JanetSlot src) {
JanetCompiler *c,
JanetSlot dest,
JanetSlot src) {
if (dest.flags & JANET_SLOT_CONSTANT) {
janetc_cerror(c, "cannot write to constant");
return;
@@ -238,19 +240,19 @@ void janetc_copy(
return;
}
/* Process: src -> near -> dest */
int32_t near = janetc_allocnear(c, JANETC_REGTEMP_3);
janetc_movenear(c, near, src);
janetc_moveback(c, dest, near);
int32_t nearreg = janetc_allocnear(c, JANETC_REGTEMP_3);
janetc_movenear(c, nearreg, src);
janetc_moveback(c, dest, nearreg);
/* Cleanup */
janetc_regalloc_freetemp(&c->scope->ra, near, JANETC_REGTEMP_3);
janetc_regalloc_freetemp(&c->scope->ra, nearreg, JANETC_REGTEMP_3);
}
/* Instruction templated emitters */
static int32_t emit1s(JanetCompiler *c, uint8_t op, JanetSlot s, int32_t rest, int wr) {
int32_t reg = janetc_regnear(c, s, JANETC_REGTEMP_0);
int32_t label = janet_v_count(c->buffer);
janetc_emit(c, op | (reg << 8) | (rest << 16));
janetc_emit(c, op | (reg << 8) | ((uint32_t)rest << 16));
if (wr)
janetc_moveback(c, s, reg);
janetc_free_regnear(c, s, reg, JANETC_REGTEMP_0);
@@ -292,7 +294,7 @@ static int32_t emit2s(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2,
int32_t reg1 = janetc_regnear(c, s1, JANETC_REGTEMP_0);
int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1);
int32_t label = janet_v_count(c->buffer);
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (rest << 24));
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)rest << 24));
janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1);
if (wr)
janetc_moveback(c, s1, reg1);
@@ -325,7 +327,7 @@ int32_t janetc_emit_sss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2
int32_t reg2 = janetc_regnear(c, s2, JANETC_REGTEMP_1);
int32_t reg3 = janetc_regnear(c, s3, JANETC_REGTEMP_2);
int32_t label = janet_v_count(c->buffer);
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (reg3 << 24));
janetc_emit(c, op | (reg1 << 8) | (reg2 << 16) | ((uint32_t)reg3 << 24));
janetc_free_regnear(c, s2, reg2, JANETC_REGTEMP_1);
janetc_free_regnear(c, s3, reg3, JANETC_REGTEMP_2);
if (wr)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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,7 +23,9 @@
#ifndef JANET_EMIT_H
#define JANET_EMIT_H
#ifndef JANET_AMALG
#include "compile.h"
#endif
void janetc_emit(JanetCompiler *c, uint32_t instr);
@@ -40,6 +42,9 @@ int32_t janetc_emit_ssi(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2
int32_t janetc_emit_ssu(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, uint8_t immediate, int wr);
int32_t janetc_emit_sss(JanetCompiler *c, uint8_t op, JanetSlot s1, JanetSlot s2, JanetSlot s3, int wr);
/* Check if two slots are equivalent */
int janetc_sequal(JanetSlot x, JanetSlot y);
/* Move value from one slot to another. Cannot copy to constant slots. */
void janetc_copy(JanetCompiler *c, JanetSlot dest, JanetSlot src);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,38 +20,36 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include "line.h"
/* Feature test macros */
extern const unsigned char *janet_gen_init;
extern int32_t janet_gen_init_size;
#ifndef JANET_FEATURES_H_defined
#define JANET_FEATURES_H_defined
int main(int argc, char **argv) {
int i, status;
JanetArray *args;
JanetTable *env;
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|| defined(__bsdi__) || defined(__DragonFly__)
/* Use BSD soucre on any BSD systems, include OSX */
# define _BSD_SOURCE
#else
/* Use POSIX feature flags */
# ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200809L
# endif
#endif
/* Set up VM */
janet_init();
env = janet_core_env();
#if defined(WIN32) || defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#endif
/* Create args tuple */
args = janet_array(argc);
for (i = 0; i < argc; i++)
janet_array_push(args, janet_cstringv(argv[i]));
janet_def(env, "process/args", janet_wrap_array(args), "Command line arguments.");
/* Needed for realpath on linux */
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
#define _XOPEN_SOURCE 500
#endif
/* Expose line getter */
janet_def(env, "getline", janet_wrap_cfunction(janet_line_getter), NULL);
janet_register("getline", janet_line_getter);
janet_line_init();
/* Needed for timegm and other extensions when building with -std=c99.
* It also defines realpath, etc, which would normally require
* _XOPEN_SOURCE >= 500. */
#if !defined(_NETBSD_SOURCE) && defined(__NetBSD__)
#define _NETBSD_SOURCE
#endif
/* Run startup script */
status = janet_dobytes(env, janet_gen_init, janet_gen_init_size, "init.janet", NULL);
/* Deinitialize vm */
janet_deinit();
janet_line_deinit();
return status;
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,56 +20,87 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "fiber.h"
#include "state.h"
#include "gc.h"
#include "util.h"
#endif
static JanetFiber *make_fiber(int32_t capacity) {
static void fiber_reset(JanetFiber *fiber) {
fiber->maxstack = JANET_STACK_MAX;
fiber->frame = 0;
fiber->stackstart = JANET_FRAME_SIZE;
fiber->stacktop = JANET_FRAME_SIZE;
fiber->child = NULL;
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
fiber->env = NULL;
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
}
static JanetFiber *fiber_alloc(int32_t capacity) {
Janet *data;
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
if (capacity < 32) {
capacity = 32;
}
fiber->capacity = capacity;
data = malloc(sizeof(Janet) * capacity);
data = malloc(sizeof(Janet) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
janet_vm_next_collection += sizeof(Janet) * capacity;
fiber->data = data;
fiber->maxstack = JANET_STACK_MAX;
fiber->frame = 0;
fiber->stackstart = JANET_FRAME_SIZE;
fiber->stacktop = JANET_FRAME_SIZE;
fiber->child = NULL;
fiber->flags = JANET_FIBER_MASK_YIELD;
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
return fiber;
}
/* Initialize a new fiber */
JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity) {
JanetFiber *fiber = make_fiber(capacity);
if (janet_fiber_funcframe(fiber, callee))
janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
return fiber;
}
/* Clear a fiber (reset it) with argn values on the stack. */
JanetFiber *janet_fiber_n(JanetFunction *callee, int32_t capacity, const Janet *argv, int32_t argn) {
/* Create a new fiber with argn values on the stack by reusing a fiber. */
JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t argc, const Janet *argv) {
int32_t newstacktop;
JanetFiber *fiber = make_fiber(capacity);
newstacktop = fiber->stacktop + argn;
if (newstacktop >= fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newstacktop);
fiber_reset(fiber);
if (argc) {
newstacktop = fiber->stacktop + argc;
if (newstacktop >= fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newstacktop);
}
if (argv) {
memcpy(fiber->data + fiber->stacktop, argv, argc * sizeof(Janet));
} else {
/* If argv not given, fill with nil */
for (int32_t i = 0; i < argc; i++) {
fiber->data[fiber->stacktop + i] = janet_wrap_nil();
}
}
fiber->stacktop = newstacktop;
}
memcpy(fiber->data + fiber->stacktop, argv, argn * sizeof(Janet));
fiber->stacktop = newstacktop;
if (janet_fiber_funcframe(fiber, callee))
janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
if (janet_fiber_funcframe(fiber, callee)) return NULL;
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
return fiber;
}
/* Create a new fiber with argn values on the stack. */
JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, const Janet *argv) {
return janet_fiber_reset(fiber_alloc(capacity), callee, argc, argv);
}
#ifdef JANET_DEBUG
/* Test for memory issues by reallocating fiber every time we push a stack frame */
static void janet_fiber_refresh_memory(JanetFiber *fiber) {
int32_t n = fiber->capacity;
if (n) {
Janet *newData = malloc(sizeof(Janet) * n);
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
memcpy(newData, fiber->data, fiber->capacity * sizeof(Janet));
free(fiber->data);
fiber->data = newData;
}
}
#endif
/* Ensure that the fiber has enough extra capacity */
void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
Janet *newData = realloc(fiber->data, sizeof(Janet) * n);
@@ -80,19 +111,27 @@ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
fiber->capacity = n;
}
/* Grow fiber if needed */
static void janet_fiber_grow(JanetFiber *fiber, int32_t needed) {
int32_t cap = needed > (INT32_MAX / 2) ? INT32_MAX : 2 * needed;
janet_fiber_setcapacity(fiber, cap);
}
/* Push a value on the next stack frame */
void janet_fiber_push(JanetFiber *fiber, Janet x) {
if (fiber->stacktop == INT32_MAX) janet_panic("stack overflow");
if (fiber->stacktop >= fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * fiber->stacktop);
janet_fiber_grow(fiber, fiber->stacktop);
}
fiber->data[fiber->stacktop++] = x;
}
/* Push 2 values on the next stack frame */
void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
if (fiber->stacktop >= INT32_MAX - 1) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + 2;
if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop);
janet_fiber_grow(fiber, newtop);
}
fiber->data[fiber->stacktop] = x;
fiber->data[fiber->stacktop + 1] = y;
@@ -101,9 +140,10 @@ void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
/* Push 3 values on the next stack frame */
void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
if (fiber->stacktop >= INT32_MAX - 2) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + 3;
if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop);
janet_fiber_grow(fiber, newtop);
}
fiber->data[fiber->stacktop] = x;
fiber->data[fiber->stacktop + 1] = y;
@@ -113,14 +153,25 @@ void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
/* Push an array on the next stack frame */
void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) {
if (fiber->stacktop > INT32_MAX - n) janet_panic("stack overflow");
int32_t newtop = fiber->stacktop + n;
if (newtop > fiber->capacity) {
janet_fiber_setcapacity(fiber, 2 * newtop);
janet_fiber_grow(fiber, newtop);
}
memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
safe_memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
fiber->stacktop = newtop;
}
/* Create a struct with n values. If n is odd, the last value is ignored. */
static Janet make_struct_n(const Janet *args, int32_t n) {
int32_t i = 0;
JanetKV *st = janet_struct_begin(n & (~1));
for (; i < n; i += 2) {
janet_struct_put(st, args[i], args[i + 1]);
}
return janet_wrap_struct(janet_struct_end(st));
}
/* Push a stack frame to a fiber */
int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
JanetStackFrame *newframe;
@@ -132,8 +183,16 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
int32_t nextstacktop = nextframe + func->def->slotcount + JANET_FRAME_SIZE;
int32_t next_arity = fiber->stacktop - fiber->stackstart;
/* Check strict arity before messing with state */
if (next_arity < func->def->min_arity) return 1;
if (next_arity > func->def->max_arity) return 1;
if (fiber->capacity < nextstacktop) {
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
#ifdef JANET_DEBUG
} else {
janet_fiber_refresh_memory(fiber);
#endif
}
/* Nil unset stack arguments (Needed for gc correctness) */
@@ -154,19 +213,19 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
/* Check varargs */
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
int32_t tuplehead = fiber->frame + func->def->arity;
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
if (tuplehead >= oldtop) {
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
fiber->data[tuplehead] = st
? make_struct_n(NULL, 0)
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
} else {
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
oldtop - tuplehead));
}
}
/* Check strict arity AFTER getting fiber to valid state. */
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
if (func->def->arity != next_arity) {
return 1;
fiber->data[tuplehead] = st
? make_struct_n(
fiber->data + tuplehead,
oldtop - tuplehead)
: janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
oldtop - tuplehead));
}
}
@@ -179,17 +238,79 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
static void janet_env_detach(JanetFuncEnv *env) {
/* Check for closure environment */
if (env) {
size_t s = sizeof(Janet) * env->length;
janet_env_valid(env);
int32_t len = env->length;
size_t s = sizeof(Janet) * (size_t) len;
Janet *vmem = malloc(s);
janet_vm_next_collection += (uint32_t) s;
if (NULL == vmem) {
JANET_OUT_OF_MEMORY;
}
memcpy(vmem, env->as.fiber->data + env->offset, s);
Janet *values = env->as.fiber->data + env->offset;
safe_memcpy(vmem, values, s);
uint32_t *bitset = janet_stack_frame(values)->func->def->closure_bitset;
if (bitset) {
/* Clear unneeded references in closure environment */
for (int32_t i = 0; i < len; i += 32) {
uint32_t mask = ~(bitset[i >> 5]);
int32_t maxj = i + 32 > len ? len : i + 32;
for (int32_t j = i; j < maxj; j++) {
if (mask & 1) vmem[j] = janet_wrap_nil();
mask >>= 1;
}
}
}
env->offset = 0;
env->as.values = vmem;
}
}
/* Validate potentially untrusted func env (unmarshalled envs are difficult to verify) */
int janet_env_valid(JanetFuncEnv *env) {
if (env->offset < 0) {
int32_t real_offset = -(env->offset);
JanetFiber *fiber = env->as.fiber;
int32_t i = fiber->frame;
while (i > 0) {
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
if (real_offset == i &&
frame->env == env &&
frame->func &&
frame->func->def->slotcount == env->length) {
env->offset = real_offset;
return 1;
}
i = frame->prevframe;
}
/* Invalid, set to empty off-stack variant. */
env->offset = 0;
env->length = 0;
env->as.values = NULL;
return 0;
} else {
return 1;
}
}
/* Detach a fiber from the env if the target fiber has stopped mutating */
void janet_env_maybe_detach(JanetFuncEnv *env) {
/* Check for detachable closure envs */
janet_env_valid(env);
if (env->offset > 0) {
JanetFiberStatus s = janet_fiber_status(env->as.fiber);
int isFinished = s == JANET_STATUS_DEAD ||
s == JANET_STATUS_ERROR ||
s == JANET_STATUS_USER0 ||
s == JANET_STATUS_USER1 ||
s == JANET_STATUS_USER2 ||
s == JANET_STATUS_USER3 ||
s == JANET_STATUS_USER4;
if (isFinished) {
janet_env_detach(env);
}
}
}
/* Create a tail frame for a function */
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
int32_t i;
@@ -198,14 +319,22 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
int32_t next_arity = fiber->stacktop - fiber->stackstart;
int32_t stacksize;
/* Check strict arity before messing with state */
if (next_arity < func->def->min_arity) return 1;
if (next_arity > func->def->max_arity) return 1;
if (fiber->capacity < nextstacktop) {
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
#ifdef JANET_DEBUG
} else {
janet_fiber_refresh_memory(fiber);
#endif
}
Janet *stack = fiber->data + fiber->frame;
Janet *args = fiber->data + fiber->stackstart;
/* Detatch old function */
/* Detach old function */
if (NULL != janet_fiber_frame(fiber)->func)
janet_env_detach(janet_fiber_frame(fiber)->env);
janet_fiber_frame(fiber)->env = NULL;
@@ -213,14 +342,21 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
/* Check varargs */
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
int32_t tuplehead = fiber->stackstart + func->def->arity;
int st = func->def->flags & JANET_FUNCDEF_FLAG_STRUCTARG;
if (tuplehead >= fiber->stacktop) {
if (tuplehead >= fiber->capacity) janet_fiber_setcapacity(fiber, 2 * (tuplehead + 1));
for (i = fiber->stacktop; i < tuplehead; ++i) fiber->data[i] = janet_wrap_nil();
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
fiber->data[tuplehead] = st
? make_struct_n(NULL, 0)
: janet_wrap_tuple(janet_tuple_n(NULL, 0));
} else {
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
fiber->stacktop - tuplehead));
fiber->data[tuplehead] = st
? make_struct_n(
fiber->data + tuplehead,
fiber->stacktop - tuplehead)
: janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
fiber->stacktop - tuplehead));
}
stacksize = tuplehead - fiber->stackstart + 1;
} else {
@@ -241,13 +377,6 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
janet_fiber_frame(fiber)->pc = func->def->bytecode;
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_TAILCALL;
/* Check strict arity AFTER getting fiber to valid state. */
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
if (func->def->arity != next_arity) {
return 1;
}
}
/* Good return */
return 0;
}
@@ -262,6 +391,10 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) {
if (fiber->capacity < nextstacktop) {
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
#ifdef JANET_DEBUG
} else {
janet_fiber_refresh_memory(fiber);
#endif
}
/* Set the next frame */
@@ -292,34 +425,59 @@ void janet_fiber_popframe(JanetFiber *fiber) {
fiber->frame = frame->prevframe;
}
JanetFiberStatus janet_fiber_status(JanetFiber *f) {
return ((f)->flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
}
JanetFiber *janet_current_fiber(void) {
return janet_vm_fiber;
}
JanetFiber *janet_root_fiber(void) {
return janet_vm_root_fiber;
}
/* CFuns */
static int cfun_new(JanetArgs args) {
JanetFiber *fiber;
JanetFunction *func;
JANET_MINARITY(args, 1);
JANET_MAXARITY(args, 2);
JANET_ARG_FUNCTION(func, args, 0);
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
if (func->def->arity != 0) {
JANET_THROW(args, "expected nullary function in fiber constructor");
}
static Janet cfun_fiber_getenv(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return fiber->env ?
janet_wrap_table(fiber->env) :
janet_wrap_nil();
}
static Janet cfun_fiber_setenv(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
if (janet_checktype(argv[1], JANET_NIL)) {
fiber->env = NULL;
} else {
fiber->env = janet_gettable(argv, 1);
}
fiber = janet_fiber(func, 64);
if (args.n == 2) {
const uint8_t *flags;
int32_t len, i;
JANET_ARG_BYTES(flags, len, args, 1);
fiber->flags = 0;
return argv[0];
}
static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetFunction *func = janet_getfunction(argv, 0);
JanetFiber *fiber;
if (func->def->min_arity > 1) {
janet_panicf("fiber function must accept 0 or 1 arguments");
}
fiber = janet_fiber(func, 64, func->def->min_arity, NULL);
if (argc == 2) {
int32_t i;
JanetByteView view = janet_getbytes(argv, 1);
fiber->flags = JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
for (i = 0; i < len; i++) {
if (flags[i] >= '0' && flags[i] <= '9') {
fiber->flags |= JANET_FIBER_MASK_USERN(flags[i] - '0');
for (i = 0; i < view.len; i++) {
if (view.bytes[i] >= '0' && view.bytes[i] <= '9') {
fiber->flags |= JANET_FIBER_MASK_USERN(view.bytes[i] - '0');
} else {
switch (flags[i]) {
switch (view.bytes[i]) {
default:
JANET_THROW(args, "invalid flag, expected a, d, e, u, or y");
case ':':
janet_panicf("invalid flag %c, expected a, t, d, e, u, y, i, or p", view.bytes[i]);
break;
case 'a':
fiber->flags |=
@@ -328,6 +486,15 @@ static int cfun_new(JanetArgs args) {
JANET_FIBER_MASK_USER |
JANET_FIBER_MASK_YIELD;
break;
case 't':
fiber->flags |=
JANET_FIBER_MASK_ERROR |
JANET_FIBER_MASK_USER0 |
JANET_FIBER_MASK_USER1 |
JANET_FIBER_MASK_USER2 |
JANET_FIBER_MASK_USER3 |
JANET_FIBER_MASK_USER4;
break;
case 'd':
fiber->flags |= JANET_FIBER_MASK_DEBUG;
break;
@@ -340,97 +507,157 @@ static int cfun_new(JanetArgs args) {
case 'y':
fiber->flags |= JANET_FIBER_MASK_YIELD;
break;
case 'i':
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(0);
}
fiber->env = janet_vm_fiber->env;
break;
case 'p':
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(0);
}
fiber->env = janet_table(0);
fiber->env->proto = janet_vm_fiber->env;
break;
}
}
}
}
JANET_RETURN_FIBER(args, fiber);
return janet_wrap_fiber(fiber);
}
static int cfun_status(JanetArgs args) {
JanetFiber *fiber;
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
JANET_FIBER_STATUS_OFFSET;
JANET_RETURN_CSYMBOL(args, janet_status_names[s]);
static Janet cfun_fiber_status(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
uint32_t s = janet_fiber_status(fiber);
return janet_ckeywordv(janet_status_names[s]);
}
static int cfun_current(JanetArgs args) {
JANET_FIXARITY(args, 0);
JANET_RETURN_FIBER(args, janet_vm_fiber);
static Janet cfun_fiber_current(int32_t argc, Janet *argv) {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_fiber(janet_vm_fiber);
}
static int cfun_maxstack(JanetArgs args) {
JanetFiber *fiber;
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
JANET_RETURN_INTEGER(args, fiber->maxstack);
static Janet cfun_fiber_root(int32_t argc, Janet *argv) {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_fiber(janet_vm_root_fiber);
}
static int cfun_setmaxstack(JanetArgs args) {
JanetFiber *fiber;
int32_t maxs;
JANET_FIXARITY(args, 2);
JANET_ARG_FIBER(fiber, args, 0);
JANET_ARG_INTEGER(maxs, args, 1);
static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return janet_wrap_integer(fiber->maxstack);
}
static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
int32_t maxs = janet_getinteger(argv, 1);
if (maxs < 0) {
JANET_THROW(args, "expected positive integer");
janet_panic("expected positive integer");
}
fiber->maxstack = maxs;
JANET_RETURN_FIBER(args, fiber);
return argv[0];
}
static const JanetReg cfuns[] = {
{"fiber/new", cfun_new,
"(fiber/new func [,sigmask])\n\n"
"Create a new fiber with function body func. Can optionally "
"take a set of signals to block from the current parent fiber "
"when called. The mask is specified as a symbol where each character "
"is used to indicate a signal to block. The default sigmask is :y. "
"For example, \n\n"
"\t(fiber/new myfun :e123)\n\n"
"blocks error signals and user signals 1, 2 and 3. The signals are "
"as follows: \n\n"
"\ta - block all signals\n"
"\td - block debug signals\n"
"\te - block error signals\n"
"\tu - block user signals\n"
"\ty - block yield signals\n"
"\t0-9 - block a specific user signal"
static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetFiberStatus s = janet_fiber_status(fiber);
int isFinished = s == JANET_STATUS_DEAD ||
s == JANET_STATUS_ERROR ||
s == JANET_STATUS_USER0 ||
s == JANET_STATUS_USER1 ||
s == JANET_STATUS_USER2 ||
s == JANET_STATUS_USER3 ||
s == JANET_STATUS_USER4;
return janet_wrap_boolean(!isFinished);
}
static const JanetReg fiber_cfuns[] = {
{
"fiber/new", cfun_fiber_new,
JDOC("(fiber/new func &opt sigmask)\n\n"
"Create a new fiber with function body func. Can optionally "
"take a set of signals to block from the current parent fiber "
"when called. The mask is specified as a keyword where each character "
"is used to indicate a signal to block. The default sigmask is :y. "
"For example, \n\n"
"\t(fiber/new myfun :e123)\n\n"
"blocks error signals and user signals 1, 2 and 3. The signals are "
"as follows: \n\n"
"\ta - block all signals\n"
"\td - block debug signals\n"
"\te - block error signals\n"
"\tt - block termination signals: error + user[0-4]\n"
"\tu - block user signals\n"
"\ty - block yield signals\n"
"\t0-9 - block a specific user signal\n\n"
"The sigmask argument also can take environment flags. If any mutually "
"exclusive flags are present, the last flag takes precedence.\n\n"
"\ti - inherit the environment from the current fiber\n"
"\tp - the environment table's prototype is the current environment table")
},
{"fiber/status", cfun_status,
"(fiber/status fib)\n\n"
"Get the status of a fiber. The status will be one of:\n\n"
"\t:dead - the fiber has finished\n"
"\t:error - the fiber has errored out\n"
"\t:debug - the fiber is suspended in debug mode\n"
"\t:pending - the fiber has been yielded\n"
"\t:user(0-9) - the fiber is suspended by a user signal\n"
"\t:alive - the fiber is currently running and cannot be resumed\n"
"\t:new - the fiber has just been created and not yet run"
{
"fiber/status", cfun_fiber_status,
JDOC("(fiber/status fib)\n\n"
"Get the status of a fiber. The status will be one of:\n\n"
"\t:dead - the fiber has finished\n"
"\t:error - the fiber has errored out\n"
"\t:debug - the fiber is suspended in debug mode\n"
"\t:pending - the fiber has been yielded\n"
"\t:user(0-9) - the fiber is suspended by a user signal\n"
"\t:alive - the fiber is currently running and cannot be resumed\n"
"\t:new - the fiber has just been created and not yet run")
},
{"fiber/current", cfun_current,
"(fiber/current)\n\n"
"Returns the currently running fiber."
{
"fiber/root", cfun_fiber_root,
JDOC("(fiber/root)\n\n"
"Returns the current root fiber. The root fiber is the oldest ancestor "
"that does not have a parent.")
},
{"fiber/maxstack", cfun_maxstack,
"(fiber/maxstack fib)\n\n"
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
"the fiber's stack is not allocated up front, the fiber will not allocated more "
"than this amount and will throw a stackoverflow error if more memory is needed. "
{
"fiber/current", cfun_fiber_current,
JDOC("(fiber/current)\n\n"
"Returns the currently running fiber.")
},
{"fiber/setmaxstack", cfun_setmaxstack,
"(fiber/setmaxstack fib maxstack)\n\n"
"Sets the maximum stack size in janet values for a fiber. By default, the "
"maximum stacksize is usually 8192."
{
"fiber/maxstack", cfun_fiber_maxstack,
JDOC("(fiber/maxstack fib)\n\n"
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
"the fiber's stack is not allocated up front, the fiber will not allocated more "
"than this amount and will throw a stack-overflow error if more memory is needed. ")
},
{
"fiber/setmaxstack", cfun_fiber_setmaxstack,
JDOC("(fiber/setmaxstack fib maxstack)\n\n"
"Sets the maximum stack size in janet values for a fiber. By default, the "
"maximum stack size is usually 8192.")
},
{
"fiber/getenv", cfun_fiber_getenv,
JDOC("(fiber/getenv fiber)\n\n"
"Gets the environment for a fiber. Returns nil if no such table is "
"set yet.")
},
{
"fiber/setenv", cfun_fiber_setenv,
JDOC("(fiber/setenv fiber table)\n\n"
"Sets the environment table for a fiber. Set to nil to remove the current "
"environment.")
},
{
"fiber/can-resume?", cfun_fiber_can_resume,
JDOC("(fiber/can-resume? fiber)\n\n"
"Check if a fiber is finished and cannot be resumed.")
},
{NULL, NULL, NULL}
};
/* Module entry point */
int janet_lib_fiber(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
return 0;
void janet_lib_fiber(JanetTable *env) {
janet_core_cfuns(env, NULL, fiber_cfuns);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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,7 +23,38 @@
#ifndef JANET_FIBER_H_defined
#define JANET_FIBER_H_defined
#include <janet/janet.h>
#ifndef JANET_AMALG
#include <janet.h>
#endif
/* Fiber signal masks. */
#define JANET_FIBER_MASK_ERROR 2
#define JANET_FIBER_MASK_DEBUG 4
#define JANET_FIBER_MASK_YIELD 8
#define JANET_FIBER_MASK_USER0 (16 << 0)
#define JANET_FIBER_MASK_USER1 (16 << 1)
#define JANET_FIBER_MASK_USER2 (16 << 2)
#define JANET_FIBER_MASK_USER3 (16 << 3)
#define JANET_FIBER_MASK_USER4 (16 << 4)
#define JANET_FIBER_MASK_USER5 (16 << 5)
#define JANET_FIBER_MASK_USER6 (16 << 6)
#define JANET_FIBER_MASK_USER7 (16 << 7)
#define JANET_FIBER_MASK_USER8 (16 << 8)
#define JANET_FIBER_MASK_USER9 (16 << 9)
#define JANET_FIBER_MASK_USERN(N) (16 << (N))
#define JANET_FIBER_MASK_USER 0x3FF0
#define JANET_FIBER_RESUME_SIGNAL 0x800000
#define JANET_FIBER_STATUS_MASK 0x7F0000
#define JANET_FIBER_STATUS_OFFSET 16
#define JANET_FIBER_BREAKPOINT 0x1000000
#define JANET_FIBER_RESUME_NO_USEVAL 0x2000000
#define JANET_FIBER_RESUME_NO_SKIP 0x4000000
#define JANET_FIBER_DID_LONGJUMP 0x8000000
#define JANET_FIBER_FLAG_MASK 0xF000000
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
@@ -43,5 +74,7 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func);
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func);
void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun);
void janet_fiber_popframe(JanetFiber *fiber);
void janet_env_maybe_detach(JanetFuncEnv *env);
int janet_env_valid(JanetFuncEnv *env);
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,21 +20,37 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "state.h"
#include "symcache.h"
#include "gc.h"
#include "util.h"
#include "fiber.h"
#endif
struct JanetScratch {
JanetScratchFinalizer finalize;
long long mem[]; /* for proper alignment */
};
/* GC State */
JANET_THREAD_LOCAL void *janet_vm_blocks;
JANET_THREAD_LOCAL uint32_t janet_vm_gc_interval;
JANET_THREAD_LOCAL uint32_t janet_vm_next_collection;
JANET_THREAD_LOCAL size_t janet_vm_gc_interval;
JANET_THREAD_LOCAL size_t janet_vm_next_collection;
JANET_THREAD_LOCAL size_t janet_vm_block_count;
JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0;
/* Roots */
JANET_THREAD_LOCAL Janet *janet_vm_roots;
JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
JANET_THREAD_LOCAL size_t janet_vm_root_count;
JANET_THREAD_LOCAL size_t janet_vm_root_capacity;
/* Scratch Memory */
JANET_THREAD_LOCAL JanetScratch **janet_scratch_mem;
JANET_THREAD_LOCAL size_t janet_scratch_cap;
JANET_THREAD_LOCAL size_t janet_scratch_len;
/* Helpers for marking the various gc types */
static void janet_mark_funcenv(JanetFuncEnv *env);
@@ -49,26 +65,51 @@ static void janet_mark_string(const uint8_t *str);
static void janet_mark_fiber(JanetFiber *fiber);
static void janet_mark_abstract(void *adata);
/* Local state that is only temporary */
/* Local state that is only temporary for gc */
static JANET_THREAD_LOCAL uint32_t depth = JANET_RECURSION_GUARD;
static JANET_THREAD_LOCAL uint32_t orig_rootcount;
static JANET_THREAD_LOCAL size_t orig_rootcount;
/* Hint to the GC that we may need to collect */
void janet_gcpressure(size_t s) {
janet_vm_next_collection += s;
}
/* Mark a value */
void janet_mark(Janet x) {
if (depth) {
depth--;
switch (janet_type(x)) {
default: break;
default:
break;
case JANET_STRING:
case JANET_SYMBOL: janet_mark_string(janet_unwrap_string(x)); break;
case JANET_FUNCTION: janet_mark_function(janet_unwrap_function(x)); break;
case JANET_ARRAY: janet_mark_array(janet_unwrap_array(x)); break;
case JANET_TABLE: janet_mark_table(janet_unwrap_table(x)); break;
case JANET_STRUCT: janet_mark_struct(janet_unwrap_struct(x)); break;
case JANET_TUPLE: janet_mark_tuple(janet_unwrap_tuple(x)); break;
case JANET_BUFFER: janet_mark_buffer(janet_unwrap_buffer(x)); break;
case JANET_FIBER: janet_mark_fiber(janet_unwrap_fiber(x)); break;
case JANET_ABSTRACT: janet_mark_abstract(janet_unwrap_abstract(x)); break;
case JANET_KEYWORD:
case JANET_SYMBOL:
janet_mark_string(janet_unwrap_string(x));
break;
case JANET_FUNCTION:
janet_mark_function(janet_unwrap_function(x));
break;
case JANET_ARRAY:
janet_mark_array(janet_unwrap_array(x));
break;
case JANET_TABLE:
janet_mark_table(janet_unwrap_table(x));
break;
case JANET_STRUCT:
janet_mark_struct(janet_unwrap_struct(x));
break;
case JANET_TUPLE:
janet_mark_tuple(janet_unwrap_tuple(x));
break;
case JANET_BUFFER:
janet_mark_buffer(janet_unwrap_buffer(x));
break;
case JANET_FIBER:
janet_mark_fiber(janet_unwrap_fiber(x));
break;
case JANET_ABSTRACT:
janet_mark_abstract(janet_unwrap_abstract(x));
break;
}
depth++;
} else {
@@ -77,7 +118,7 @@ void janet_mark(Janet x) {
}
static void janet_mark_string(const uint8_t *str) {
janet_gc_mark(janet_string_raw(str));
janet_gc_mark(janet_string_head(str));
}
static void janet_mark_buffer(JanetBuffer *buffer) {
@@ -85,11 +126,11 @@ static void janet_mark_buffer(JanetBuffer *buffer) {
}
static void janet_mark_abstract(void *adata) {
if (janet_gc_reachable(janet_abstract_header(adata)))
if (janet_gc_reachable(janet_abstract_head(adata)))
return;
janet_gc_mark(janet_abstract_header(adata));
if (janet_abstract_header(adata)->type->gcmark) {
janet_abstract_header(adata)->type->gcmark(adata, janet_abstract_size(adata));
janet_gc_mark(janet_abstract_head(adata));
if (janet_abstract_head(adata)->type->gcmark) {
janet_abstract_head(adata)->type->gcmark(adata, janet_abstract_size(adata));
}
}
@@ -120,7 +161,7 @@ static void janet_mark_array(JanetArray *array) {
}
static void janet_mark_table(JanetTable *table) {
recur: /* Manual tail recursion */
recur: /* Manual tail recursion */
if (janet_gc_reachable(table))
return;
janet_gc_mark(table);
@@ -132,16 +173,16 @@ static void janet_mark_table(JanetTable *table) {
}
static void janet_mark_struct(const JanetKV *st) {
if (janet_gc_reachable(janet_struct_raw(st)))
if (janet_gc_reachable(janet_struct_head(st)))
return;
janet_gc_mark(janet_struct_raw(st));
janet_gc_mark(janet_struct_head(st));
janet_mark_kvs(st, janet_struct_capacity(st));
}
static void janet_mark_tuple(const Janet *tuple) {
if (janet_gc_reachable(janet_tuple_raw(tuple)))
if (janet_gc_reachable(janet_tuple_head(tuple)))
return;
janet_gc_mark(janet_tuple_raw(tuple));
janet_gc_mark(janet_tuple_head(tuple));
janet_mark_many(tuple, janet_tuple_length(tuple));
}
@@ -150,7 +191,10 @@ static void janet_mark_funcenv(JanetFuncEnv *env) {
if (janet_gc_reachable(env))
return;
janet_gc_mark(env);
if (env->offset) {
/* If closure env references a dead fiber, we can just copy out the stack frame we need so
* we don't need to keep around the whole dead fiber. */
janet_env_maybe_detach(env);
if (env->offset > 0) {
/* On stack */
janet_mark_fiber(env->as.fiber);
} else {
@@ -195,6 +239,11 @@ recur:
if (janet_gc_reachable(fiber))
return;
janet_gc_mark(fiber);
/* Mark values on the argument stack */
janet_mark_many(fiber->data + fiber->stackstart,
fiber->stacktop - fiber->stackstart);
i = fiber->frame;
j = fiber->stackstart - JANET_FRAME_SIZE;
while (i > 0) {
@@ -209,6 +258,9 @@ recur:
i = frame->prevframe;
}
if (fiber->env)
janet_mark_table(fiber->env);
/* Explicit tail recursion */
if (fiber->child) {
fiber = fiber->child;
@@ -217,21 +269,19 @@ recur:
}
/* Deinitialize a block of memory */
static void janet_deinit_block(JanetGCMemoryHeader *block) {
void *mem = ((char *)(block + 1));
JanetAbstractHeader *h = (JanetAbstractHeader *)mem;
switch (block->flags & JANET_MEM_TYPEBITS) {
static void janet_deinit_block(JanetGCObject *mem) {
switch (mem->flags & JANET_MEM_TYPEBITS) {
default:
case JANET_MEMORY_FUNCTION:
break; /* Do nothing for non gc types */
case JANET_MEMORY_SYMBOL:
janet_symbol_deinit((const uint8_t *)mem + 2 * sizeof(int32_t));
janet_symbol_deinit(((JanetStringHead *) mem)->data);
break;
case JANET_MEMORY_ARRAY:
janet_array_deinit((JanetArray*) mem);
free(((JanetArray *) mem)->data);
break;
case JANET_MEMORY_TABLE:
janet_table_deinit((JanetTable*) mem);
free(((JanetTable *) mem)->data);
break;
case JANET_MEMORY_FIBER:
free(((JanetFiber *)mem)->data);
@@ -239,44 +289,46 @@ static void janet_deinit_block(JanetGCMemoryHeader *block) {
case JANET_MEMORY_BUFFER:
janet_buffer_deinit((JanetBuffer *) mem);
break;
case JANET_MEMORY_ABSTRACT:
if (h->type->gc) {
janet_assert(!h->type->gc((void *)(h + 1), h->size), "finalizer failed");
case JANET_MEMORY_ABSTRACT: {
JanetAbstractHead *head = (JanetAbstractHead *)mem;
if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
}
break;
case JANET_MEMORY_FUNCENV:
{
JanetFuncEnv *env = (JanetFuncEnv *)mem;
if (0 == env->offset)
free(env->as.values);
}
break;
case JANET_MEMORY_FUNCDEF:
{
JanetFuncDef *def = (JanetFuncDef *)mem;
/* TODO - get this all with one alloc and one free */
free(def->defs);
free(def->environments);
free(def->constants);
free(def->bytecode);
free(def->sourcemap);
}
break;
}
break;
case JANET_MEMORY_FUNCENV: {
JanetFuncEnv *env = (JanetFuncEnv *)mem;
if (0 == env->offset)
free(env->as.values);
}
break;
case JANET_MEMORY_FUNCDEF: {
JanetFuncDef *def = (JanetFuncDef *)mem;
/* TODO - get this all with one alloc and one free */
free(def->defs);
free(def->environments);
free(def->constants);
free(def->bytecode);
free(def->sourcemap);
free(def->closure_bitset);
}
break;
}
}
/* Iterate over all allocated memory, and free memory that is not
* marked as reachable. Flip the gc color flag for next sweep. */
void janet_sweep() {
JanetGCMemoryHeader *previous = NULL;
JanetGCMemoryHeader *current = janet_vm_blocks;
JanetGCMemoryHeader *next;
JanetGCObject *previous = NULL;
JanetGCObject *current = janet_vm_blocks;
JanetGCObject *next;
while (NULL != current) {
next = current->next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
previous = current;
current->flags &= ~JANET_MEM_REACHABLE;
} else {
janet_vm_block_count--;
janet_deinit_block(current);
if (NULL != previous) {
previous->next = next;
@@ -291,29 +343,47 @@ void janet_sweep() {
/* Allocate some memory that is tracked for garbage collection */
void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
JanetGCMemoryHeader *mdata;
size_t total = size + sizeof(JanetGCMemoryHeader);
JanetGCObject *mem;
/* Make sure everything is inited */
janet_assert(NULL != janet_vm_cache, "please initialize janet before use");
void *mem = malloc(total);
mem = malloc(size);
/* Check for bad malloc */
if (NULL == mem) {
JANET_OUT_OF_MEMORY;
}
mdata = (JanetGCMemoryHeader *)mem;
/* Configure block */
mdata->flags = type;
mem->flags = type;
/* Prepend block to heap list */
janet_vm_next_collection += (int32_t) size;
mdata->next = janet_vm_blocks;
janet_vm_blocks = mdata;
janet_vm_next_collection += size;
mem->next = janet_vm_blocks;
janet_vm_blocks = mem;
janet_vm_block_count++;
return (char *) mem + sizeof(JanetGCMemoryHeader);
return (void *)mem;
}
static void free_one_scratch(JanetScratch *s) {
if (NULL != s->finalize) {
s->finalize((char *) s->mem);
}
free(s);
}
/* Free all allocated scratch memory */
static void janet_free_all_scratch(void) {
for (size_t i = 0; i < janet_scratch_len; i++) {
free_one_scratch(janet_scratch_mem[i]);
}
janet_scratch_len = 0;
}
static JanetScratch *janet_mem2scratch(void *mem) {
JanetScratch *s = (JanetScratch *)mem;
return s - 1;
}
/* Run garbage collection */
@@ -321,7 +391,18 @@ void janet_collect(void) {
uint32_t i;
if (janet_vm_gc_suspend) return;
depth = JANET_RECURSION_GUARD;
/* Try and prevent many major collections back to back.
* A full collection will take O(janet_vm_block_count) time.
* If we have a large heap, make sure our interval is not too
* small so we won't make many collections over it. This is just a
* heuristic for automatically changing the gc interval */
if (janet_vm_block_count * 8 > janet_vm_gc_interval) {
janet_vm_gc_interval = janet_vm_block_count * sizeof(JanetGCObject);
}
orig_rootcount = janet_vm_root_count;
#ifdef JANET_NET
janet_net_markloop();
#endif
for (i = 0; i < orig_rootcount; i++)
janet_mark(janet_vm_roots[i]);
while (orig_rootcount < janet_vm_root_count) {
@@ -330,15 +411,16 @@ void janet_collect(void) {
}
janet_sweep();
janet_vm_next_collection = 0;
janet_free_all_scratch();
}
/* Add a root value to the GC. This prevents the GC from removing a value
* and all of its children. If gcroot is called on a value n times, unroot
* must also be called n times to remove it as a gc root. */
void janet_gcroot(Janet root) {
uint32_t newcount = janet_vm_root_count + 1;
size_t newcount = janet_vm_root_count + 1;
if (newcount > janet_vm_root_capacity) {
uint32_t newcap = 2 * newcount;
size_t newcap = 2 * newcount;
janet_vm_roots = realloc(janet_vm_roots, sizeof(Janet) * newcap);
if (NULL == janet_vm_roots) {
JANET_OUT_OF_MEMORY;
@@ -354,14 +436,11 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
if (janet_type(lhs) != janet_type(rhs))
return 0;
switch (janet_type(lhs)) {
case JANET_TRUE:
case JANET_FALSE:
case JANET_BOOLEAN:
case JANET_NIL:
case JANET_NUMBER:
/* These values don't really matter to the gc so returning 1 all the time is fine. */
return 1;
case JANET_INTEGER:
return janet_unwrap_integer(lhs) == janet_unwrap_integer(rhs);
case JANET_REAL:
return janet_unwrap_real(lhs) == janet_unwrap_real(rhs);
default:
return janet_unwrap_pointer(lhs) == janet_unwrap_pointer(rhs);
}
@@ -371,9 +450,8 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
* a value and all its children. */
int janet_gcunroot(Janet root) {
Janet *vtop = janet_vm_roots + janet_vm_root_count;
Janet *v = janet_vm_roots;
/* Search from top to bottom as access is most likely LIFO */
for (v = janet_vm_roots; v < vtop; v++) {
for (Janet *v = janet_vm_roots; v < vtop; v++) {
if (janet_gc_idequals(root, *v)) {
*v = janet_vm_roots[--janet_vm_root_count];
return 1;
@@ -385,10 +463,9 @@ int janet_gcunroot(Janet root) {
/* Remove a root value from the GC. This sets the effective reference count to 0. */
int janet_gcunrootall(Janet root) {
Janet *vtop = janet_vm_roots + janet_vm_root_count;
Janet *v = janet_vm_roots;
int ret = 0;
/* Search from top to bottom as access is most likely LIFO */
for (v = janet_vm_roots; v < vtop; v++) {
for (Janet *v = janet_vm_roots; v < vtop; v++) {
if (janet_gc_idequals(root, *v)) {
*v = janet_vm_roots[--janet_vm_root_count];
vtop--;
@@ -400,16 +477,93 @@ int janet_gcunrootall(Janet root) {
/* Free all allocated memory */
void janet_clear_memory(void) {
JanetGCMemoryHeader *current = janet_vm_blocks;
JanetGCObject *current = janet_vm_blocks;
while (NULL != current) {
janet_deinit_block(current);
JanetGCMemoryHeader *next = current->next;
JanetGCObject *next = current->next;
free(current);
current = next;
}
janet_vm_blocks = NULL;
janet_free_all_scratch();
free(janet_scratch_mem);
}
/* Primitives for suspending GC. */
int janet_gclock(void) { return janet_vm_gc_suspend++; }
void janet_gcunlock(int handle) { janet_vm_gc_suspend = handle; }
int janet_gclock(void) {
return janet_vm_gc_suspend++;
}
void janet_gcunlock(int handle) {
janet_vm_gc_suspend = handle;
}
/* Scratch memory API */
void *janet_smalloc(size_t size) {
JanetScratch *s = malloc(sizeof(JanetScratch) + size);
if (NULL == s) {
JANET_OUT_OF_MEMORY;
}
s->finalize = NULL;
if (janet_scratch_len == janet_scratch_cap) {
size_t newcap = 2 * janet_scratch_cap + 2;
JanetScratch **newmem = (JanetScratch **) realloc(janet_scratch_mem, newcap * sizeof(JanetScratch));
if (NULL == newmem) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_cap = newcap;
janet_scratch_mem = newmem;
}
janet_scratch_mem[janet_scratch_len++] = s;
return (char *)(s->mem);
}
void *janet_scalloc(size_t nmemb, size_t size) {
if (nmemb && size > SIZE_MAX / nmemb) {
JANET_OUT_OF_MEMORY;
}
size_t n = nmemb * size;
void *p = janet_smalloc(n);
memset(p, 0, n);
return p;
}
void *janet_srealloc(void *mem, size_t size) {
if (NULL == mem) return janet_smalloc(size);
JanetScratch *s = janet_mem2scratch(mem);
if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == s) {
JanetScratch *news = realloc(s, size + sizeof(JanetScratch));
if (NULL == news) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_mem[i] = news;
return (char *)(news->mem);
}
if (i == 0) break;
}
}
JANET_EXIT("invalid janet_srealloc");
}
void janet_sfinalizer(void *mem, JanetScratchFinalizer finalizer) {
JanetScratch *s = janet_mem2scratch(mem);
s->finalize = finalizer;
}
void janet_sfree(void *mem) {
if (NULL == mem) return;
JanetScratch *s = janet_mem2scratch(mem);
if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == s) {
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
free_one_scratch(s);
return;
}
if (i == 0) break;
}
}
JANET_EXIT("invalid janet_sfree");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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,10 +23,13 @@
#ifndef JANET_GC_H
#define JANET_GC_H
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#endif
/* The metadata header associated with an allocated block of memory */
#define janet_gc_header(mem) ((JanetGCMemoryHeader *)(mem) - 1)
#define janet_gc_header(mem) ((JanetGCObject *)(mem))
#define JANET_MEM_TYPEBITS 0xFF
#define JANET_MEM_REACHABLE 0x100
@@ -36,16 +39,8 @@
#define janet_gc_type(m) (janet_gc_header(m)->flags & 0xFF)
#define janet_gc_mark(m) (janet_gc_header(m)->flags |= JANET_MEM_REACHABLE)
#define janet_gc_unmark(m) (janet_gc_header(m)->flags &= ~JANET_MEM_COLOR)
#define janet_gc_reachable(m) (janet_gc_header(m)->flags & JANET_MEM_REACHABLE)
/* Memory header struct. Node of a linked list of memory blocks. */
typedef struct JanetGCMemoryHeader JanetGCMemoryHeader;
struct JanetGCMemoryHeader {
JanetGCMemoryHeader *next;
uint32_t flags;
};
/* Memory types for the GC. Different from JanetType to include funcenv and funcdef. */
enum JanetMemoryType {
JANET_MEMORY_NONE,

534
src/core/inttypes.c Normal file
View File

@@ -0,0 +1,534 @@
/*
* Copyright (c) 2020 Calvin Rose & contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "util.h"
#endif
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <inttypes.h>
#include <math.h>
/* Conditional compilation */
#ifdef JANET_INT_TYPES
#define MAX_INT_IN_DBL 9007199254740992ULL /* 2^53 */
static int it_s64_get(void *p, Janet key, Janet *out);
static int it_u64_get(void *p, Janet key, Janet *out);
static int32_t janet_int64_hash(void *p1, size_t size) {
(void) size;
int32_t *words = p1;
return words[0] ^ words[1];
}
static int janet_int64_compare(void *p1, void *p2) {
int64_t x = *((int64_t *)p1);
int64_t y = *((int64_t *)p2);
return x == y ? 0 : x < y ? -1 : 1;
}
static int janet_uint64_compare(void *p1, void *p2) {
uint64_t x = *((uint64_t *)p1);
uint64_t y = *((uint64_t *)p2);
return x == y ? 0 : x < y ? -1 : 1;
}
static void int64_marshal(void *p, JanetMarshalContext *ctx) {
janet_marshal_abstract(ctx, p);
janet_marshal_int64(ctx, *((int64_t *)p));
}
static void *int64_unmarshal(JanetMarshalContext *ctx) {
int64_t *p = janet_unmarshal_abstract(ctx, sizeof(int64_t));
p[0] = janet_unmarshal_int64(ctx);
return p;
}
static void it_s64_tostring(void *p, JanetBuffer *buffer) {
char str[32];
sprintf(str, "%" PRId64, *((int64_t *)p));
janet_buffer_push_cstring(buffer, str);
}
static void it_u64_tostring(void *p, JanetBuffer *buffer) {
char str[32];
sprintf(str, "%" PRIu64, *((uint64_t *)p));
janet_buffer_push_cstring(buffer, str);
}
const JanetAbstractType janet_s64_type = {
"core/s64",
NULL,
NULL,
it_s64_get,
NULL,
int64_marshal,
int64_unmarshal,
it_s64_tostring,
janet_int64_compare,
janet_int64_hash,
JANET_ATEND_HASH
};
const JanetAbstractType janet_u64_type = {
"core/u64",
NULL,
NULL,
it_u64_get,
NULL,
int64_marshal,
int64_unmarshal,
it_u64_tostring,
janet_uint64_compare,
janet_int64_hash,
JANET_ATEND_HASH
};
int64_t janet_unwrap_s64(Janet x) {
switch (janet_type(x)) {
default:
break;
case JANET_NUMBER : {
double dbl = janet_unwrap_number(x);
if (fabs(dbl) <= MAX_INT_IN_DBL)
return (int64_t)dbl;
break;
}
case JANET_STRING: {
int64_t value;
const uint8_t *str = janet_unwrap_string(x);
if (janet_scan_int64(str, janet_string_length(str), &value))
return value;
break;
}
case JANET_ABSTRACT: {
void *abst = janet_unwrap_abstract(x);
if (janet_abstract_type(abst) == &janet_s64_type ||
(janet_abstract_type(abst) == &janet_u64_type))
return *(int64_t *)abst;
break;
}
}
janet_panic("bad s64 initializer");
return 0;
}
uint64_t janet_unwrap_u64(Janet x) {
switch (janet_type(x)) {
default:
break;
case JANET_NUMBER : {
double dbl = janet_unwrap_number(x);
if ((dbl >= 0) && (dbl <= MAX_INT_IN_DBL))
return (uint64_t)dbl;
break;
}
case JANET_STRING: {
uint64_t value;
const uint8_t *str = janet_unwrap_string(x);
if (janet_scan_uint64(str, janet_string_length(str), &value))
return value;
break;
}
case JANET_ABSTRACT: {
void *abst = janet_unwrap_abstract(x);
if (janet_abstract_type(abst) == &janet_s64_type ||
(janet_abstract_type(abst) == &janet_u64_type))
return *(uint64_t *)abst;
break;
}
}
janet_panic("bad u64 initializer");
return 0;
}
JanetIntType janet_is_int(Janet x) {
if (!janet_checktype(x, JANET_ABSTRACT)) return JANET_INT_NONE;
const JanetAbstractType *at = janet_abstract_type(janet_unwrap_abstract(x));
return (at == &janet_s64_type) ? JANET_INT_S64 :
((at == &janet_u64_type) ? JANET_INT_U64 :
JANET_INT_NONE);
}
Janet janet_wrap_s64(int64_t x) {
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
*box = (int64_t)x;
return janet_wrap_abstract(box);
}
Janet janet_wrap_u64(uint64_t x) {
uint64_t *box = janet_abstract(&janet_u64_type, sizeof(uint64_t));
*box = (uint64_t)x;
return janet_wrap_abstract(box);
}
static Janet cfun_it_s64_new(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
return janet_wrap_s64(janet_unwrap_s64(argv[0]));
}
static Janet cfun_it_u64_new(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
return janet_wrap_u64(janet_unwrap_u64(argv[0]));
}
// Code to support polymorphic comparison.
//
// int/u64 and int/s64 support a "compare" method that allows
// comparison to each other, and to Janet numbers, using the
// "compare" "compare<" ... functions.
//
// In the following code explicit casts are sometimes used to help
// make it clear when int/float conversions are happening.
//
static int compare_double_double(double x, double y) {
return (x < y) ? -1 : ((x > y) ? 1 : 0);
}
static int compare_int64_double(int64_t x, double y) {
if (isnan(y)) {
return 0; // clojure and python do this
} else if ((y > (- ((double) MAX_INT_IN_DBL))) && (y < ((double) MAX_INT_IN_DBL))) {
double dx = (double) x;
return compare_double_double(dx, y);
} else if (y > ((double) INT64_MAX)) {
return -1;
} else if (y < ((double) INT64_MIN)) {
return 1;
} else {
int64_t yi = (int64_t) y;
return (x < yi) ? -1 : ((x > yi) ? 1 : 0);
}
}
static int compare_uint64_double(uint64_t x, double y) {
if (isnan(y)) {
return 0; // clojure and python do this
} else if (y < 0) {
return 1;
} else if ((y >= 0) && (y < ((double) MAX_INT_IN_DBL))) {
double dx = (double) x;
return compare_double_double(dx, y);
} else if (y > ((double) UINT64_MAX)) {
return -1;
} else {
uint64_t yi = (uint64_t) y;
return (x < yi) ? -1 : ((x > yi) ? 1 : 0);
}
}
static Janet cfun_it_s64_compare(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
if (janet_is_int(argv[0]) != JANET_INT_S64)
janet_panic("compare method requires int/s64 as first argument");
int64_t x = janet_unwrap_s64(argv[0]);
switch (janet_type(argv[1])) {
default:
break;
case JANET_NUMBER : {
double y = janet_unwrap_number(argv[1]);
return janet_wrap_number(compare_int64_double(x, y));
}
case JANET_ABSTRACT: {
void *abst = janet_unwrap_abstract(argv[1]);
if (janet_abstract_type(abst) == &janet_s64_type) {
int64_t y = *(int64_t *)abst;
return janet_wrap_number((x < y) ? -1 : (x > y ? 1 : 0));
} else if (janet_abstract_type(abst) == &janet_u64_type) {
// comparing signed to unsigned -- be careful!
uint64_t y = *(uint64_t *)abst;
if (x < 0) {
return janet_wrap_number(-1);
} else if (y > INT64_MAX) {
return janet_wrap_number(-1);
} else {
int64_t y2 = (int64_t) y;
return janet_wrap_number((x < y2) ? -1 : (x > y2 ? 1 : 0));
}
}
break;
}
}
return janet_wrap_nil();
}
static Janet cfun_it_u64_compare(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
if (janet_is_int(argv[0]) != JANET_INT_U64) // is this needed?
janet_panic("compare method requires int/u64 as first argument");
uint64_t x = janet_unwrap_u64(argv[0]);
switch (janet_type(argv[1])) {
default:
break;
case JANET_NUMBER : {
double y = janet_unwrap_number(argv[1]);
return janet_wrap_number(compare_uint64_double(x, y));
}
case JANET_ABSTRACT: {
void *abst = janet_unwrap_abstract(argv[1]);
if (janet_abstract_type(abst) == &janet_u64_type) {
uint64_t y = *(uint64_t *)abst;
return janet_wrap_number((x < y) ? -1 : (x > y ? 1 : 0));
} else if (janet_abstract_type(abst) == &janet_s64_type) {
// comparing unsigned to signed -- be careful!
int64_t y = *(int64_t *)abst;
if (y < 0) {
return janet_wrap_number(1);
} else if (x > INT64_MAX) {
return janet_wrap_number(1);
} else {
int64_t x2 = (int64_t) x;
return janet_wrap_number((x2 < y) ? -1 : (x2 > y ? 1 : 0));
}
}
break;
}
}
return janet_wrap_nil();
}
#define OPMETHOD(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_arity(argc, 2, -1); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[0]); \
for (int32_t i = 1; i < argc; i++) \
*box oper##= janet_unwrap_##type(argv[i]); \
return janet_wrap_abstract(box); \
} \
#define OPMETHODINVERT(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_fixarity(argc, 2); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[1]); \
*box oper##= janet_unwrap_##type(argv[0]); \
return janet_wrap_abstract(box); \
} \
#define DIVMETHOD(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_arity(argc, 2, -1); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[0]); \
for (int32_t i = 1; i < argc; i++) { \
T value = janet_unwrap_##type(argv[i]); \
if (value == 0) janet_panic("division by zero"); \
*box oper##= value; \
} \
return janet_wrap_abstract(box); \
} \
#define DIVMETHODINVERT(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_fixarity(argc, 2); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[1]); \
T value = janet_unwrap_##type(argv[0]); \
if (value == 0) janet_panic("division by zero"); \
*box oper##= value; \
return janet_wrap_abstract(box); \
} \
#define DIVMETHOD_SIGNED(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_arity(argc, 2, -1); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[0]); \
for (int32_t i = 1; i < argc; i++) { \
T value = janet_unwrap_##type(argv[i]); \
if (value == 0) janet_panic("division by zero"); \
if ((value == -1) && (*box == INT64_MIN)) janet_panic("INT64_MIN divided by -1"); \
*box oper##= value; \
} \
return janet_wrap_abstract(box); \
} \
#define DIVMETHODINVERT_SIGNED(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_fixarity(argc, 2); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = janet_unwrap_##type(argv[1]); \
T value = janet_unwrap_##type(argv[0]); \
if (value == 0) janet_panic("division by zero"); \
if ((value == -1) && (*box == INT64_MIN)) janet_panic("INT64_MIN divided by -1"); \
*box oper##= value; \
return janet_wrap_abstract(box); \
} \
static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
janet_arity(argc, 2, -1);
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
*box = janet_unwrap_s64(argv[0]);
for (int32_t i = 1; i < argc; i++) {
int64_t value = janet_unwrap_s64(argv[i]);
if (value == 0) janet_panic("division by zero");
int64_t x = *box % value;
if (x < 0) {
x = (*box < 0) ? x - *box : x + *box;
}
*box = x;
}
return janet_wrap_abstract(box);
}
static Janet cfun_it_s64_modi(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
int64_t op1 = janet_unwrap_s64(argv[0]);
int64_t op2 = janet_unwrap_s64(argv[1]);
int64_t x = op1 % op2;
if (x < 0) {
x = (op1 < 0) ? x - op1 : x + op1;
}
*box = x;
return janet_wrap_abstract(box);
}
OPMETHOD(int64_t, s64, add, +)
OPMETHOD(int64_t, s64, sub, -)
OPMETHODINVERT(int64_t, s64, subi, -)
OPMETHOD(int64_t, s64, mul, *)
DIVMETHOD_SIGNED(int64_t, s64, div, /)
DIVMETHOD_SIGNED(int64_t, s64, rem, %)
DIVMETHODINVERT_SIGNED(int64_t, s64, divi, /)
DIVMETHODINVERT_SIGNED(int64_t, s64, remi, %)
OPMETHOD(int64_t, s64, and, &)
OPMETHOD(int64_t, s64, or, |)
OPMETHOD(int64_t, s64, xor, ^)
OPMETHOD(int64_t, s64, lshift, <<)
OPMETHOD(int64_t, s64, rshift, >>)
OPMETHOD(uint64_t, u64, add, +)
OPMETHOD(uint64_t, u64, sub, -)
OPMETHODINVERT(uint64_t, u64, subi, -)
OPMETHOD(uint64_t, u64, mul, *)
DIVMETHOD(uint64_t, u64, div, /)
DIVMETHOD(uint64_t, u64, mod, %)
DIVMETHODINVERT(uint64_t, u64, divi, /)
DIVMETHODINVERT(uint64_t, u64, modi, %)
OPMETHOD(uint64_t, u64, and, &)
OPMETHOD(uint64_t, u64, or, |)
OPMETHOD(uint64_t, u64, xor, ^)
OPMETHOD(uint64_t, u64, lshift, <<)
OPMETHOD(uint64_t, u64, rshift, >>)
#undef OPMETHOD
#undef DIVMETHOD
#undef DIVMETHOD_SIGNED
#undef COMPMETHOD
static JanetMethod it_s64_methods[] = {
{"+", cfun_it_s64_add},
{"r+", cfun_it_s64_add},
{"-", cfun_it_s64_sub},
{"r-", cfun_it_s64_subi},
{"*", cfun_it_s64_mul},
{"r*", cfun_it_s64_mul},
{"/", cfun_it_s64_div},
{"r/", cfun_it_s64_divi},
{"mod", cfun_it_s64_mod},
{"rmod", cfun_it_s64_modi},
{"%", cfun_it_s64_rem},
{"r%", cfun_it_s64_remi},
{"&", cfun_it_s64_and},
{"r&", cfun_it_s64_and},
{"|", cfun_it_s64_or},
{"r|", cfun_it_s64_or},
{"^", cfun_it_s64_xor},
{"r^", cfun_it_s64_xor},
{"<<", cfun_it_s64_lshift},
{">>", cfun_it_s64_rshift},
{"compare", cfun_it_s64_compare},
{NULL, NULL}
};
static JanetMethod it_u64_methods[] = {
{"+", cfun_it_u64_add},
{"r+", cfun_it_u64_add},
{"-", cfun_it_u64_sub},
{"r-", cfun_it_u64_subi},
{"*", cfun_it_u64_mul},
{"r*", cfun_it_u64_mul},
{"/", cfun_it_u64_div},
{"r/", cfun_it_u64_divi},
{"mod", cfun_it_u64_mod},
{"rmod", cfun_it_u64_modi},
{"%", cfun_it_u64_mod},
{"r%", cfun_it_u64_modi},
{"&", cfun_it_u64_and},
{"r&", cfun_it_u64_and},
{"|", cfun_it_u64_or},
{"r|", cfun_it_u64_or},
{"^", cfun_it_u64_xor},
{"r^", cfun_it_u64_xor},
{"<<", cfun_it_u64_lshift},
{">>", cfun_it_u64_rshift},
{"compare", cfun_it_u64_compare},
{NULL, NULL}
};
static int it_s64_get(void *p, Janet key, Janet *out) {
(void) p;
if (!janet_checktype(key, JANET_KEYWORD))
return 0;
return janet_getmethod(janet_unwrap_keyword(key), it_s64_methods, out);
}
static int it_u64_get(void *p, Janet key, Janet *out) {
(void) p;
if (!janet_checktype(key, JANET_KEYWORD))
return 0;
return janet_getmethod(janet_unwrap_keyword(key), it_u64_methods, out);
}
static const JanetReg it_cfuns[] = {
{
"int/s64", cfun_it_s64_new,
JDOC("(int/s64 value)\n\n"
"Create a boxed signed 64 bit integer from a string value.")
},
{
"int/u64", cfun_it_u64_new,
JDOC("(int/u64 value)\n\n"
"Create a boxed unsigned 64 bit integer from a string value.")
},
{NULL, NULL, NULL}
};
/* Module entry point */
void janet_lib_inttypes(JanetTable *env) {
janet_core_cfuns(env, NULL, it_cfuns);
janet_register_abstract_type(&janet_s64_type);
janet_register_abstract_type(&janet_u64_type);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,79 +20,214 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "util.h"
#endif
#include <math.h>
static JANET_THREAD_LOCAL JanetRNG janet_vm_rng = {0, 0, 0, 0, 0};
static int janet_rng_get(void *p, Janet key, Janet *out);
static void janet_rng_marshal(void *p, JanetMarshalContext *ctx) {
JanetRNG *rng = (JanetRNG *)p;
janet_marshal_abstract(ctx, p);
janet_marshal_int(ctx, (int32_t) rng->a);
janet_marshal_int(ctx, (int32_t) rng->b);
janet_marshal_int(ctx, (int32_t) rng->c);
janet_marshal_int(ctx, (int32_t) rng->d);
janet_marshal_int(ctx, (int32_t) rng->counter);
}
static void *janet_rng_unmarshal(JanetMarshalContext *ctx) {
JanetRNG *rng = janet_unmarshal_abstract(ctx, sizeof(JanetRNG));
rng->a = (uint32_t) janet_unmarshal_int(ctx);
rng->b = (uint32_t) janet_unmarshal_int(ctx);
rng->c = (uint32_t) janet_unmarshal_int(ctx);
rng->d = (uint32_t) janet_unmarshal_int(ctx);
rng->counter = (uint32_t) janet_unmarshal_int(ctx);
return rng;
}
const JanetAbstractType janet_rng_type = {
"core/rng",
NULL,
NULL,
janet_rng_get,
NULL,
janet_rng_marshal,
janet_rng_unmarshal,
JANET_ATEND_UNMARSHAL
};
JanetRNG *janet_default_rng(void) {
return &janet_vm_rng;
}
void janet_rng_seed(JanetRNG *rng, uint32_t seed) {
rng->a = seed;
rng->b = 0x97654321u;
rng->c = 123871873u;
rng->d = 0xf23f56c8u;
rng->counter = 0u;
/* First several numbers aren't that random. */
for (int i = 0; i < 16; i++) janet_rng_u32(rng);
}
void janet_rng_longseed(JanetRNG *rng, const uint8_t *bytes, int32_t len) {
uint8_t state[16] = {0};
for (int32_t i = 0; i < len; i++)
state[i & 0xF] ^= bytes[i];
rng->a = state[0] + (state[1] << 8) + (state[2] << 16) + (state[3] << 24);
rng->b = state[4] + (state[5] << 8) + (state[6] << 16) + (state[7] << 24);
rng->c = state[8] + (state[9] << 8) + (state[10] << 16) + (state[11] << 24);
rng->d = state[12] + (state[13] << 8) + (state[14] << 16) + (state[15] << 24);
rng->counter = 0u;
/* a, b, c, d can't all be 0 */
if (rng->a == 0) rng->a = 1u;
for (int i = 0; i < 16; i++) janet_rng_u32(rng);
}
uint32_t janet_rng_u32(JanetRNG *rng) {
/* Algorithm "xorwow" from p. 5 of Marsaglia, "Xorshift RNGs" */
uint32_t t = rng->d;
uint32_t const s = rng->a;
rng->d = rng->c;
rng->c = rng->b;
rng->b = s;
t ^= t >> 2;
t ^= t << 1;
t ^= s ^ (s << 4);
rng->a = t;
rng->counter += 362437;
return t + rng->counter;
}
double janet_rng_double(JanetRNG *rng) {
uint32_t hi = janet_rng_u32(rng);
uint32_t lo = janet_rng_u32(rng);
uint64_t big = (uint64_t)(lo) | (((uint64_t) hi) << 32);
return ldexp((double)(big >> (64 - 52)), -52);
}
static Janet cfun_rng_make(int32_t argc, Janet *argv) {
janet_arity(argc, 0, 1);
JanetRNG *rng = janet_abstract(&janet_rng_type, sizeof(JanetRNG));
if (argc == 1) {
if (janet_checkint(argv[0])) {
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
janet_rng_seed(rng, seed);
} else {
JanetByteView bytes = janet_getbytes(argv, 0);
janet_rng_longseed(rng, bytes.bytes, bytes.len);
}
} else {
janet_rng_seed(rng, 0);
}
return janet_wrap_abstract(rng);
}
static Janet cfun_rng_uniform(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
return janet_wrap_number(janet_rng_double(rng));
}
static Janet cfun_rng_int(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
if (argc == 1) {
uint32_t word = janet_rng_u32(rng) >> 1;
return janet_wrap_integer(word);
} else {
int32_t max = janet_optnat(argv, argc, 1, INT32_MAX);
if (max == 0) return janet_wrap_number(0.0);
uint32_t modulo = (uint32_t) max;
uint32_t maxgen = INT32_MAX;
uint32_t maxword = maxgen - (maxgen % modulo);
uint32_t word;
do {
word = janet_rng_u32(rng) >> 1;
} while (word > maxword);
return janet_wrap_integer(word % modulo);
}
}
static void rng_get_4bytes(JanetRNG *rng, uint8_t *buf) {
uint32_t word = janet_rng_u32(rng);
buf[0] = word & 0xFF;
buf[1] = (word >> 8) & 0xFF;
buf[2] = (word >> 16) & 0xFF;
buf[3] = (word >> 24) & 0xFF;
}
static Janet cfun_rng_buffer(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 3);
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
int32_t n = janet_getnat(argv, 1);
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, n);
/* Split into first part (that is divisible by 4), and rest */
int32_t first_part = n & ~3;
int32_t second_part = n - first_part;
/* Get first part in chunks of 4 bytes */
janet_buffer_extra(buffer, n);
uint8_t *buf = buffer->data + buffer->count;
for (int32_t i = 0; i < first_part; i += 4) rng_get_4bytes(rng, buf + i);
buffer->count += first_part;
/* Get remaining 0 - 3 bytes */
if (second_part) {
uint8_t wordbuf[4] = {0};
rng_get_4bytes(rng, wordbuf);
janet_buffer_push_bytes(buffer, wordbuf, second_part);
}
return janet_wrap_buffer(buffer);
}
static const JanetMethod rng_methods[] = {
{"uniform", cfun_rng_uniform},
{"int", cfun_rng_int},
{"buffer", cfun_rng_buffer},
{NULL, NULL}
};
static int janet_rng_get(void *p, Janet key, Janet *out) {
(void) p;
if (!janet_checktype(key, JANET_KEYWORD)) return 0;
return janet_getmethod(janet_unwrap_keyword(key), rng_methods, out);
}
/* Get a random number */
int janet_rand(JanetArgs args) {
JANET_FIXARITY(args, 0);
double r = (rand() % RAND_MAX) / ((double) RAND_MAX);
JANET_RETURN_REAL(args, r);
static Janet janet_rand(int32_t argc, Janet *argv) {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_number(janet_rng_double(&janet_vm_rng));
}
/* Seed the random number generator */
int janet_srand(JanetArgs args) {
int32_t x = 0;
JANET_FIXARITY(args, 1);
JANET_ARG_INTEGER(x, args, 0);
srand((unsigned) x);
return 0;
}
/* Convert a number to an integer */
int janet_int(JanetArgs args) {
JANET_FIXARITY(args, 1);
switch (janet_type(args.v[0])) {
default:
JANET_THROW(args, "could not convert to integer");
case JANET_REAL:
*args.ret = janet_wrap_integer((int32_t) janet_unwrap_real(args.v[0]));
break;
case JANET_INTEGER:
*args.ret = args.v[0];
break;
}
return 0;
}
/* Convert a number to a real number */
int janet_real(JanetArgs args) {
JANET_FIXARITY(args, 1);
switch (janet_type(args.v[0])) {
default:
JANET_THROW(args, "could not convert to real");
case JANET_REAL:
*args.ret = args.v[0];
break;
case JANET_INTEGER:
*args.ret = janet_wrap_real((double) janet_unwrap_integer(args.v[0]));
break;
}
return 0;
}
int janet_remainder(JanetArgs args) {
JANET_FIXARITY(args, 2);
if (janet_checktype(args.v[0], JANET_INTEGER) &&
janet_checktype(args.v[1], JANET_INTEGER)) {
int32_t x, y;
x = janet_unwrap_integer(args.v[0]);
y = janet_unwrap_integer(args.v[1]);
JANET_RETURN_INTEGER(args, x % y);
static Janet janet_srand(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
if (janet_checkint(argv[0])) {
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
janet_rng_seed(&janet_vm_rng, seed);
} else {
double x, y;
JANET_ARG_NUMBER(x, args, 0);
JANET_ARG_NUMBER(y, args, 1);
JANET_RETURN_REAL(args, fmod(x, y));
JanetByteView bytes = janet_getbytes(argv, 0);
janet_rng_longseed(&janet_vm_rng, bytes.bytes, bytes.len);
}
return janet_wrap_nil();
}
#define JANET_DEFINE_MATHOP(name, fop)\
int janet_##name(JanetArgs args) {\
double x;\
JANET_FIXARITY(args, 1);\
JANET_ARG_NUMBER(x, args, 0);\
JANET_RETURN_REAL(args, fop(x));\
static Janet janet_##name(int32_t argc, Janet *argv) {\
janet_fixarity(argc, 1); \
double x = janet_getnumber(argv, 0); \
return janet_wrap_number(fop(x)); \
}
JANET_DEFINE_MATHOP(acos, acos)
@@ -100,123 +235,283 @@ JANET_DEFINE_MATHOP(asin, asin)
JANET_DEFINE_MATHOP(atan, atan)
JANET_DEFINE_MATHOP(cos, cos)
JANET_DEFINE_MATHOP(cosh, cosh)
JANET_DEFINE_MATHOP(acosh, acosh)
JANET_DEFINE_MATHOP(sin, sin)
JANET_DEFINE_MATHOP(sinh, sinh)
JANET_DEFINE_MATHOP(asinh, asinh)
JANET_DEFINE_MATHOP(tan, tan)
JANET_DEFINE_MATHOP(tanh, tanh)
JANET_DEFINE_MATHOP(atanh, atanh)
JANET_DEFINE_MATHOP(exp, exp)
JANET_DEFINE_MATHOP(exp2, exp2)
JANET_DEFINE_MATHOP(expm1, expm1)
JANET_DEFINE_MATHOP(log, log)
JANET_DEFINE_MATHOP(log10, log10)
JANET_DEFINE_MATHOP(log2, log2)
JANET_DEFINE_MATHOP(sqrt, sqrt)
JANET_DEFINE_MATHOP(cbrt, cbrt)
JANET_DEFINE_MATHOP(ceil, ceil)
JANET_DEFINE_MATHOP(fabs, fabs)
JANET_DEFINE_MATHOP(floor, floor)
JANET_DEFINE_MATHOP(trunc, trunc)
JANET_DEFINE_MATHOP(round, round)
JANET_DEFINE_MATHOP(gamma, lgamma)
JANET_DEFINE_MATHOP(log1p, log1p)
JANET_DEFINE_MATHOP(erf, erf)
JANET_DEFINE_MATHOP(erfc, erfc)
#define JANET_DEFINE_MATH2OP(name, fop)\
int janet_##name(JanetArgs args) {\
double lhs, rhs;\
JANET_FIXARITY(args, 2);\
JANET_ARG_NUMBER(lhs, args, 0);\
JANET_ARG_NUMBER(rhs, args, 1);\
JANET_RETURN_REAL(args, fop(lhs, rhs));\
static Janet janet_##name(int32_t argc, Janet *argv) {\
janet_fixarity(argc, 2); \
double lhs = janet_getnumber(argv, 0); \
double rhs = janet_getnumber(argv, 1); \
return janet_wrap_number(fop(lhs, rhs)); \
}\
JANET_DEFINE_MATH2OP(atan2, atan2)
JANET_DEFINE_MATH2OP(pow, pow)
JANET_DEFINE_MATH2OP(hypot, hypot)
JANET_DEFINE_MATH2OP(nextafter, nextafter)
static int janet_not(JanetArgs args) {
JANET_FIXARITY(args, 1);
JANET_RETURN_BOOLEAN(args, !janet_truthy(args.v[0]));
static Janet janet_not(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
return janet_wrap_boolean(!janet_truthy(argv[0]));
}
static const JanetReg cfuns[] = {
{"%", janet_remainder,
"(% dividend divisor)\n\n"
"Returns the remainder of dividend / divisor."
static const JanetReg math_cfuns[] = {
{
"not", janet_not,
JDOC("(not x)\n\nReturns the boolean inverse of x.")
},
{"not", janet_not,
"(not x)\n\nReturns the boolen inverse of x."
{
"math/random", janet_rand,
JDOC("(math/random)\n\n"
"Returns a uniformly distributed random number between 0 and 1.")
},
{"int", janet_int,
"(int x)\n\nCast a number x to an integer."
{
"math/seedrandom", janet_srand,
JDOC("(math/seedrandom seed)\n\n"
"Set the seed for the random number generator. seed should be "
"an integer or a buffer.")
},
{"real", janet_real,
"(real x)\n\nCast a number x to a real number."
{
"math/cos", janet_cos,
JDOC("(math/cos x)\n\n"
"Returns the cosine of x.")
},
{"math/random", janet_rand,
"(math/random)\n\n"
"Returns a uniformly distrbuted random real number between 0 and 1."
{
"math/sin", janet_sin,
JDOC("(math/sin x)\n\n"
"Returns the sine of x.")
},
{"math/seedrandom", janet_srand,
"(math/seedrandom seed)\n\n"
"Set the seed for the random number generator. 'seed' should be an "
"an integer."
{
"math/tan", janet_tan,
JDOC("(math/tan x)\n\n"
"Returns the tangent of x.")
},
{"math/cos", janet_cos,
"(math/cos x)\n\n"
"Returns the cosine of x."
{
"math/acos", janet_acos,
JDOC("(math/acos x)\n\n"
"Returns the arccosine of x.")
},
{"math/sin", janet_sin,
"(math/sin x)\n\n"
"Returns the sine of x."
{
"math/asin", janet_asin,
JDOC("(math/asin x)\n\n"
"Returns the arcsine of x.")
},
{"math/tan", janet_tan,
"(math/tan x)\n\n"
"Returns the tangent of x."
{
"math/atan", janet_atan,
JDOC("(math/atan x)\n\n"
"Returns the arctangent of x.")
},
{"math/acos", janet_acos,
"(math/acos x)\n\n"
"Returns the arccosine of x."
{
"math/exp", janet_exp,
JDOC("(math/exp x)\n\n"
"Returns e to the power of x.")
},
{"math/asin", janet_asin,
"(math/asin x)\n\n"
"Returns the arcsine of x."
{
"math/log", janet_log,
JDOC("(math/log x)\n\n"
"Returns log base natural number of x.")
},
{"math/atan", janet_atan,
"(math/atan x)\n\n"
"Returns the arctangent of x."
{
"math/log10", janet_log10,
JDOC("(math/log10 x)\n\n"
"Returns log base 10 of x.")
},
{"math/exp", janet_exp,
"(math/exp x)\n\n"
"Returns e to the power of x."
{
"math/log2", janet_log2,
JDOC("(math/log2 x)\n\n"
"Returns log base 2 of x.")
},
{"math/log", janet_log,
"(math/log x)\n\n"
"Returns log base 2 of x."
{
"math/sqrt", janet_sqrt,
JDOC("(math/sqrt x)\n\n"
"Returns the square root of x.")
},
{"math/log10", janet_log10,
"(math/log10 x)\n\n"
"Returns log base 10 of x."
{
"math/cbrt", janet_cbrt,
JDOC("(math/cbrt x)\n\n"
"Returns the cube root of x.")
},
{"math/sqrt", janet_sqrt,
"(math/sqrt x)\n\n"
"Returns the square root of x."
{
"math/floor", janet_floor,
JDOC("(math/floor x)\n\n"
"Returns the largest integer value number that is not greater than x.")
},
{"math/floor", janet_floor,
"(math/floor x)\n\n"
"Returns the largest integer value real number that is not greater than x."
{
"math/ceil", janet_ceil,
JDOC("(math/ceil x)\n\n"
"Returns the smallest integer value number that is not less than x.")
},
{"math/ceil", janet_ceil,
"(math/ceil x)\n\n"
"Returns the smallest integer value real number that is not less than x."
{
"math/pow", janet_pow,
JDOC("(math/pow a x)\n\n"
"Return a to the power of x.")
},
{"math/pow", janet_pow,
"(math/pow a x)\n\n"
"Return a to the power of x."
{
"math/abs", janet_fabs,
JDOC("(math/abs x)\n\n"
"Return the absolute value of x.")
},
{
"math/sinh", janet_sinh,
JDOC("(math/sinh x)\n\n"
"Return the hyperbolic sine of x.")
},
{
"math/cosh", janet_cosh,
JDOC("(math/cosh x)\n\n"
"Return the hyperbolic cosine of x.")
},
{
"math/tanh", janet_tanh,
JDOC("(math/tanh x)\n\n"
"Return the hyperbolic tangent of x.")
},
{
"math/atanh", janet_atanh,
JDOC("(math/atanh x)\n\n"
"Return the hyperbolic arctangent of x.")
},
{
"math/asinh", janet_asinh,
JDOC("(math/asinh x)\n\n"
"Return the hyperbolic arcsine of x.")
},
{
"math/acosh", janet_acosh,
JDOC("(math/acosh x)\n\n"
"Return the hyperbolic arccosine of x.")
},
{
"math/atan2", janet_atan2,
JDOC("(math/atan2 y x)\n\n"
"Return the arctangent of y/x. Works even when x is 0.")
},
{
"math/rng", cfun_rng_make,
JDOC("(math/rng &opt seed)\n\n"
"Creates a Psuedo-Random number generator, with an optional seed. "
"The seed should be an unsigned 32 bit integer or a buffer. "
"Do not use this for cryptography. Returns a core/rng abstract type.")
},
{
"math/rng-uniform", cfun_rng_uniform,
JDOC("(math/rng-seed rng seed)\n\n"
"Extract a random number in the range [0, 1) from the RNG.")
},
{
"math/rng-int", cfun_rng_int,
JDOC("(math/rng-int rng &opt max)\n\n"
"Extract a random random integer in the range [0, max] from the RNG. If "
"no max is given, the default is 2^31 - 1.")
},
{
"math/rng-buffer", cfun_rng_buffer,
JDOC("(math/rng-buffer rng n &opt buf)\n\n"
"Get n random bytes and put them in a buffer. Creates a new buffer if no buffer is "
"provided, otherwise appends to the given buffer. Returns the buffer.")
},
{
"math/hypot", janet_hypot,
JDOC("(math/hypot a b)\n\n"
"Returns the c from the equation c^2 = a^2 + b^2")
},
{
"math/exp2", janet_exp2,
JDOC("(math/exp2 x)\n\n"
"Returns 2 to the power of x.")
},
{
"math/log1p", janet_log1p,
JDOC("(math/log1p x)\n\n"
"Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
},
{
"math/gamma", janet_gamma,
JDOC("(math/gamma x)\n\n"
"Returns gamma(x).")
},
{
"math/erfc", janet_erfc,
JDOC("(math/erfc x)\n\n"
"Returns the complementary error function of x.")
},
{
"math/erf", janet_erf,
JDOC("(math/erf x)\n\n"
"Returns the error function of x.")
},
{
"math/expm1", janet_expm1,
JDOC("(math/expm1 x)\n\n"
"Returns e to the power of x minus 1.")
},
{
"math/trunc", janet_trunc,
JDOC("(math/trunc x)\n\n"
"Returns the integer between x and 0 nearest to x.")
},
{
"math/round", janet_round,
JDOC("(math/round x)\n\n"
"Returns the integer nearest to x.")
},
{
"math/next", janet_nextafter,
JDOC("(math/next x y)\n\n"
"Returns the next representable floating point value after x in the direction of y.")
},
{NULL, NULL, NULL}
};
/* Module entry point */
int janet_lib_math(JanetArgs args) {
JanetTable *env = janet_env(args);
janet_cfuns(env, NULL, cfuns);
janet_def(env, "math/pi", janet_wrap_real(3.1415926535897931),
"The value pi.");
janet_def(env, "math/e", janet_wrap_real(2.7182818284590451),
"The base of the natural log.");
janet_def(env, "math/inf", janet_wrap_real(INFINITY),
"The real number representing positive infinity");
return 0;
void janet_lib_math(JanetTable *env) {
janet_core_cfuns(env, NULL, math_cfuns);
janet_register_abstract_type(&janet_rng_type);
#ifdef JANET_BOOTSTRAP
janet_def(env, "math/pi", janet_wrap_number(3.1415926535897931),
JDOC("The value pi."));
janet_def(env, "math/e", janet_wrap_number(2.7182818284590451),
JDOC("The base of the natural log."));
janet_def(env, "math/inf", janet_wrap_number(INFINITY),
JDOC("The number representing positive infinity"));
janet_def(env, "math/-inf", janet_wrap_number(-INFINITY),
JDOC("The number representing negative infinity"));
janet_def(env, "math/int32-min", janet_wrap_number(INT32_MIN),
JDOC("The maximum contiguous integer representable by a 32 bit signed integer"));
janet_def(env, "math/int32-max", janet_wrap_number(INT32_MAX),
JDOC("The minimum contiguous integer represtenable by a 32 bit signed integer"));
janet_def(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE),
JDOC("The maximum contiguous integer representable by a double (2^53)"));
janet_def(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE),
JDOC("The minimum contiguous integer represtenable by a double (-(2^53))"));
#ifdef NAN
janet_def(env, "math/nan", janet_wrap_number(NAN),
#else
janet_def(env, "math/nan", janet_wrap_number(0.0 / 0.0),
#endif
JDOC("Not a number (IEEE-754 NaN)"));
#endif
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright (c) 2018 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include "compile.h"
#include "emit.h"
#include "vector.h"
/* Parse a part of a symbol that can be used for building up code. */
static JanetSlot multisym_parse_part(JanetCompiler *c, const uint8_t *sympart, int32_t len) {
if (sympart[0] == ':') {
return janetc_cslot(janet_symbolv(sympart, len));
} else {
int err = 0;
int32_t num = janet_scan_integer(sympart + 1, len - 1, &err);
if (err) {
return janetc_resolve(c, janet_symbol(sympart + 1, len - 1));
} else {
return janetc_cslot(janet_wrap_integer(num));
}
}
}
static JanetSlot multisym_do_parts(JanetFopts opts, int put, const uint8_t *sym, Janet rvalue) {
JanetSlot slot;
JanetFopts subopts = janetc_fopts_default(opts.compiler);
int i, j;
for (i = 1, j = 0; sym[i]; i++) {
if (sym[i] == ':' || sym[i] == '.') {
if (j) {
JanetSlot target = janetc_gettarget(subopts);
JanetSlot value = multisym_parse_part(opts.compiler, sym + j, i - j);
janetc_emit_sss(opts.compiler, JOP_GET, target, slot, value, 1);
slot = target;
} else {
const uint8_t *nextsym = janet_symbol(sym + j, i - j);
slot = janetc_resolve(opts.compiler, nextsym);
}
j = i;
}
}
if (j) {
/* multisym (outermost get or put) */
JanetSlot target = janetc_gettarget(opts);
JanetSlot key = multisym_parse_part(opts.compiler, sym + j, i - j);
if (put) {
subopts.flags = JANET_FOPTS_HINT;
subopts.hint = target;
JanetSlot r_slot = janetc_value(subopts, rvalue);
janetc_emit_sss(opts.compiler, JOP_PUT, slot, key, r_slot, 0);
janetc_copy(opts.compiler, target, r_slot);
} else {
janetc_emit_sss(opts.compiler, JOP_GET, target, slot, key, 1);
}
return target;
} else {
/* normal symbol */
if (put) {
JanetSlot ret, dest;
dest = janetc_resolve(opts.compiler, sym);
if (!(dest.flags & JANET_SLOT_MUTABLE)) {
janetc_cerror(opts.compiler, "cannot set constant");
return janetc_cslot(janet_wrap_nil());
}
subopts.flags = JANET_FOPTS_HINT;
subopts.hint = dest;
ret = janetc_value(subopts, rvalue);
janetc_copy(opts.compiler, dest, ret);
return ret;
}
return janetc_resolve(opts.compiler, sym);
}
}
/* Check if a symbol is a multisym, and if so, transform
* it and emit the code for treating it as a bunch of nested
* gets. */
JanetSlot janetc_sym_rvalue(JanetFopts opts, const uint8_t *sym) {
if (janet_string_length(sym) && sym[0] != ':') {
return multisym_do_parts(opts, 0, sym, janet_wrap_nil());
} else {
/* keyword */
return janetc_cslot(janet_wrap_symbol(sym));
}
}
/* Check if a symbol is a multisym, and if so, transform
* it into the correct 'put' expression. */
JanetSlot janetc_sym_lvalue(JanetFopts opts, const uint8_t *sym, Janet value) {
return multisym_do_parts(opts, 1, sym, value);
}

713
src/core/net.c Normal file
View File

@@ -0,0 +1,713 @@
/*
* Copyright (c) 2020 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
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "util.h"
#endif
#ifdef JANET_NET
#ifdef JANET_WINDOWS
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "Advapi32.lib")
#else
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <netdb.h>
#include <fcntl.h>
#endif
/*
* Streams
*/
#define JANET_STREAM_CLOSED 1
#define JANET_STREAM_READABLE 2
#define JANET_STREAM_WRITABLE 4
static int janet_stream_close(void *p, size_t s);
static int janet_stream_getter(void *p, Janet key, Janet *out);
static const JanetAbstractType StreamAT = {
"core/stream",
janet_stream_close,
NULL,
janet_stream_getter,
JANET_ATEND_GET
};
#ifdef JANET_WINDOWS
typedef struct {
SOCKET fd;
int flags;
} JanetStream;
#define JSOCKCLOSE(x) closesocket(x)
#define JSOCKDEFAULT INVALID_SOCKET
#define JLASTERR WSAGetLastError()
#define JSOCKVALID(x) ((x) != INVALID_SOCKET)
#define JEINTR WSAEINTR
#define JEWOULDBLOCK WSAEWOULDBLOCK
#define JEAGAIN WSAEWOULDBLOCK
#define JPOLL WSAPoll
#define JPollStruct WSAPOLLFD
#define JSock SOCKET
#define JReadInt long
#define JSOCKFLAGS 0
static JanetStream *make_stream(SOCKET fd, int flags) {
u_long iMode = 0;
JanetStream *stream = janet_abstract(&StreamAT, sizeof(JanetStream));
ioctlsocket(fd, FIONBIO, &iMode);
stream->fd = fd;
stream->flags = flags;
return stream;
}
#else
typedef struct {
int fd;
int flags;
} JanetStream;
#define JSOCKCLOSE(x) close(x)
#define JSOCKDEFAULT 0
#define JLASTERR errno
#define JSOCKVALID(x) ((x) >= 0)
#define JEINTR EINTR
#define JEWOULDBLOCK EWOULDBLOCK
#define JEAGAIN EAGAIN
#define JPOLL poll
#define JPollStruct struct pollfd
#define JSock int
#define JReadInt ssize_t
#ifdef SOCK_CLOEXEC
#define JSOCKFLAGS SOCK_CLOEXEC
#else
#define JSOCKFLAGS 0
#endif
static JanetStream *make_stream(int fd, int flags) {
JanetStream *stream = janet_abstract(&StreamAT, sizeof(JanetStream));
#if !defined(SOCK_CLOEXEC) && defined(O_CLOEXEC)
int extra = O_CLOEXEC;
#else
int extra = 0;
#endif
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK | extra);
stream->fd = fd;
stream->flags = flags;
return stream;
}
#endif
/* We pass this flag to all send calls to prevent sigpipe */
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
static int janet_stream_close(void *p, size_t s) {
(void) s;
JanetStream *stream = p;
if (!(stream->flags & JANET_STREAM_CLOSED)) {
stream->flags |= JANET_STREAM_CLOSED;
JSOCKCLOSE(stream->fd);
}
return 0;
}
static void nosigpipe(JSock s) {
#ifdef SO_NOSIGPIPE
int enable = 1;
if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) {
JSOCKCLOSE(s);
janet_panic("setsockopt(SO_NOSIGPIPE) failed");
}
#else
(void) s;
#endif
}
/*
* Event loop
*/
/* This large struct describes a waiting file descriptor, as well
* as what to do when we get an event for it. It is a variant type, where
* each variant implements a simple state machine. */
typedef struct {
/* File descriptor to listen for events on. */
JanetStream *stream;
/* Fiber to resume when event finishes. Can be NULL, in which case,
* no fiber is resumed when event completes. */
JanetFiber *fiber;
/* What kind of event we are listening for.
* As more IO functionality get's added, we can
* expand this. */
enum {
JLE_READ_CHUNK,
JLE_READ_SOME,
JLE_READ_ACCEPT,
JLE_CONNECT,
JLE_WRITE_FROM_BUFFER,
JLE_WRITE_FROM_STRINGLIKE
} event_type;
/* Each variant can have a different payload. */
union {
/* JLE_READ_CHUNK/JLE_READ_SOME */
struct {
int32_t bytes_left;
JanetBuffer *buf;
} read_chunk;
/* JLE_READ_ACCEPT */
struct {
JanetFunction *handler;
} read_accept;
/* JLE_WRITE_FROM_BUFFER */
struct {
JanetBuffer *buf;
int32_t start;
} write_from_buffer;
/* JLE_WRITE_FROM_STRINGLIKE */
struct {
const uint8_t *str;
int32_t start;
} write_from_stringlike;
} data;
} JanetLoopFD;
#define JANET_LOOPFD_MAX 1024
/* Global loop data */
JANET_THREAD_LOCAL JPollStruct janet_vm_pollfds[JANET_LOOPFD_MAX];
JANET_THREAD_LOCAL JanetLoopFD janet_vm_loopfds[JANET_LOOPFD_MAX];
JANET_THREAD_LOCAL int janet_vm_loop_count;
/* We could also add/remove gc roots. This is easier for now. */
void janet_net_markloop(void) {
for (int i = 0; i < janet_vm_loop_count; i++) {
JanetLoopFD lfd = janet_vm_loopfds[i];
if (lfd.fiber != NULL) {
janet_mark(janet_wrap_fiber(lfd.fiber));
}
janet_mark(janet_wrap_abstract(lfd.stream));
switch (lfd.event_type) {
default:
break;
case JLE_READ_CHUNK:
case JLE_READ_SOME:
janet_mark(janet_wrap_buffer(lfd.data.read_chunk.buf));
break;
case JLE_READ_ACCEPT:
janet_mark(janet_wrap_function(lfd.data.read_accept.handler));
break;
case JLE_CONNECT:
break;
case JLE_WRITE_FROM_BUFFER:
janet_mark(janet_wrap_buffer(lfd.data.write_from_buffer.buf));
break;
case JLE_WRITE_FROM_STRINGLIKE:
janet_mark(janet_wrap_string(lfd.data.write_from_stringlike.str));
}
}
}
/* Add a loop fd to the global event loop */
static int janet_loop_schedule(JanetLoopFD lfd, short events) {
if (janet_vm_loop_count == JANET_LOOPFD_MAX) {
return -1;
}
int index = janet_vm_loop_count++;
janet_vm_loopfds[index] = lfd;
janet_vm_pollfds[index].fd = lfd.stream->fd;
janet_vm_pollfds[index].events = events;
janet_vm_pollfds[index].revents = 0;
return index;
}
/* Remove event from list */
static void janet_loop_rmindex(int index) {
janet_vm_loopfds[index] = janet_vm_loopfds[--janet_vm_loop_count];
janet_vm_pollfds[index] = janet_vm_pollfds[janet_vm_loop_count];
}
/* Return delta in number of loop fds. Abstracted out so
* we can separate out the polling logic */
static size_t janet_loop_event(size_t index) {
JanetLoopFD *jlfd = janet_vm_loopfds + index;
JanetStream *stream = jlfd->stream;
JSock fd = stream->fd;
int ret = 1;
int should_resume = 0;
Janet resumeval = janet_wrap_nil();
JanetSignal resumesignal = JANET_SIGNAL_OK;
if (stream->flags & JANET_STREAM_CLOSED) {
should_resume = 1;
resumeval = janet_cstringv("stream is closed");
resumesignal = JANET_SIGNAL_ERROR;
ret = 0;
} else {
switch (jlfd->event_type) {
case JLE_READ_CHUNK:
case JLE_READ_SOME: {
JanetBuffer *buffer = jlfd->data.read_chunk.buf;
int32_t bytes_left = jlfd->data.read_chunk.bytes_left;
janet_buffer_extra(buffer, bytes_left);
if (!(stream->flags & JANET_STREAM_READABLE)) {
should_resume = 1;
ret = 0;
resumesignal = JANET_SIGNAL_ERROR;
resumeval = janet_cstringv("stream not readable");
break;
}
JReadInt nread;
do {
nread = recv(fd, buffer->data + buffer->count, bytes_left, 0);
} while (nread == -1 && JLASTERR == JEINTR);
if (JLASTERR == JEAGAIN || JLASTERR == JEWOULDBLOCK) {
ret = 1;
break;
}
if (nread > 0) {
buffer->count += nread;
bytes_left -= nread;
} else {
bytes_left = 0;
}
if (jlfd->event_type == JLE_READ_SOME || bytes_left == 0) {
should_resume = 1;
if (nread > 0) {
resumeval = janet_wrap_buffer(buffer);
} else {
if (nread == 0) {
resumeval = janet_cstringv("could not read from stream");
} else {
resumeval = janet_cstringv(strerror(JLASTERR));
}
resumesignal = JANET_SIGNAL_ERROR;
}
ret = 0;
} else {
jlfd->data.read_chunk.bytes_left = bytes_left;
ret = 1;
}
break;
}
case JLE_READ_ACCEPT: {
JSock connfd = accept(fd, NULL, NULL);
if (JSOCKVALID(connfd)) {
/* Made a new connection socket */
nosigpipe(connfd);
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
Janet streamv = janet_wrap_abstract(stream);
JanetFunction *handler = jlfd->data.read_accept.handler;
Janet out;
JanetFiber *fiberp = NULL;
/* Launch connection fiber */
JanetSignal sig = janet_pcall(handler, 1, &streamv, &out, &fiberp);
if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) {
janet_stacktrace(fiberp, out);
}
}
ret = JANET_LOOPFD_MAX;
break;
}
case JLE_WRITE_FROM_BUFFER:
case JLE_WRITE_FROM_STRINGLIKE: {
int32_t start, len;
const uint8_t *bytes;
if (!(stream->flags & JANET_STREAM_WRITABLE)) {
should_resume = 1;
resumesignal = JANET_SIGNAL_ERROR;
resumeval = janet_cstringv("stream not writeable");
ret = 0;
break;
}
if (jlfd->event_type == JLE_WRITE_FROM_BUFFER) {
JanetBuffer *buffer = jlfd->data.write_from_buffer.buf;
bytes = buffer->data;
len = buffer->count;
start = jlfd->data.write_from_buffer.start;
} else {
bytes = jlfd->data.write_from_stringlike.str;
len = janet_string_length(bytes);
start = jlfd->data.write_from_stringlike.start;
}
if (start < len) {
int32_t nbytes = len - start;
JReadInt nwrote;
do {
nwrote = send(fd, bytes + start, nbytes, MSG_NOSIGNAL);
} while (nwrote == -1 && JLASTERR == JEINTR);
if (nwrote > 0) {
start += nwrote;
} else {
resumesignal = JANET_SIGNAL_ERROR;
if (nwrote == -1) {
resumeval = janet_cstringv(strerror(JLASTERR));
} else {
resumeval = janet_cstringv("could not write");
}
start = len;
}
}
if (start >= len) {
should_resume = 1;
ret = 0;
} else {
if (jlfd->event_type == JLE_WRITE_FROM_BUFFER) {
jlfd->data.write_from_buffer.start = start;
} else {
jlfd->data.write_from_stringlike.start = start;
}
ret = 1;
}
break;
}
case JLE_CONNECT: {
break;
}
}
}
/* Resume a fiber for some events */
if (NULL != jlfd->fiber && should_resume) {
/* Resume the fiber */
Janet out;
JanetSignal sig = janet_continue_signal(jlfd->fiber, resumeval, &out, resumesignal);
if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) {
janet_stacktrace(jlfd->fiber, out);
}
}
/* Remove this handler from the handler pool. */
if (should_resume) janet_loop_rmindex((int) index);
return ret;
}
static void janet_loop1(void) {
/* Remove closed file descriptors */
for (int i = 0; i < janet_vm_loop_count;) {
if (janet_vm_loopfds[i].stream->flags & JANET_STREAM_CLOSED) {
janet_loop_rmindex(i);
} else {
i++;
}
}
/* Poll */
if (janet_vm_loop_count == 0) return;
int ready;
do {
ready = JPOLL(janet_vm_pollfds, janet_vm_loop_count, -1);
} while (ready == -1 && JLASTERR == JEINTR);
if (ready == -1) return;
/* Handle events */
for (int i = 0; i < janet_vm_loop_count;) {
int revents = janet_vm_pollfds[i].revents;
janet_vm_pollfds[i].revents = 0;
if ((janet_vm_pollfds[i].events | POLLHUP | POLLERR) & revents) {
size_t delta = janet_loop_event(i);
i += (int) delta;
} else {
i++;
}
}
}
void janet_loop(void) {
while (janet_vm_loop_count) {
janet_loop1();
}
}
/*
* Scheduling Helpers
*/
#define JANET_SCHED_FSOME 1
JANET_NO_RETURN static void janet_sched_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes, int flags) {
JanetLoopFD lfd;
lfd.stream = stream;
lfd.fiber = janet_root_fiber();
lfd.event_type = (flags & JANET_SCHED_FSOME) ? JLE_READ_SOME : JLE_READ_CHUNK;
lfd.data.read_chunk.buf = buf;
lfd.data.read_chunk.bytes_left = nbytes;
janet_loop_schedule(lfd, POLLIN);
janet_signalv(JANET_SIGNAL_EVENT, janet_wrap_nil());
}
JANET_NO_RETURN static void janet_sched_write_buffer(JanetStream *stream, JanetBuffer *buf) {
JanetLoopFD lfd;
lfd.stream = stream;
lfd.fiber = janet_root_fiber();
lfd.event_type = JLE_WRITE_FROM_BUFFER;
lfd.data.write_from_buffer.buf = buf;
lfd.data.write_from_buffer.start = 0;
janet_loop_schedule(lfd, POLLOUT);
janet_signalv(JANET_SIGNAL_EVENT, janet_wrap_nil());
}
JANET_NO_RETURN static void janet_sched_write_stringlike(JanetStream *stream, const uint8_t *str) {
JanetLoopFD lfd;
lfd.stream = stream;
lfd.fiber = janet_root_fiber();
lfd.event_type = JLE_WRITE_FROM_STRINGLIKE;
lfd.data.write_from_stringlike.str = str;
lfd.data.write_from_stringlike.start = 0;
janet_loop_schedule(lfd, POLLOUT);
janet_signalv(JANET_SIGNAL_EVENT, janet_wrap_nil());
}
/* Needs argc >= offset + 2 */
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset) {
/* Get host and port */
const char *host = janet_getcstring(argv, offset);
const char *port;
if (janet_checkint(argv[offset + 1])) {
port = (const char *)janet_to_string(argv[offset + 1]);
} else {
port = janet_getcstring(argv, offset + 1);
}
/* getaddrinfo */
struct addrinfo *ai = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(host, port, &hints, &ai);
if (status) {
janet_panicf("could not get address info: %s", gai_strerror(status));
}
return ai;
}
/*
* C Funs
*/
static Janet cfun_net_connect(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
/* Create socket */
JSock sock = socket(ai->ai_family, ai->ai_socktype | JSOCKFLAGS, ai->ai_protocol);
if (!JSOCKVALID(sock)) {
freeaddrinfo(ai);
janet_panic("could not create socket");
}
/* Connect to socket */
int status = connect(sock, ai->ai_addr, (int) ai->ai_addrlen);
freeaddrinfo(ai);
if (status == -1) {
JSOCKCLOSE(sock);
janet_panic("could not connect to socket");
}
nosigpipe(sock);
/* Wrap socket in abstract type JanetStream */
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
return janet_wrap_abstract(stream);
}
static Janet cfun_net_server(int32_t argc, Janet *argv) {
janet_fixarity(argc, 3);
/* Get host, port, and handler*/
JanetFunction *fun = janet_getfunction(argv, 2);
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
/* Check all addrinfos in a loop for the first that we can bind to. */
JSock sfd = JSOCKDEFAULT;
struct addrinfo *rp = NULL;
for (rp = ai; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol);
if (!JSOCKVALID(sfd)) continue;
/* Set various socket options */
int enable = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
JSOCKCLOSE(sfd);
janet_panic("setsockopt(SO_REUSEADDR) failed");
}
nosigpipe(sfd);
#ifdef SO_REUSEPORT
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
JSOCKCLOSE(sfd);
janet_panic("setsockopt(SO_REUSEPORT) failed");
}
#endif
/* Bind */
if (bind(sfd, rp->ai_addr, (int) rp->ai_addrlen) == 0) break;
JSOCKCLOSE(sfd);
}
if (NULL == rp) {
freeaddrinfo(ai);
janet_panic("could not bind to any sockets");
}
/* listen */
int status = listen(sfd, 1024);
freeaddrinfo(ai);
if (status) {
JSOCKCLOSE(sfd);
janet_panic("could not listen on file descriptor");
}
/* Put sfd on our loop */
JanetLoopFD lfd;
memset(&lfd, 0, sizeof(lfd));
lfd.stream = make_stream(sfd, 0);
lfd.event_type = JLE_READ_ACCEPT;
lfd.data.read_accept.handler = fun;
janet_loop_schedule(lfd, POLLIN);
return janet_wrap_abstract(lfd.stream);
}
static Janet cfun_stream_read(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 3);
JanetStream *stream = janet_getabstract(argv, 0, &StreamAT);
int32_t n = janet_getnat(argv, 1);
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, 10);
janet_sched_read(stream, buffer, n, JANET_SCHED_FSOME);
}
static Janet cfun_stream_chunk(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 3);
JanetStream *stream = janet_getabstract(argv, 0, &StreamAT);
int32_t n = janet_getnat(argv, 1);
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, 10);
janet_sched_read(stream, buffer, n, 0);
}
static Janet cfun_stream_close(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetStream *stream = janet_getabstract(argv, 0, &StreamAT);
janet_stream_close(stream, 0);
return janet_wrap_nil();
}
static Janet cfun_stream_write(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JanetStream *stream = janet_getabstract(argv, 0, &StreamAT);
if (janet_checktype(argv[1], JANET_BUFFER)) {
janet_sched_write_buffer(stream, janet_getbuffer(argv, 1));
} else {
JanetByteView bytes = janet_getbytes(argv, 1);
janet_sched_write_stringlike(stream, bytes.bytes);
}
}
static const JanetMethod stream_methods[] = {
{"chunk", cfun_stream_chunk},
{"close", cfun_stream_close},
{"read", cfun_stream_read},
{"write", cfun_stream_write},
{NULL, NULL}
};
static int janet_stream_getter(void *p, Janet key, Janet *out) {
(void) p;
if (!janet_checktype(key, JANET_KEYWORD)) return 0;
return janet_getmethod(janet_unwrap_keyword(key), stream_methods, out);
}
static const JanetReg net_cfuns[] = {
{
"net/server", cfun_net_server,
JDOC("(net/server host port handler)\n\n"
"Start a TCP server. handler is a function that will be called with a stream "
"on each connection to the server. Returns a new stream that is neither readable nor "
"writeable.")
},
{
"net/read", cfun_stream_read,
JDOC("(net/read stream nbytes &opt buf)\n\n"
"Read up to n bytes from a stream, suspending the current fiber until the bytes are available. "
"If less than n bytes are available (and more than 0), will push those bytes and return early. "
"Returns a buffer with up to n more bytes in it, or raises an error if the read failed.")
},
{
"net/chunk", cfun_stream_chunk,
JDOC("(net/chunk stream nbytes &opt buf)\n\n"
"Same a net/read, but will wait for all n bytes to arrive rather than return early.")
},
{
"net/write", cfun_stream_write,
JDOC("(net/write stream data)\n\n"
"Write data to a stream, suspending the current fiber until the write "
"completes. Returns nil, or raises an error if the write failed.")
},
{
"net/close", cfun_stream_close,
JDOC("(net/close stream)\n\n"
"Close a stream so that no further communication can occur.")
},
{
"net/connect", cfun_net_connect,
JDOC("(net/connect host port)\n\n"
"Open a connection to communicate with a server. Returns a duplex stream "
"that can be used to communicate with the server.")
},
{NULL, NULL, NULL}
};
void janet_lib_net(JanetTable *env) {
janet_vm_loop_count = 0;
#ifdef JANET_WINDOWS
WSADATA wsaData;
janet_assert(!WSAStartup(MAKEWORD(2, 2), &wsaData), "could not start winsock");
#endif
janet_core_cfuns(env, NULL, net_cfuns);
}
void janet_net_deinit(void) {
#ifdef JANET_WINDOWS
WSACleanup();
#endif
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1486
src/core/peg.c Normal file

File diff suppressed because it is too large Load Diff

1004
src/core/pp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,8 +20,12 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "regalloc.h"
#include "util.h"
#endif
void janetc_regalloc_init(JanetcRegisterAllocator *ra) {
ra->chunks = NULL;
@@ -57,19 +61,23 @@ static int32_t count_trailing_ones(uint32_t x) {
/* Get N bits */
#define nbits(N) (ithbit(N) - 1)
/* Copy a regsiter allocator */
/* Copy a register allocator */
void janetc_regalloc_clone(JanetcRegisterAllocator *dest, JanetcRegisterAllocator *src) {
size_t size;
dest->count = src->count;
dest->capacity = src->capacity;
dest->max = src->max;
size = sizeof(uint32_t) * dest->capacity;
dest->chunks = malloc(size);
size = sizeof(uint32_t) * (size_t) dest->capacity;
dest->regtemps = 0;
if (!dest->chunks) {
JANET_OUT_OF_MEMORY;
if (size) {
dest->chunks = malloc(size);
if (!dest->chunks) {
JANET_OUT_OF_MEMORY;
}
memcpy(dest->chunks, src->chunks, size);
} else {
dest->chunks = NULL;
}
memcpy(dest->chunks, src->chunks, size);
}
/* Allocate one more chunk in chunks */
@@ -79,7 +87,7 @@ static void pushchunk(JanetcRegisterAllocator *ra) {
int32_t newcount = ra->count + 1;
if (newcount > ra->capacity) {
int32_t newcapacity = newcount * 2;
ra->chunks = realloc(ra->chunks, newcapacity * sizeof(uint32_t));
ra->chunks = realloc(ra->chunks, (size_t) newcapacity * sizeof(uint32_t));
if (!ra->chunks) {
JANET_OUT_OF_MEMORY;
}
@@ -137,7 +145,7 @@ void janetc_regalloc_free(JanetcRegisterAllocator *ra, int32_t reg) {
int32_t janetc_regalloc_temp(JanetcRegisterAllocator *ra, JanetcRegisterTemp nth) {
int32_t oldmax = ra->max;
if (ra->regtemps & (1 << nth)) {
janet_exit("regtemp already allocated");
JANET_EXIT("regtemp already allocated");
}
ra->regtemps |= 1 << nth;
int32_t reg = janetc_regalloc_1(ra);
@@ -153,78 +161,3 @@ void janetc_regalloc_freetemp(JanetcRegisterAllocator *ra, int32_t reg, JanetcRe
if (reg < 0xF0)
janetc_regalloc_free(ra, reg);
}
/* Disable multi-slot allocation for now. */
/*
static int32_t checkrange(JanetcRegisterAllocator *ra, int32_t start, int32_t end) {
int32_t startchunk = start / 32;
int32_t endchunk = end / 32;
for (int32_t chunk = startchunk; chunk <= endchunk; chunk++) {
while (ra->count <= chunk) pushchunk(ra);
uint32_t mask = 0xFFFFFFFF;
if (chunk == startchunk)
mask &= ~nbits(start & 0x1F);
if (chunk == endchunk)
mask &= nbits(end & 0x1F);
uint32_t block = ra->chunks[chunk];
uint32_t masking = mask & block;
if (masking) {
int32_t nextbit = (block == 0xFFFFFFFF)
? 32
: count_trailing_zeros(masking) + 1;
return chunk * 32 + nextbit;
}
}
return -1;
}
static void markrange(JanetcRegisterAllocator *ra, int32_t start, int32_t end) {
int32_t startchunk = start / 32;
int32_t endchunk = end / 32;
for (int32_t chunk = startchunk; chunk <= endchunk; chunk++) {
uint32_t mask = 0xFFFFFFFF;
if (chunk == startchunk)
mask &= ~nbits(start & 0x1F);
if (chunk == endchunk)
mask &= nbits(end & 0x1F);
ra->chunks[chunk] |= mask;
}
}
void janetc_regalloc_freerange(JanetcRegisterAllocator *ra, int32_t start, int32_t n) {
int32_t end = start + n - 1;
int32_t startchunk = start / 32;
int32_t endchunk = end / 32;
for (int32_t chunk = startchunk; chunk <= endchunk; chunk++) {
uint32_t mask = 0;
if (chunk == startchunk)
mask |= nbits(start & 0x1F);
if (chunk == endchunk)
mask |= ~nbits(end & 0x1F);
ra->chunks[chunk] &= mask;
}
}
int32_t janetc_regalloc_n(JanetcRegisterAllocator *ra, int32_t n) {
int32_t start = 0, end = 0, next = 0;
while (next >= 0) {
start = next;
end = start + n - 1;
next = checkrange(ra, start, end);
}
markrange(ra, start, end);
if (end > ra->max)
ra->max = end;
return start;
}
int32_t janetc_regalloc_call(JanetcRegisterAllocator *ra, int32_t callee, int32_t nargs) {
if (checkrange(ra, callee, callee + nargs) < 0) {
markrange(ra, callee + 1, callee + nargs);
return callee;
}
return janetc_regalloc_n(ra, nargs + 1);
}
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -44,7 +44,7 @@ typedef struct {
int32_t count; /* number of chunks in chunks */
int32_t capacity; /* amount allocated for chunks */
int32_t max; /* The maximum allocated register so far */
int32_t regtemps; /* Hold which tempregistered are alloced. */
int32_t regtemps; /* Hold which temp. registers are allocated. */
} JanetcRegisterAllocator;
void janetc_regalloc_init(JanetcRegisterAllocator *ra);
@@ -57,11 +57,4 @@ void janetc_regalloc_freetemp(JanetcRegisterAllocator *ra, int32_t reg, JanetcRe
void janetc_regalloc_clone(JanetcRegisterAllocator *dest, JanetcRegisterAllocator *src);
void janetc_regalloc_touch(JanetcRegisterAllocator *ra, int32_t reg);
/* Mutli-slot allocation disabled */
/*
int32_t janetc_regalloc_n(JanetcRegisterAllocator *ra, int32_t n);
int32_t janetc_regalloc_call(JanetcRegisterAllocator *ra, int32_t callee, int32_t nargs);
void janetc_regalloc_freerange(JanetcRegisterAllocator *ra, int32_t regstart, int32_t n);
*/
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,124 +20,82 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#include "state.h"
#include "vector.h"
/* Error reporting */
void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
int32_t fi;
const char *errstr = (const char *)janet_to_string(err);
JanetFiber **fibers = NULL;
fprintf(stderr, "%s error: %s\n", errtype, errstr);
while (fiber) {
janet_v_push(fibers, fiber);
fiber = fiber->child;
}
for (fi = janet_v_count(fibers) - 1; fi >= 0; fi--) {
fiber = fibers[fi];
int32_t i = fiber->frame;
if (i > 0) fprintf(stderr, " (fiber)\n");
while (i > 0) {
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
JanetFuncDef *def = NULL;
i = frame->prevframe;
fprintf(stderr, " in");
if (frame->func) {
def = frame->func->def;
fprintf(stderr, " %s", def->name ? (const char *)def->name : "<anonymous>");
if (def->source) {
fprintf(stderr, " [%s]", (const char *)def->source);
}
} else {
JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) {
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
if (!janet_checktype(name, JANET_NIL))
fprintf(stderr, " %s", (const char *)janet_to_string(name));
else
fprintf(stderr, " <cfunction>");
}
}
if (frame->flags & JANET_STACKFRAME_TAILCALL)
fprintf(stderr, " (tailcall)");
if (frame->func && frame->pc) {
int32_t off = (int32_t) (frame->pc - def->bytecode);
if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off];
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
} else {
fprintf(stderr, " pc=%d", off);
}
}
fprintf(stderr, "\n");
}
}
janet_v_free(fibers);
}
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#endif
/* Run a string */
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
JanetParser parser;
int errflags = 0;
int errflags = 0, done = 0;
int32_t index = 0;
int dudeol = 0;
int done = 0;
Janet ret = janet_wrap_nil();
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
if (where) janet_gcroot(janet_wrap_string(where));
if (NULL == sourcePath) sourcePath = "<unknown>";
janet_parser_init(&parser);
while (!errflags && !done) {
switch (janet_parser_status(&parser)) {
case JANET_PARSE_FULL:
{
Janet form = janet_parser_produce(&parser);
JanetCompileResult cres = janet_compile(form, env, where);
if (cres.status == JANET_COMPILE_OK) {
JanetFunction *f = janet_thunk(cres.funcdef);
JanetFiber *fiber = janet_fiber(f, 64);
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
if (status != JANET_SIGNAL_OK) {
janet_stacktrace(fiber, "runtime", ret);
errflags |= 0x01;
}
} else {
janet_stacktrace(cres.macrofiber, "compile",
janet_wrap_string(cres.error));
errflags |= 0x02;
}
/* While we haven't seen an error */
while (!done) {
/* Evaluate parsed values */
while (janet_parser_has_more(&parser)) {
Janet form = janet_parser_produce(&parser);
JanetCompileResult cres = janet_compile(form, env, where);
if (cres.status == JANET_COMPILE_OK) {
JanetFunction *f = janet_thunk(cres.funcdef);
JanetFiber *fiber = janet_fiber(f, 64, 0, NULL);
fiber->env = env;
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
janet_stacktrace(fiber, ret);
errflags |= 0x01;
done = 1;
}
} else {
ret = janet_wrap_string(cres.error);
if (cres.macrofiber) {
janet_eprintf("compile error in %s: ", sourcePath);
janet_stacktrace(cres.macrofiber, ret);
} else {
janet_eprintf("compile error in %s: %s\n", sourcePath,
(const char *)cres.error);
}
errflags |= 0x02;
done = 1;
}
}
if (done) break;
/* Dispatch based on parse state */
switch (janet_parser_status(&parser)) {
case JANET_PARSE_DEAD:
done = 1;
break;
case JANET_PARSE_ERROR:
case JANET_PARSE_ERROR: {
const char *e = janet_parser_error(&parser);
errflags |= 0x04;
fprintf(stderr, "parse error: %s\n", janet_parser_error(&parser));
ret = janet_cstringv(e);
janet_eprintf("parse error in %s: %s\n", sourcePath, e);
done = 1;
break;
}
case JANET_PARSE_ROOT:
case JANET_PARSE_PENDING:
if (index >= len) {
if (dudeol) {
errflags |= 0x04;
fprintf(stderr, "internal parse error: unexpected end of source\n");
} else {
dudeol = 1;
janet_parser_consume(&parser, '\n');
}
} else {
janet_parser_consume(&parser, bytes[index++]);
}
break;
case JANET_PARSE_ROOT:
if (index >= len) {
done = 1;
janet_parser_eof(&parser);
} else {
janet_parser_consume(&parser, bytes[index++]);
}
break;
}
}
/* Clean up and return errors */
janet_parser_deinit(&parser);
if (where) janet_gcunroot(janet_wrap_string(where));
if (out) *out = ret;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -20,11 +20,14 @@
* IN THE SOFTWARE.
*/
#include <janet/janet.h>
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "compile.h"
#include "util.h"
#include "vector.h"
#include "emit.h"
#endif
static JanetSlot janetc_quote(JanetFopts opts, int32_t argn, const Janet *argv) {
if (argn != 1) {
@@ -53,50 +56,60 @@ static JanetSlot qq_slots(JanetFopts opts, JanetSlot *slots, int makeop) {
return target;
}
static JanetSlot quasiquote(JanetFopts opts, Janet x) {
static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
if (depth == 0) {
janetc_cerror(opts.compiler, "quasiquote too deeply nested");
return janetc_cslot(janet_wrap_nil());
}
JanetSlot *slots = NULL;
switch (janet_type(x)) {
default:
return janetc_cslot(x);
case JANET_TUPLE:
{
int32_t i, len;
const Janet *tup = janet_unwrap_tuple(x);
len = janet_tuple_length(tup);
if (len > 1 && janet_checktype(tup[0], JANET_SYMBOL)) {
const uint8_t *head = janet_unwrap_symbol(tup[0]);
if (!janet_cstrcmp(head, "unquote"))
case JANET_TUPLE: {
int32_t i, len;
const Janet *tup = janet_unwrap_tuple(x);
len = janet_tuple_length(tup);
if (len > 1 && janet_checktype(tup[0], JANET_SYMBOL)) {
const uint8_t *head = janet_unwrap_symbol(tup[0]);
if (!janet_cstrcmp(head, "unquote")) {
if (level == 0) {
return janetc_value(janetc_fopts_default(opts.compiler), tup[1]);
} else {
level--;
}
} else if (!janet_cstrcmp(head, "quasiquote")) {
level++;
}
for (i = 0; i < len; i++)
janet_v_push(slots, quasiquote(opts, tup[i]));
return qq_slots(opts, slots, JOP_MAKE_TUPLE);
}
case JANET_ARRAY:
{
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]));
return qq_slots(opts, slots, JOP_MAKE_ARRAY);
}
for (i = 0; i < len; i++)
janet_v_push(slots, quasiquote(opts, 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);
}
case JANET_ARRAY: {
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));
return qq_slots(opts, slots, JOP_MAKE_ARRAY);
}
case JANET_TABLE:
case JANET_STRUCT:
{
const JanetKV *kv = NULL, *kvs = NULL;
int32_t len, cap;
janet_dictionary_view(x, &kvs, &len, &cap);
while ((kv = janet_dictionary_next(kvs, cap, kv))) {
JanetSlot key = quasiquote(opts, kv->key);
JanetSlot value = quasiquote(opts, kv->value);
key.flags &= ~JANET_SLOT_SPLICED;
value.flags &= ~JANET_SLOT_SPLICED;
janet_v_push(slots, key);
janet_v_push(slots, value);
}
return qq_slots(opts, slots,
janet_checktype(x, JANET_TABLE) ? JOP_MAKE_TABLE : JOP_MAKE_STRUCT);
case JANET_STRUCT: {
const JanetKV *kv = NULL, *kvs = NULL;
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);
key.flags &= ~JANET_SLOT_SPLICED;
value.flags &= ~JANET_SLOT_SPLICED;
janet_v_push(slots, key);
janet_v_push(slots, value);
}
return qq_slots(opts, slots,
janet_checktype(x, JANET_TABLE) ? JOP_MAKE_TABLE : JOP_MAKE_STRUCT);
}
}
}
@@ -105,7 +118,7 @@ static JanetSlot janetc_quasiquote(JanetFopts opts, int32_t argn, const Janet *a
janetc_cerror(opts.compiler, "expected 1 argument");
return janetc_cslot(janet_wrap_nil());
}
return quasiquote(opts, argv[0]);
return quasiquote(opts, argv[0], JANET_RECURSION_GUARD, 0);
}
static JanetSlot janetc_unquote(JanetFopts opts, int32_t argn, const Janet *argv) {
@@ -115,17 +128,17 @@ static JanetSlot janetc_unquote(JanetFopts opts, int32_t argn, const Janet *argv
return janetc_cslot(janet_wrap_nil());
}
/* Preform destructuring. Be careful to
* keep the order registers are freed.
/* Perform destructuring. Be careful to
* keep the order registers are freed.
* Returns if the slot 'right' can be freed. */
static int destructure(JanetCompiler *c,
Janet left,
JanetSlot right,
int (*leaf)(JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *attr),
JanetTable *attr) {
Janet left,
JanetSlot right,
int (*leaf)(JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *attr),
JanetTable *attr) {
switch (janet_type(left)) {
default:
janetc_cerror(c, "unexpected type in destructuring");
@@ -134,67 +147,92 @@ static int destructure(JanetCompiler *c,
/* Leaf, assign right to left */
return leaf(c, janet_unwrap_symbol(left), right, attr);
case JANET_TUPLE:
case JANET_ARRAY:
{
int32_t i, len;
const Janet *values;
janet_indexed_view(left, &values, &len);
for (i = 0; i < len; i++) {
JanetSlot nextright = janetc_farslot(c);
Janet subval = values[i];
if (i < 0x100) {
janetc_emit_ssu(c, JOP_GET_INDEX, nextright, right, (uint8_t) i, 1);
} else {
JanetSlot k = janetc_cslot(janet_wrap_integer(i));
janetc_emit_sss(c, JOP_GET, nextright, right, k, 1);
}
if (destructure(c, subval, nextright, leaf, attr))
janetc_freeslot(c, nextright);
case JANET_ARRAY: {
int32_t len = 0;
const Janet *values = NULL;
janet_indexed_view(left, &values, &len);
for (int32_t i = 0; i < len; i++) {
JanetSlot nextright = janetc_farslot(c);
Janet subval = values[i];
if (i < 0x100) {
janetc_emit_ssu(c, JOP_GET_INDEX, nextright, right, (uint8_t) i, 1);
} else {
JanetSlot k = janetc_cslot(janet_wrap_integer(i));
janetc_emit_sss(c, JOP_IN, nextright, right, k, 1);
}
if (destructure(c, subval, nextright, leaf, attr))
janetc_freeslot(c, nextright);
}
return 1;
}
return 1;
case JANET_TABLE:
case JANET_STRUCT:
{
const JanetKV *kvs = NULL;
int32_t i, cap, len;
janet_dictionary_view(left, &kvs, &len, &cap);
for (i = 0; i < cap; i++) {
if (janet_checktype(kvs[i].key, JANET_NIL)) continue;
JanetSlot nextright = janetc_farslot(c);
JanetSlot k = janetc_value(janetc_fopts_default(c), kvs[i].key);
janetc_emit_sss(c, JOP_GET, nextright, right, k, 1);
if (destructure(c, kvs[i].value, nextright, leaf, attr))
janetc_freeslot(c, nextright);
}
case JANET_STRUCT: {
const JanetKV *kvs = NULL;
int32_t cap = 0, len = 0;
janet_dictionary_view(left, &kvs, &len, &cap);
for (int32_t i = 0; i < cap; i++) {
if (janet_checktype(kvs[i].key, JANET_NIL)) continue;
JanetSlot nextright = janetc_farslot(c);
JanetSlot k = janetc_value(janetc_fopts_default(c), kvs[i].key);
janetc_emit_sss(c, JOP_IN, nextright, right, k, 1);
if (destructure(c, kvs[i].value, nextright, leaf, attr))
janetc_freeslot(c, nextright);
}
return 1;
}
return 1;
}
}
/* Create a source map for definitions. */
static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
Janet *tup = janet_tuple_begin(3);
tup[0] = janet_wrap_string(c->source);
tup[1] = janet_wrap_integer(c->current_mapping.start);
tup[2] = janet_wrap_integer(c->current_mapping.end);
tup[0] = c->source ? janet_wrap_string(c->source) : janet_wrap_nil();
tup[1] = janet_wrap_integer(c->current_mapping.line);
tup[2] = janet_wrap_integer(c->current_mapping.column);
return janet_tuple_end(tup);
}
static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv) {
/*JanetFopts subopts = janetc_fopts_default(opts.compiler);*/
/*JanetSlot ret, dest;*/
Janet head;
if (argn != 2) {
janetc_cerror(opts.compiler, "expected 2 arguments");
return janetc_cslot(janet_wrap_nil());
}
head = argv[0];
if (!janet_checktype(head, JANET_SYMBOL)) {
janetc_cerror(opts.compiler, "expected symbol");
JanetFopts subopts = janetc_fopts_default(opts.compiler);
if (janet_checktype(argv[0], JANET_SYMBOL)) {
/* Normal var - (set a 1) */
const uint8_t *sym = janet_unwrap_symbol(argv[0]);
JanetSlot dest = janetc_resolve(opts.compiler, sym);
if (!(dest.flags & JANET_SLOT_MUTABLE)) {
janetc_cerror(opts.compiler, "cannot set constant");
return janetc_cslot(janet_wrap_nil());
}
subopts.flags = JANET_FOPTS_HINT;
subopts.hint = dest;
JanetSlot ret = janetc_value(subopts, argv[1]);
janetc_copy(opts.compiler, dest, ret);
return ret;
} else if (janet_checktype(argv[0], JANET_TUPLE)) {
/* Set a field (setf behavior) - (set (tab :key) 2) */
const Janet *tup = janet_unwrap_tuple(argv[0]);
/* Tuple must have 2 elements */
if (janet_tuple_length(tup) != 2) {
janetc_cerror(opts.compiler, "expected 2 element tuple for l-value to set");
return janetc_cslot(janet_wrap_nil());
}
JanetSlot ds = janetc_value(subopts, tup[0]);
JanetSlot key = janetc_value(subopts, tup[1]);
/* Can't be tail position because we will emit a PUT instruction afterwards */
/* Also can't drop either */
opts.flags &= ~(JANET_FOPTS_TAIL | JANET_FOPTS_DROP);
JanetSlot rvalue = janetc_value(opts, argv[1]);
/* Emit the PUT instruction */
janetc_emit_sss(opts.compiler, JOP_PUT, ds, key, rvalue, 0);
return rvalue;
} else {
/* Error */
janetc_cerror(opts.compiler, "expected symbol or tuple for l-value to set");
return janetc_cslot(janet_wrap_nil());
}
return janetc_sym_lvalue(opts, janet_unwrap_symbol(head), argv[1]);
}
/* Add attributes to a global def or var table */
@@ -207,11 +245,11 @@ static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv)
default:
janetc_cerror(c, "could not add metadata to binding");
break;
case JANET_SYMBOL:
case JANET_KEYWORD:
janet_table_put(tab, attr, janet_wrap_true());
break;
case JANET_STRING:
janet_table_put(tab, janet_csymbolv(":doc"), attr);
janet_table_put(tab, janet_ckeywordv("doc"), attr);
break;
}
}
@@ -235,8 +273,8 @@ static JanetSlot dohead(JanetCompiler *c, JanetFopts opts, Janet *head, int32_t
/* Def or var a symbol in a local scope */
static int namelocal(JanetCompiler *c, const uint8_t *head, int32_t flags, JanetSlot ret) {
int isUnnamedRegister = !(ret.flags & JANET_SLOT_NAMED) &&
ret.index > 0 &&
ret.envindex >= 0;
ret.index > 0 &&
ret.envindex >= 0;
if (!isUnnamedRegister) {
/* Slot is not able to be named */
JanetSlot localslot = janetc_farslot(c);
@@ -249,21 +287,20 @@ static int namelocal(JanetCompiler *c, const uint8_t *head, int32_t flags, Janet
}
static int varleaf(
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *attr) {
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *reftab) {
if (c->scope->flags & JANET_SCOPE_TOP) {
/* Global var, generate var */
JanetSlot refslot;
JanetTable *reftab = janet_table(1);
reftab->proto = attr;
JanetTable *entry = janet_table_clone(reftab);
JanetArray *ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
janet_table_put(reftab, janet_csymbolv(":ref"), janet_wrap_array(ref));
janet_table_put(reftab, janet_csymbolv(":source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(reftab));
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)));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(entry));
refslot = janetc_cslot(janet_wrap_array(ref));
janetc_emit_ssu(c, JOP_PUT_INDEX, refslot, s, 0, 0);
return 1;
@@ -283,20 +320,19 @@ static JanetSlot janetc_var(JanetFopts opts, int32_t argn, const Janet *argv) {
}
static int defleaf(
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *attr) {
JanetCompiler *c,
const uint8_t *sym,
JanetSlot s,
JanetTable *tab) {
if (c->scope->flags & JANET_SCOPE_TOP) {
JanetTable *tab = janet_table(2);
janet_table_put(tab, janet_csymbolv(":source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
tab->proto = attr;
JanetSlot valsym = janetc_cslot(janet_csymbolv(":value"));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(tab));
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));
/* Add env entry to env */
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(tab));
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);
@@ -353,8 +389,8 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Set target for compilation */
target = (drop || tail)
? janetc_cslot(janet_wrap_nil())
: janetc_gettarget(opts);
? janetc_cslot(janet_wrap_nil())
: janetc_gettarget(opts);
/* Compile condition */
janetc_scope(&condscope, c, 0, "if");
@@ -369,8 +405,9 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
falsebody = truebody;
truebody = temp;
}
janetc_scope(&tempscope, c, 0, "if-body");
target = janetc_value(bodyopts, truebody);
janetc_scope(&tempscope, c, 0, "if-true");
right = janetc_value(bodyopts, truebody);
if (!drop && !tail) janetc_copy(c, target, right);
janetc_popscope(c);
janetc_throwaway(bodyopts, falsebody);
janetc_popscope(c);
@@ -446,6 +483,75 @@ static int32_t janetc_addfuncdef(JanetCompiler *c, JanetFuncDef *def) {
return janet_v_count(scope->defs) - 1;
}
/*
* break
*
* jump :end or retn if in function
*/
static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
JanetScope *scope = c->scope;
if (argn > 1) {
janetc_cerror(c, "expected at most 1 argument");
return janetc_cslot(janet_wrap_nil());
}
/* Find scope to break from */
while (scope) {
if (scope->flags & (JANET_SCOPE_FUNCTION | JANET_SCOPE_WHILE))
break;
scope = scope->parent;
}
if (NULL == scope) {
janetc_cerror(c, "break must occur in while loop or closure");
return janetc_cslot(janet_wrap_nil());
}
/* Emit code to break from that scope */
JanetFopts subopts = janetc_fopts_default(c);
if (scope->flags & JANET_SCOPE_FUNCTION) {
if (!(scope->flags & JANET_SCOPE_WHILE) && argn) {
/* Closure body with return argument */
subopts.flags |= JANET_FOPTS_TAIL;
JanetSlot ret = janetc_value(subopts, argv[0]);
ret.flags |= JANET_SLOT_RETURNED;
return ret;
} else {
/* while loop IIFE or no argument */
if (argn) {
subopts.flags |= JANET_FOPTS_DROP;
janetc_value(subopts, argv[0]);
}
janetc_emit(c, JOP_RETURN_NIL);
JanetSlot s = janetc_cslot(janet_wrap_nil());
s.flags |= JANET_SLOT_RETURNED;
return s;
}
} else {
if (argn) {
subopts.flags |= JANET_FOPTS_DROP;
janetc_value(subopts, argv[0]);
}
/* Tag the instruction so the while special can turn it into a proper jump */
janetc_emit(c, 0x80 | JOP_JUMP);
return janetc_cslot(janet_wrap_nil());
}
}
/* Check if a form matches the pattern (not= nil _) */
static int janetc_check_notnil_form(Janet x, Janet *capture) {
if (!janet_checktype(x, JANET_TUPLE)) return 0;
JanetTuple tup = janet_unwrap_tuple(x);
if (!janet_checktype(tup[0], JANET_FUNCTION)) return 0;
if (3 != janet_tuple_length(tup)) return 0;
JanetFunction *fun = janet_unwrap_function(tup[0]);
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
if (tag != JANET_FUN_NEQ) return 0;
if (!janet_checktype(tup[1], JANET_NIL)) return 0;
*capture = tup[2];
return 1;
}
/*
* :whiletop
* ...
@@ -462,6 +568,9 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
JanetScope tempscope;
int32_t labelwt, labeld, labeljt, labelc, i;
int infinite = 0;
int is_notnil_form = 0;
uint8_t ifjmp = JOP_JUMP_IF;
uint8_t ifnjmp = JOP_JUMP_IF_NOT;
if (argn < 2) {
janetc_cerror(c, "expected at least 2 arguments");
@@ -470,15 +579,28 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
labelwt = janet_v_count(c->buffer);
janetc_scope(&tempscope, c, 0, "while");
janetc_scope(&tempscope, c, JANET_SCOPE_WHILE, "while");
/* Check for `(not= nil _)` in condition, and if so, use the
* jmpnl or jmpnn instructions. This let's us implement `(each ...)`
* more efficiently. */
Janet condform = argv[0];
if (janetc_check_notnil_form(condform, &condform)) {
is_notnil_form = 1;
ifjmp = JOP_JUMP_IF_NOT_NIL;
ifnjmp = JOP_JUMP_IF_NIL;
}
/* Compile condition */
cond = janetc_value(subopts, argv[0]);
cond = janetc_value(subopts, condform);
/* Check for constant condition */
if (cond.flags & JANET_SLOT_CONSTANT) {
/* Loop never executes */
if (!janet_truthy(cond.constant)) {
int never_executes = is_notnil_form
? janet_checktype(cond.constant, JANET_NIL)
: !janet_truthy(cond.constant);
if (never_executes) {
janetc_popscope(c);
return janetc_cslot(janet_wrap_nil());
}
@@ -488,8 +610,8 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
/* Infinite loop does not need to check condition */
labelc = infinite
? 0
: janetc_emit_si(c, JOP_JUMP_IF_NOT, cond, 0, 0);
? 0
: janetc_emit_si(c, ifnjmp, cond, 0, 0);
/* Compile body */
for (i = 1; i < argn; i++) {
@@ -500,18 +622,19 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
/* Check if closure created in while scope. If so,
* recompile in a function scope. */
if (tempscope.flags & JANET_SCOPE_CLOSURE) {
subopts = janetc_fopts_default(c);
tempscope.flags |= JANET_SCOPE_UNUSED;
janetc_popscope(c);
janet_v__cnt(c->buffer) = labelwt;
janet_v__cnt(c->mapbuffer) = labelwt;
if (c->buffer) janet_v__cnt(c->buffer) = labelwt;
if (c->mapbuffer) janet_v__cnt(c->mapbuffer) = labelwt;
janetc_scope(&tempscope, c, JANET_SCOPE_FUNCTION, "while-iife");
/* Recompile in the function scope */
cond = janetc_value(subopts, argv[0]);
cond = janetc_value(subopts, condform);
if (!(cond.flags & JANET_SLOT_CONSTANT)) {
/* If not an infinte loop, return nil when condition false */
janetc_emit_si(c, JOP_JUMP_IF, cond, 2, 0);
/* If not an infinite loop, return nil when condition false */
janetc_emit_si(c, ifjmp, cond, 2, 0);
janetc_emit(c, JOP_RETURN_NIL);
}
for (i = 1; i < argn; i++) {
@@ -522,27 +645,36 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
int32_t tempself = janetc_regalloc_temp(&tempscope.ra, JANETC_REGTEMP_0);
janetc_emit(c, JOP_LOAD_SELF | (tempself << 8));
janetc_emit(c, JOP_TAILCALL | (tempself << 8));
janetc_regalloc_freetemp(&c->scope->ra, tempself, JANETC_REGTEMP_0);
/* Compile function */
JanetFuncDef *def = janetc_pop_funcdef(c);
def->name = janet_cstring("_while");
janet_def_addflags(def);
int32_t defindex = janetc_addfuncdef(c, def);
/* And then load the closure and call it. */
int32_t cloreg = janetc_regalloc_temp(&c->scope->ra, JANETC_REGTEMP_0);
janetc_emit(c, JOP_CLOSURE | (cloreg << 8) | (defindex << 16));
janetc_emit(c, JOP_CALL | (cloreg << 8) | (cloreg << 16));
janetc_regalloc_free(&c->scope->ra, cloreg);
janetc_regalloc_freetemp(&c->scope->ra, cloreg, JANETC_REGTEMP_0);
c->scope->flags |= JANET_SCOPE_CLOSURE;
return janetc_cslot(janet_wrap_nil());
}
/* Compile jump to whiletop */
/* Compile jump to :whiletop */
labeljt = janet_v_count(c->buffer);
janetc_emit(c, JOP_JUMP);
/* Calculate jumps */
labeld = janet_v_count(c->buffer);
if (!infinite) c->buffer[labelc] |= (labeld - labelc) << 16;
c->buffer[labeljt] |= (labelwt - labeljt) << 8;
if (!infinite) c->buffer[labelc] |= (uint32_t)(labeld - labelc) << 16;
c->buffer[labeljt] |= (uint32_t)(labelwt - labeljt) << 8;
/* Calculate breaks */
for (int32_t i = labelwt; i < labeld; i++) {
if (c->buffer[i] == (0x80 | JOP_JUMP)) {
c->buffer[i] = JOP_JUMP | ((labeld - i) << 8);
}
}
/* Pop scope and return nil slot */
janetc_popscope(c);
@@ -556,23 +688,25 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetSlot ret;
Janet head;
JanetScope fnscope;
int32_t paramcount, argi, parami, arity, defindex, i;
int32_t paramcount, argi, parami, arity, min_arity, max_arity, defindex, i;
JanetFopts subopts = janetc_fopts_default(c);
const Janet *params;
const char *errmsg = NULL;
/* Function flags */
int vararg = 0;
int fixarity = 1;
int structarg = 0;
int allow_extra = 0;
int selfref = 0;
int seenamp = 0;
int seenopt = 0;
/* Begin function */
c->scope->flags |= JANET_SCOPE_CLOSURE;
janetc_scope(&fnscope, c, JANET_SCOPE_FUNCTION, "function");
if (argn < 2) {
errmsg = "expected at least 2 arguments to function literal";
if (argn == 0) {
errmsg = "expected at least 1 argument to function literal";
goto error;
}
@@ -588,6 +722,9 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
goto error;
}
/* Keep track of destructured parameters */
JanetSlot *destructed_params = NULL;
/* Compile function parameters */
params = janet_unwrap_tuple(argv[parami]);
paramcount = janet_tuple_length(params);
@@ -596,27 +733,68 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
Janet param = params[i];
if (janet_checktype(param, JANET_SYMBOL)) {
/* Check for varargs and unfixed arity */
if ((!seenamp) &&
(0 == janet_cstrcmp(janet_unwrap_symbol(param), "&"))) {
seenamp = 1;
fixarity = 0;
if (i == paramcount - 1) {
if (!janet_cstrcmp(janet_unwrap_symbol(param), "&")) {
if (seenamp) {
errmsg = "& in unexpected location";
goto error;
} else if (i == paramcount - 1) {
allow_extra = 1;
arity--;
} else if (i == paramcount - 2) {
vararg = 1;
arity -= 2;
} else {
errmsg = "variable argument symbol in unexpected location";
errmsg = "& in unexpected location";
goto error;
}
seenamp = 1;
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&opt")) {
if (seenopt) {
errmsg = "only one &opt allowed";
goto error;
} else if (i == paramcount - 1) {
errmsg = "&opt cannot be last item in parameter list";
goto error;
}
min_arity = i;
arity--;
seenopt = 1;
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&keys")) {
if (seenamp) {
errmsg = "&keys in unexpected location";
goto error;
} else if (i == paramcount - 2) {
vararg = 1;
structarg = 1;
arity -= 2;
} else {
errmsg = "&keys in unexpected location";
goto error;
}
seenamp = 1;
} else {
janetc_nameslot(c, janet_unwrap_symbol(param), janetc_farslot(c));
}
} else {
destructure(c, param, janetc_farslot(c), defleaf, NULL);
janet_v_push(destructed_params, janetc_farslot(c));
}
}
/* Compile destructed params */
int32_t j = 0;
for (i = 0; i < paramcount; i++) {
Janet param = params[i];
if (!janet_checktype(param, JANET_SYMBOL)) {
JanetSlot reg = destructed_params[j++];
destructure(c, param, reg, defleaf, NULL);
janetc_freeslot(c, reg);
}
}
janet_v_free(destructed_params);
max_arity = (vararg || allow_extra) ? INT32_MAX : arity;
if (!seenopt) min_arity = arity;
/* Check for self ref */
if (selfref) {
JanetSlot slot = janetc_farslot(c);
@@ -628,20 +806,25 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Compile function body */
if (parami + 1 == argn) {
janetc_emit(c, JOP_RETURN_NIL);
} else for (argi = parami + 1; argi < argn; argi++) {
subopts.flags = (argi == (argn - 1)) ? JANET_FOPTS_TAIL : JANET_FOPTS_DROP;
janetc_value(subopts, argv[argi]);
if (c->result.status == JANET_COMPILE_ERROR)
goto error2;
} else {
for (argi = parami + 1; argi < argn; argi++) {
subopts.flags = (argi == (argn - 1)) ? JANET_FOPTS_TAIL : JANET_FOPTS_DROP;
janetc_value(subopts, argv[argi]);
if (c->result.status == JANET_COMPILE_ERROR)
goto error2;
}
}
/* Build function */
def = janetc_pop_funcdef(c);
def->arity = arity;
if (fixarity) def->flags |= JANET_FUNCDEF_FLAG_FIXARITY;
def->min_arity = min_arity;
def->max_arity = max_arity;
if (vararg) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
if (structarg) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
if (selfref) def->name = janet_unwrap_symbol(head);
janet_def_addflags(def);
defindex = janetc_addfuncdef(c, def);
/* Ensure enough slots for vararg function. */
@@ -661,6 +844,7 @@ error2:
/* Keep in lexicographic order */
static const JanetSpecial janetc_specials[] = {
{"break", janetc_break},
{"def", janetc_def},
{"do", janetc_do},
{"fn", janetc_fn},
@@ -677,9 +861,9 @@ static const JanetSpecial janetc_specials[] = {
/* Find a special */
const JanetSpecial *janetc_special(const uint8_t *name) {
return janet_strbinsearch(
&janetc_specials,
sizeof(janetc_specials)/sizeof(JanetSpecial),
sizeof(JanetSpecial),
name);
&janetc_specials,
sizeof(janetc_specials) / sizeof(JanetSpecial),
sizeof(JanetSpecial),
name);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 Calvin Rose
* Copyright (c) 2020 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
@@ -27,10 +27,18 @@
/* The VM state. Rather than a struct that is passed
* around, the vm state is global for simplicity. If
* at some point a a global state object, or context,
* is required to be passed around, this is waht would
* be in it. However, thread local globals for interpreter
* state should allow easy multithreading. */
* at some point a global state object, or context,
* is required to be passed around, this is what would
* be in it. However, thread local global variables for interpreter
* state should allow easy multi-threading. */
typedef struct JanetScratch JanetScratch;
/* Top level dynamic bindings */
extern JANET_THREAD_LOCAL JanetTable *janet_vm_top_dyns;
/* Cache the core environment */
extern JANET_THREAD_LOCAL JanetTable *janet_vm_core_env;
/* How many VM stacks have been entered */
extern JANET_THREAD_LOCAL int janet_vm_stackn;
@@ -38,11 +46,21 @@ extern JANET_THREAD_LOCAL int janet_vm_stackn;
/* The current running fiber on the current thread.
* Set and unset by janet_run. */
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_root_fiber;
/* The global registry for c functions. Used to store metadata
/* The current pointer to the inner most jmp_buf. The current
* return point for panics. */
extern JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf;
extern JANET_THREAD_LOCAL Janet *janet_vm_return_reg;
/* The global registry for c functions. Used to store meta-data
* along with otherwise bare c function pointers. */
extern JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
/* Registry for abstract abstract types that can be marshalled.
* We need this to look up the constructors when unmarshalling. */
extern JANET_THREAD_LOCAL JanetTable *janet_vm_abstract_registry;
/* Immutable value cache */
extern JANET_THREAD_LOCAL const uint8_t **janet_vm_cache;
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_capacity;
@@ -51,13 +69,36 @@ extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_deleted;
/* Garbage collection */
extern JANET_THREAD_LOCAL void *janet_vm_blocks;
extern JANET_THREAD_LOCAL uint32_t janet_vm_gc_interval;
extern JANET_THREAD_LOCAL uint32_t janet_vm_next_collection;
extern JANET_THREAD_LOCAL size_t janet_vm_gc_interval;
extern JANET_THREAD_LOCAL size_t janet_vm_next_collection;
extern JANET_THREAD_LOCAL size_t janet_vm_block_count;
extern JANET_THREAD_LOCAL int janet_vm_gc_suspend;
/* GC roots */
extern JANET_THREAD_LOCAL Janet *janet_vm_roots;
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
extern JANET_THREAD_LOCAL size_t janet_vm_root_count;
extern JANET_THREAD_LOCAL size_t janet_vm_root_capacity;
/* Scratch memory */
extern JANET_THREAD_LOCAL JanetScratch **janet_scratch_mem;
extern JANET_THREAD_LOCAL size_t janet_scratch_cap;
extern JANET_THREAD_LOCAL size_t janet_scratch_len;
/* Recursionless traversal of data structures */
typedef struct {
JanetGCObject *self;
JanetGCObject *other;
int32_t index;
int32_t index2;
} JanetTraversalNode;
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal;
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_top;
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_base;
/* Setup / teardown */
#ifdef JANET_THREADS
void janet_threads_init(void);
void janet_threads_deinit(void);
#endif
#endif /* JANET_STATE_H_defined */

Some files were not shown because too many files have changed in this diff Show More