Compare commits

...

1863 Commits

Author SHA1 Message Date
Calvin Rose 7bae7d9efd Merge changes from bundle-tools branch:
- Update file IO to explicitly use 64bit ftell/fseek
- Add env argument to eval
- Allow naming function literals with keywords.
2024-05-26 12:04:35 -05:00
Calvin Rose ae2c5820a1 Fix janet_strerror when _GNU_SOURCE defined. 2024-05-25 13:24:01 -05:00
Calvin Rose 60e0c8ea92 Ignore gcov 2024-05-25 09:25:27 -05:00
Calvin Rose 7d3acc0ed6 Get rid of "extended locale" support.
While useful on some platforms, behavior seems to be different across
the board, making use difficult.
2024-05-19 18:01:20 -05:00
Calvin Rose 2637b33957 Include locale.h and xlocale.h on some platforms. 2024-05-19 17:40:39 -05:00
Calvin Rose 58ccb66659 Move janet_buffer_dtostr 2024-05-19 17:14:21 -05:00
Calvin Rose 634429cf61 Merge branch 'locales' 2024-05-19 17:05:49 -05:00
Calvin Rose 03166a745a Disallow nan and inf in jdn. 2024-05-19 13:25:25 -05:00
Calvin Rose ace60e1898 Add ev/with-*lock macros. 2024-05-18 17:55:47 -05:00
Calvin Rose 876b7f106f OpenBSD does not work with LC_*_MASK stuff. 2024-05-18 17:22:10 -05:00
Calvin Rose 809b6589a1 Put limits.h back. 2024-05-18 15:31:23 -05:00
Calvin Rose 02f53ca014 Formatting. 2024-05-18 15:21:37 -05:00
Calvin Rose 0b03ddb21b More work on setting locale for extended locale support. 2024-05-18 15:20:22 -05:00
Calvin Rose ea5d4fd3af JANET_BSD not defined on apple. 2024-05-18 14:24:51 -05:00
Calvin Rose e6b73f8cd1 BSD, use xlocale for thread safe functionality 2024-05-18 14:11:05 -05:00
Calvin Rose af232ef729 windows needs a distinct implementation from posix for thread safety.
I must say, the windows solution is a lot simpler.
2024-05-18 14:02:20 -05:00
Calvin Rose 2e2f8abfc0 Work on add locales.
Need to be careful not to mess with %j formatter, or
in some other places.
2024-05-18 13:23:33 -05:00
Calvin Rose 91a583db27
Merge pull request #1448 from znley/master
Add LoongArch64 support
2024-05-18 06:33:07 -05:00
znley c1647a74c5 Add LoongArch64 support 2024-05-18 07:18:59 +00:00
Calvin Rose 721f280966 Add `with-env`. 2024-05-16 21:52:49 -05:00
Calvin Rose e914eaf055 Update CHANGELOG.md 2024-05-16 21:37:08 -05:00
Calvin Rose fe54013679 Update naming *module-make-env* for #1447 2024-05-16 19:11:25 -05:00
Calvin Rose fdaf2e1594 Add *module/make-env* 2024-05-16 19:10:30 -05:00
Calvin Rose 9946f3bdf4 Add buffer/format-at
Move changes over from bundle-tools branch and add testing.
2024-05-15 20:16:42 -05:00
Calvin Rose c747e8d16c Address some compiler linter messages on openbsd 2024-05-15 18:20:20 -05:00
Calvin Rose 3e402d397e Use older openbsd build for CI. 2024-05-15 18:16:19 -05:00
Calvin Rose 0350834cd3 By default, require and import extend current env. 2024-05-15 07:40:21 -05:00
Calvin Rose 60e22d9703
Merge pull request #1445 from wishdev/defbind-alias
Add ffi/defbind-alias
2024-05-11 14:25:03 -05:00
John W Higgins ee7362e847 Add ffi/defbind-alias 2024-05-09 21:31:22 -07:00
Calvin Rose 369f96b80e Update README to prefer Zulip. 2024-05-03 07:51:35 -05:00
Calvin Rose 7c5ed04ab1 A few minor improvements.
- Add long-form CLI options
- Update changelog.
- Use snprintf instead of sprintf for linters.
2024-05-02 09:13:29 -05:00
Calvin Rose 4779a445e0 Fix BSD/Macos issue for #1431 2024-04-26 19:32:47 -05:00
Calvin Rose f0f1b7ce9e Address #1431 - level-trigger mode for net/accept-loop
In the edge-trigger mode before this change, if a socket
receives 2 connections before one can be handled, then only a single
connection is handle and 1 connection will never be handled in some
cases. Reverting to level-trigger mode makes this impossible.
2024-04-26 19:28:20 -05:00
Calvin Rose 7c9157a0ed Remove unneeded `string` functions. 2024-04-26 18:11:10 -05:00
Calvin Rose 522a6cb435
Merge pull request #1440 from ahgamut/cosmo-build
Build janet with Cosmopolitan Libc
2024-04-21 08:06:51 -05:00
Gautham d0d551d739 remove superconfigure recipe 2024-04-21 01:16:54 -05:00
Gautham 71a123fef7 apelink 2024-04-21 01:14:58 -05:00
Gautham 3f40c8d7fb fix typo 2024-04-21 01:12:59 -05:00
Gautham 983c2e5499 simplify build to use only cosmocc 2024-04-21 01:10:06 -05:00
Gautham eebb4c3ade remove logging 2024-04-20 22:35:04 -05:00
Gautham 50425eac72 typo 2024-04-20 22:23:29 -05:00
Gautham 382ff77bbe typo 2024-04-20 22:16:23 -05:00
Gautham bf680fb5d3 simplify janet APE build 2024-04-20 22:09:10 -05:00
Gautham 4ed7db4f91 simplify naming 2024-04-19 10:56:46 -05:00
Calvin Rose bf19920d65 Improve casting. 2024-04-18 03:29:45 -05:00
Gautham 174b5f6686 missing folder 2024-04-16 22:24:31 -05:00
Gautham 4173645b81 missing folder 2024-04-16 22:23:12 -05:00
Gautham af511f1f55 patch folder location 2024-04-16 22:15:54 -05:00
Gautham 83c6080380 yml config for building with Cosmopolitan Libc 2024-04-16 22:02:31 -05:00
Calvin Rose 2f0c789ea1 More work to address #1391
Properly set read_fiber and write_fiber to NULL when unused.
This was causing extra listening in the poll implemenation leading to
busy loops where a read was accidentally listening for POLLOUT.
2024-04-15 21:32:17 -05:00
Calvin Rose a9b8f8e8a9 Address #1391 - set fd to negative value if not used.
See https://groups.google.com/g/comp.unix.programmer/c/bNNadBIEpTo/m/G5gs1mqNhbIJ?pli=1 for a conversation and workaround.
2024-04-15 18:12:42 -05:00
Calvin Rose f92f3eb6fa Address #1434 - add dynamic bindings for module state. 2024-04-15 16:20:13 -05:00
Calvin Rose 89e74dca3e Update freebsd build 2024-04-15 16:02:34 -05:00
Calvin Rose f2e86d2f8d
Merge pull request #1432 from wishdev/os/clock
Add additional format options for os/clock
2024-04-15 07:34:02 -05:00
John W Higgins 623da131e5 os/clock docstring typos 2024-03-27 22:32:27 -07:00
John W Higgins e89ec31ae5 Add additional format options for os/clock 2024-03-27 22:32:27 -07:00
Calvin Rose 68a6ed208e
Merge pull request #1430 from pepe/fix-win-clean
Add exists test for dist directory on build command clean
2024-03-24 10:49:34 -07:00
Calvin Rose c01b32c4f3
Merge pull request #1429 from pepe/prepare-134 2024-03-22 06:52:40 -07:00
Josef Pospíšil ee11ff9da9 Move date and sort people 2024-03-22 07:54:23 +01:00
Josef Pospíšil ed56d5d6ff Add @llmII to docs 2024-03-20 10:40:30 +01:00
Josef Pospíšil b317ab755c One more commit 2024-03-20 10:34:30 +01:00
Josef Pospíšil 9819994999 Correct changelog 2024-03-20 10:32:13 +01:00
Josef Pospíšil e9dbaa81d2 Add exists test on clean 2024-03-20 10:18:42 +01:00
Josef Pospíšil 9f9146ffae Prepare for 1.34.0 release 2024-03-20 10:11:08 +01:00
Josef Pospíšil 9d9732af97 Update changelog for 1.34.0 2024-03-20 09:57:57 +01:00
Calvin Rose ebb8fa9787
Merge pull request #1410 from sogaiu/ev-deadline-and-friends-doc-tweaks
Doc tweaks for ev/deadline and ev/with-deadline
2024-03-12 06:18:40 -07:00
Calvin Rose 9e6abbf4d4 Fix asm roundtrip issue. 2024-03-10 09:07:11 -05:00
Calvin Rose 6032a6d658
Merge pull request #1414 from MaxGyver83/master
Fix documentation of peg/replace
2024-02-24 11:06:16 -08:00
Max Schillinger c29ab22e6d Fix documentation of peg/replace 2024-02-23 12:46:45 +01:00
sogaiu 592ac4904c Doc tweaks for ev/deadline and ev/with-deadline 2024-02-23 10:59:43 +09:00
Calvin Rose 03ae2ec153
Merge pull request #1394 from amano-kenji/master
Improve documentation on subprocess API
2024-02-19 11:25:17 -08:00
Calvin Rose 3bc42d0d37 Only re-register when using poll. 2024-02-19 13:19:23 -06:00
Calvin Rose 12630d3e54 Register stream on unmarshal 2024-02-19 13:16:45 -06:00
Calvin Rose c9897f99c3 Address #1405 - don't try and resume fibers that can't be resumed.
FOr fibers that _can_ be resumed and then get cancelled, the sched_id
will be incremented later prevent the spurious wake ups.
2024-02-19 08:37:49 -06:00
Calvin Rose e66dc14b3a Formatting. 2024-02-17 13:35:07 -06:00
Calvin Rose 7a2868c147 Fix macex1 to keep syntax location for all tuples - Address #1404 2024-02-17 13:34:23 -06:00
Calvin Rose 9e0daaee09 Address #1401 - restore if-let tail calls.
Changes to avoid multiple macro expansions of the "false" branch caused
a regression in this functionality.
2024-02-15 06:30:26 -06:00
Calvin Rose c293c7de93
Merge pull request #1402 from sogaiu/each-body-before-set
Swap set / body order for each (#1400)
2024-02-15 04:05:15 -08:00
Calvin Rose 49eb5f8563
Merge pull request #1403 from llmII/fix-os-proc-wait
Fix: make `proc_get_status` compliant to OS documentation.
2024-02-15 04:01:09 -08:00
amano.kenji 674b375b2c
Improve documentation on subprocess API 2024-02-13 05:34:52 +00:00
llmII 7e94c091eb
Fix: os/proc-wait
As discused over gitter, `WIFSIGNALED` macro must be checked before one
uses the WTERMSIG macro. This change reflects that necessity and adds a
final else clause which will panic if no status code could be
determined.
2024-02-12 23:06:08 -06:00
sogaiu 5885ccba61 Swap set / body order for each (#1400) 2024-02-13 11:12:18 +09:00
Calvin Rose 431ecd3d1a Abort on assert failure instead of exit 2024-02-03 14:12:10 -06:00
Calvin Rose f6df8ff935 Expose _exit to skip certain cleanup with os/exit 2024-02-03 14:12:10 -06:00
Calvin Rose 3fd70f0951 Update debug meson options. 2024-02-03 14:12:10 -06:00
Calvin Rose bebb635d4f
Merge pull request #1392 from sogaiu/propagate-docstring-additions
Add to propagate docstring (#1365)
2024-02-03 10:52:27 -08:00
sogaiu 354896bc4b Add to propagate docstring (#1365) 2024-02-03 15:48:19 +09:00
Calvin Rose 5ddefff27e
Merge pull request #1389 from sogaiu/fiber-last-value-doc-tweak 2024-02-02 08:42:48 -08:00
sogaiu 91827eef4f Tweak fiber/last-value docstring 2024-02-02 19:06:56 +09:00
Calvin Rose 9c14c09962 Add explicit stdatomic config setting for #1374
There was some hacky workaround code for development versions of TCC
that interfered with other compilers and technically was not legal
c99.
2024-01-28 15:53:41 -06:00
Calvin Rose e85a84171f Revert local change that removes stdatomic.h 2024-01-28 07:58:22 -06:00
Calvin Rose 3a4f86c3d7 Make host and port configurable for suite-ev.janet 2024-01-28 07:56:59 -06:00
Calvin Rose 5e75963312
Merge pull request #1367 from sogaiu/debug-stacktrace-doc-tweak
Tweak debug/stacktrace docstring (#1365)
2024-01-28 05:33:11 -08:00
Calvin Rose 184d9289b5
Merge pull request #1371 from pepe/destructuring-typo
Fix typo in destructuring
2024-01-28 05:33:05 -08:00
Calvin Rose b7ff9577c0
Merge pull request #1373 from sogaiu/module-expand-path-doc-suggestion
Address #1370
2024-01-28 05:32:50 -08:00
sogaiu 942a1aaac6 Address #1370 2024-01-27 21:20:27 +09:00
Josef Pospíšil 69f0fe004d Fix typo in destructuring 2024-01-26 14:36:56 +01:00
sogaiu 2a04347a42 Tweak debug/stacktrace docstring (#1365) 2024-01-24 16:52:37 +09:00
Calvin Rose 1394f1a5c0
Merge pull request #1364 from sogaiu/module-expand-path-doc-tweak
Cosmetically tweak module/expand-path docstring
2024-01-23 16:01:49 -08:00
sogaiu cf4d19a8ea Cosmetically tweak module/expand-path docstring 2024-01-22 22:16:14 +09:00
Calvin Rose 23b0fe9f8e
Merge pull request #1360 from pepe/patch-1 2024-01-17 11:51:59 -08:00
Josef Pospíšil 1ba718b15e
Update CHANGELOG.md 2024-01-17 13:58:00 +01:00
Calvin Rose df5f79ff35
Merge pull request #1359 from pnelson/binary
Add buffer/push-* sized int and float
2024-01-15 08:56:57 -08:00
Calvin Rose 6d7e8528ea
Merge pull request #1346 from ianthehenry/peg-split
add a new (split) PEG special
2024-01-15 08:16:06 -08:00
Philip Nelson 197bb73a62 Add buffer/push-* sized int and float 2024-01-14 15:32:13 -08:00
Calvin Rose f91e599451
Merge pull request #1351 from pepe/1.33 2024-01-07 13:30:08 -06:00
Josef Pospíšil 5b9aa9237c Prepare for 1.33.0 release 2024-01-07 16:26:20 +01:00
Ian Henry 61f38fab37
add a new (split) PEG special
This works similarly to string/split, but the separator is a PEG.
2024-01-05 22:02:52 -08:00
Calvin Rose 9142f38cbc Fix #1341. 2024-01-01 08:58:31 -06:00
Calvin Rose e8ed961572
Merge pull request #1344 from ianthehenry/peg-sub-special
Add a new (sub) PEG special
2023-12-31 18:40:47 -06:00
Calvin Rose be11a2a1ad Fix #1342 2023-12-31 18:36:55 -06:00
Ian Henry ea75086300
add a new (sub) PEG special
(sub) will first match one pattern, then match another pattern against the
text that the first pattern advanced over.
2023-12-28 22:15:54 -08:00
Calvin Rose 9eeefbd79a
Merge pull request #1340 from sogaiu/string-format-doc-tweak 2023-12-20 09:10:26 -06:00
sogaiu c573a98363 Cosmetically tweak string/format docstring 2023-12-19 18:33:47 +09:00
Calvin Rose 11d7af3f95 Work on addressing #1337 - fix valgrind case. 2023-12-18 08:56:27 -06:00
Calvin Rose a10b4f61d8 Address #1337 (leet!).
Changes a few scheduling details and adds a 0 byte explicitly to
symbols created via gensym.
2023-12-16 16:15:46 -06:00
Calvin Rose a0cb7514f1 Update Makefile for #1329
Add separate import library for libjanet.so and janet.exe with Mingw.
This was causing issues with linking.
2023-12-09 10:11:15 -06:00
Calvin Rose b066edc116
Merge pull request #1336 from pepe/peg-arity-typo 2023-12-07 11:31:13 -06:00
Josef Pospíšil 938f5a689e Fix arity typo in peg 2023-12-07 14:08:03 +01:00
Calvin Rose 772f4c26e8
Merge pull request #1334 from iacore/fix-0
fix (doc next)
2023-12-02 17:28:32 -06:00
Locria Cyber 6b5d151beb
fix typo in (doc next) 2023-12-02 15:38:35 +00:00
Calvin Rose a9176a77e6 Prevent bytecode optimization from remove mk* instructions.
These instructions read from the stack, and therefor have side effects.
Removing them without clearing the stack results in broken bytecode.
2023-11-22 08:18:23 -06:00
Calvin Rose 16f409c6a9 Typo for SIGALARM in os/proc-kill 2023-11-21 21:51:56 -06:00
Calvin Rose 9593c930de Address #1326 in a dynamic way that is fairly conservative.
Another optimization would be to keep track of immutable closure
captures (vs. mutable closure captures) and always detach them.
2023-11-14 21:13:21 -06:00
Calvin Rose 56f33f514b Fix regression #1327 2023-11-14 19:52:22 -06:00
Calvin Rose 1ccd544b94 Address #1326 - marshal_one_env w/ JANET_MARSHAL_UNSAFE.
This allows uses the precise closure state capture
when marshalling data between threads. This prevents
accidental state capture when using ev/do-thread or similar
with closures that reference the current state.
2023-11-10 15:36:45 -06:00
Calvin Rose 93c83a2ee2 Fix warnings w/ MSVC and format. 2023-11-10 15:02:10 -06:00
Calvin Rose f459e32ada
Merge pull request #1325 from zevv/zevv-connect-cleanup
net/ev: Cleaned up unused NetStateConnect, fixed janet_async_end() ev refcount
2023-11-10 15:01:43 -06:00
Ico Doornekamp 9b640c8e9c net/ev: Cleaned up unused NetStateConnect, fixed janet_async_end() ev refcount 2023-11-10 20:34:17 +01:00
Calvin Rose a3228f4997 Add changes and test cases for #1324 2023-11-09 11:18:03 -06:00
Calvin Rose 715eb69d92 Add more ipv6 feature detection. 2023-11-03 18:24:35 -05:00
Calvin Rose df2d5cb3d3 Add ipv6, shared, and cryptorand options to meosn.
Allows for builting with cosmopolitan, both with meson
and Makefile. Use:

CC=comsocc meson setup -Dipv6=false -Ddynamic_modules=false
-Dshared=false -Dos_name=cosmopolitan

to configure for cosmopolitan build.
2023-11-02 08:56:10 -05:00
Calvin Rose 3b189eab64 Fix #1321, poll event loop CPU usage issue
A stream may have a fiber attached for memory management purposes, but
not actually be waiting on anything. Be more seletive with poll, which
is not edge-triggered, to not poll for readiness on these streams.
2023-10-29 11:34:21 -05:00
Calvin Rose 609b629c22 Add support for atomic loads in Janet's atomic abstraction. 2023-10-21 10:40:57 -05:00
Calvin Rose e74365fe38 Be a bit safer with reference counting.
We might want to revisit some uses of refcounts in the
ev module to be more efficient if we care about signal atomicity
(where memory order isn't really important) or multithreading atomicity.
2023-10-21 09:55:00 -05:00
Calvin Rose 46b34833c2
Merge pull request #1314 from williewillus/pr1314
Use libc strlen in janet_buffer_push_cstring
2023-10-20 15:41:29 -07:00
Vincent Lee 045c80869d Use libc strlen in janet_buffer_push_cstring
Platform libc's often contains optimized assembly implementations of strlen, so take
advantage of them here instead of doing a naive count.
2023-10-19 23:30:28 -07:00
Calvin Rose 2ea2e72ddd
Merge pull request #1313 from sogaiu/default-peg-grammar-additions
Add more + and * keywords to default-peg-grammar
2023-10-19 19:26:10 -07:00
sogaiu 1b17e12fd6 Add more + and * keywords to default-peg-grammar 2023-10-19 18:45:20 +09:00
Calvin Rose cc5beda0d2 Update patch release. 2023-10-15 14:33:43 -05:00
Calvin Rose a363fd926d Update CHANGELOG.md 2023-10-15 14:32:56 -05:00
Calvin Rose 21ebede529 Move posix-fork inside correct if-def
Don't compile if processes are disabled.
2023-10-15 11:03:26 -05:00
Calvin Rose 15d67e9191
Merge pull request #1310 from Andriamanitra/patch-forward-word
Change Alt-f in the REPL move to next end of word instead of beginning
2023-10-14 18:36:05 -07:00
Calvin Rose b5996f5f02 Update for 1.32.0 2023-10-14 19:48:20 -05:00
Andriamanitra 83204dc293 Change Alt-f in the REPL move to next end of word instead of beginning 2023-10-14 14:21:16 +03:00
Calvin Rose e3f4142d2a Update result value from janet_do* functions. 2023-10-12 05:26:23 -05:00
Calvin Rose f18ad36b1b Rework #1306 - better default for pretty printing numbers.
Not perfect for serialization, but a representation that
plays well with both safe integers (z where abs(z) < 2^54) and
non-integer floats.
2023-10-11 00:59:57 -05:00
Calvin Rose cb25a2ecd6 Avoid using execvpe function. 2023-10-08 21:33:15 -05:00
Calvin Rose 741a5036e8 Add %D and %I for 64 bit formatting.
Instead of breaking old code with changing %i and %d.
2023-10-08 21:23:03 -05:00
Calvin Rose 549ee95f3d Add os/posix-exec (along os/posix-fork)
Useful for old-style unix daemons, start up scripts, and so on.
Easy to add on top of os/execute.

May want to consider allowing the same IO redirection as os/execute
and os/spawn.

May also want to put both fork and exec behind a config switch since I
suppose some systems may not support them, although I don't know of any
concrete examples.
2023-10-08 21:03:08 -05:00
Calvin Rose 6ae81058aa Be more consistent with va_arg types. 2023-10-08 19:09:35 -05:00
Calvin Rose 267c603824 Don't use full parallelism to avoid oom 2023-10-08 18:37:31 -05:00
Calvin Rose a8f583a372 CMD isn't bash 2023-10-08 18:34:04 -05:00
Calvin Rose 2b5d90f73a Disable amalgamation w/ mingw in CI due to memory limitations 2023-10-08 18:28:07 -05:00
Calvin Rose 4139e426fe Refine interface for janet's new event loop.
Infer the current root fiber and force user to
allocate state for async events.
2023-10-08 18:25:46 -05:00
Calvin Rose a775a89e01 Improve assert-no-error test helper. 2023-10-08 17:34:50 -05:00
Calvin Rose 990f6352e0 Allow for unregistered streams w/ kqueue. 2023-10-08 17:21:42 -05:00
Calvin Rose b344702304 Merge branch 'master' into ev-epoll-fewer-syscalls 2023-10-08 17:20:20 -05:00
Calvin Rose d497612bce Revert 2023-10-08 17:18:36 -05:00
Calvin Rose 2a3b101bd8 ktrace trace -c 2023-10-08 16:25:55 -05:00
Calvin Rose 63e93af421 Ktrace 2023-10-08 16:00:33 -05:00
Calvin Rose ab055b3ebe i dont know how ktrace works 2 2023-10-08 15:54:57 -05:00
Calvin Rose a9a013473f i dont know how ktrace works 2023-10-08 15:53:44 -05:00
Calvin Rose 87de1e5766 Quick experiment on macos 2023-10-08 15:51:44 -05:00
Calvin Rose 894aaef267 Mac please 2023-10-08 15:42:54 -05:00
Calvin Rose e209e54ffe bsds are very strict on C standards
No labels before declarations.
2023-10-08 15:37:23 -05:00
Calvin Rose 7511eadaa7 Update code for freebsd and ENODEV on stream register 2023-10-08 15:26:02 -05:00
Calvin Rose 6c4906605a Some bsds return ENODEV for devices like /dev/null 2023-10-08 15:09:53 -05:00
Calvin Rose 8a9be9d837 Make sure posted events are read from non-blocking socket. 2023-10-08 13:46:24 -05:00
Calvin Rose b72098cc71 remove extra decref 2023-10-08 13:24:42 -05:00
Calvin Rose defe60e08b Handle refcounts in posted events. 2023-10-08 13:18:08 -05:00
Calvin Rose 7f852b8af4 Handle refcounts in posted events. 2023-10-08 13:14:36 -05:00
Calvin Rose d71c100ca7 Revert "Add EV_EOF and EV_CLEAR to selfpipe for kqueue"
This reverts commit 5442c8e86d.
2023-10-08 13:13:58 -05:00
Calvin Rose 5442c8e86d Add EV_EOF and EV_CLEAR to selfpipe for kqueue 2023-10-08 12:34:13 -05:00
Calvin Rose cf4901e713 Update docstring for os/posix-fork 2023-10-08 11:54:25 -05:00
Calvin Rose 4b8c1ac2d2 Add os/posix-fork
Very simple fork function that returns a process object that can be
waited on.
2023-10-08 11:09:00 -05:00
Calvin Rose 555e0c0b85 Try to capture more events in kqueue. 2023-10-08 10:52:27 -05:00
Calvin Rose dc301305de Turn off verbose CI builds for BSD. 2023-10-07 21:35:38 -05:00
Calvin Rose f1111c135b Work on kq 2023-10-07 21:32:20 -05:00
Calvin Rose 3905e92965 kqueue mirror master branch implementation a bit better. 2023-10-07 12:53:59 -07:00
Calvin Rose 1418ada38f Remove duplicate code in kqueue event handling. 2023-10-07 12:40:43 -07:00
Calvin Rose 9256a66b76 Update ev.c for removing msvc warnings 2023-10-07 12:11:14 -07:00
Calvin Rose e8c013a778 Remove some extra fiber state and use a flag. 2023-10-07 12:07:05 -07:00
Calvin Rose fea8242ea7 Reuse overlapped overhead on windows for something useful. 2023-10-07 11:25:20 -07:00
Calvin Rose 7bfb17c209 Lots of work to make iocp work again.
Big issue with IOCP vs. poll variants is that the overlapped
structures have a longer lifetime than intermediate state needed
for epoll. One cannot free overlapped structures after closing a
handle/socket, like one can do with any intermediate state when using
readiness-based IO.
2023-10-07 11:18:43 -07:00
Calvin Rose e7e4341e70 Add EV_EOF for kqueue. 2023-10-06 17:39:52 -05:00
Calvin Rose 6186be4443 Run tests verbosely 2023-10-06 01:40:12 -05:00
Calvin Rose d07f01d7cb Update kqueue 2023-10-06 01:33:51 -05:00
Calvin Rose 73291a30a0 Update marsh.c 2023-10-06 01:26:07 -05:00
Calvin Rose a3b129845b Quick blind take on getting kqueue similar to poll and poll. 2023-10-06 00:48:05 -05:00
Calvin Rose 0ff8f58be8 Simpler async model that is better suited to epoll 2023-10-06 00:37:19 -05:00
Calvin Rose 66292beec9 Don't mess with async connect on BSDs. 2023-10-04 23:33:40 -05:00
Calvin Rose bf2af1051f Missing && 2023-10-04 23:29:54 -05:00
Calvin Rose b6e3020d4c Attempt 2 to fix bsd compilation errors. 2023-10-04 23:27:56 -05:00
Calvin Rose 8f516a1e28 Address some bsd issues. 2023-10-04 23:24:40 -05:00
Calvin Rose 5f2e287efd Make epoll event loop use EPOLLET and not reregister file descriptors.
This results in fewer system calls and presumably more effcient code. It
also brings the epoll (and kqueue) code more in line with how the
windows IOCP code works, incidentally.
2023-10-04 22:35:04 -05:00
Calvin Rose 8c0d65cf9f
Merge pull request #1301 from ianthehenry/typos 2023-10-03 19:25:01 -07:00
Ian Henry fa609a5079
fix some typos in docstrings 2023-10-03 19:17:18 -07:00
Calvin Rose c708ff9708 Allow for qemu and other simulator based testing. 2023-10-02 23:31:55 -07:00
Calvin Rose 2ea90334a3 Remove some checking code for iocp events.
Be more permissive abouts events we get.
2023-10-02 23:25:26 -07:00
Calvin Rose eea8aa555f Revert dccb60b to address #1299
This commit was to address issues with a use after free error in the
windows event loop, but the erroneous code was later reworked.
2023-10-03 00:14:25 -05:00
Calvin Rose 51a75e1872 Update janet_interpreter_interrupt to use new atomics 2023-10-01 10:52:05 -05:00
Calvin Rose af7ed4322e Get rid of req for 64 bit atomics 2023-10-01 10:27:51 -05:00
Calvin Rose 7cdd7cf6eb Expose atomic refcounts to be easier to port.
This code was duplicate in a few places.
2023-10-01 10:09:23 -05:00
Calvin Rose 26aa622afc Update CHANGELOG.md 2023-09-30 12:26:50 -05:00
Calvin Rose 84ad161f1e Add support for weak references in arrays.
Also change weak table syntax to not require keyword arguments.
2023-09-30 10:56:43 -05:00
Calvin Rose 6efb965dab Merge branch 'weak-tables' 2023-09-29 07:38:21 -05:00
Calvin Rose 8c90a12e0f More test cases. 2023-09-29 07:37:33 -05:00
Calvin Rose 2d54e88e74 Update CHANGELOG.md 2023-09-28 20:41:19 -05:00
Calvin Rose 16ea5323e0 More meson tweaks. 2023-09-28 20:32:14 -05:00
Calvin Rose 7a23ce2367 See if we can fix sr.ht build due to change in install. 2023-09-28 20:24:19 -05:00
Calvin Rose e05bc7eb54 Address compiler bug with `break`.
Using result from `break` expression could trigger code that would
work, yet contain invalid, dead code preventing good marshalling.
2023-09-28 20:14:22 -05:00
Calvin Rose b3a6e25ce0 Add weak references in the form of weak tables.
Any references exclusively held by a weak table may be collected
without the programmer needing to free references manually. A table
can be setup to have weak keys, weak values, or both.
2023-09-27 23:36:09 -05:00
Calvin Rose b63d41102e Fix bad merge. 2023-09-27 22:34:46 -05:00
Calvin Rose 964295b59d Merge branch 'net-reworkings' 2023-09-27 19:06:14 -05:00
Calvin Rose d19db30f3d Fix meson install test. 2023-09-27 00:19:35 -05:00
Calvin Rose d12464fc0e Make poll work by going back to array of listeners for gc keeping. 2023-09-26 23:02:06 -05:00
Calvin Rose a96971c8a7 More work on epoll implementation. 2023-09-26 12:05:06 -05:00
Calvin Rose f6f769503a Fix up ev.c to pass tests. 2023-09-26 11:11:29 -05:00
Calvin Rose 82917ac6e3 Kqueue fix. 2023-09-25 19:17:51 -07:00
Calvin Rose a6ffafb1a2 Patches to kqueue implementation. 2023-09-25 19:07:18 -07:00
Calvin Rose fb8c529f2e Partial work updating epoll reimplentation. 2023-09-25 18:52:15 -07:00
Calvin Rose 1ee98e1e66 Get IOCP reworked event loop passing tests. 2023-09-25 15:19:39 -07:00
Calvin Rose 81f35f5dd1 Redo state management for Janet listeners.
Make more use of the built in GC code for abstracts to
be sure things are more correct. Issue before was streams could
be freed before IOCP events arrived.
2023-09-25 00:43:36 -07:00
Calvin Rose 1b402347cd Work on debugging issue with server spawning. 2023-09-24 18:15:58 -07:00
Calvin Rose 7599656784 Update meson build once more. 2023-09-24 15:35:40 -07:00
Calvin Rose dccb60ba35 Ignore IOCP where the event failed to deque. 2023-09-24 12:53:06 -07:00
Calvin Rose ae642ceca0 Don't hide windows segfaults in build_win.bat. 2023-09-24 12:36:15 -07:00
Calvin Rose 471b6f9966 Add TOCLOSE back. 2023-09-24 12:28:35 -07:00
Calvin Rose 5dd18bac2c More fixups to gc.c 2023-09-24 11:51:22 -07:00
Calvin Rose 018f4e0891 Remove some old code. 2023-09-24 10:30:58 -07:00
Calvin Rose e85809a98a Remove remains of gc instrumentation code. 2023-09-24 10:11:24 -07:00
Calvin Rose e6e9bd8147 Redo async connect code to be moved out of ev.c.
Async connect is different than write.
2023-09-24 10:08:40 -07:00
Calvin Rose 221645d2ce More refinement of meson build. 2023-09-23 14:16:13 -07:00
Calvin Rose 2f4a6214a2 Make meson build work on windows.
By default, use more traditional linking pattern with meson.
The janet.exe will now link to janet-x.x.dll on windows (and
similar for linux/posix) when built with meson. This is slightly
less efficient and means that janet.exe built this way is no longer
standalone (you would need to move the dll along with the exe), but
plays better with most build systems.
2023-09-23 08:53:37 -07:00
Calvin Rose e00a461c26 Add optional buffer-size to file/open.
This calls setvbuf to change FILE buffering. A goal is
to be able to use the existing file/* functions for blocking
IO analogous to `read` and `write` system calls.
2023-09-23 09:40:17 -05:00
Calvin Rose c31314be38
Merge pull request #1296 from Andriamanitra/doc-loop-unless
add :unless modifier to (doc loop)
2023-09-22 05:41:06 -07:00
Andriamanitra ee142c4be0 truthy/falsey is more accurate than true/false 2023-09-22 03:04:41 +03:00
Andriamanitra aeacc0b31b add :unless modifier to (doc loop) 2023-09-21 19:23:40 +03:00
Calvin Rose 7b4c3bdbcc Address issues from #1294 on non-nanboxed platforms.
Underlying bug was obscured by nanbox implementation.
2023-09-21 07:36:53 -07:00
Calvin Rose 910b9cf1fd Distinguish between JANET_API and JANET_EXPORT
One is a way to export symbols, the other a way to reference
API functions. Also include prebuilt dlljanet.dll and dlljanet.lib
for windows to save people the trouble of compiling janet.c themselves.
2023-09-20 20:07:03 -07:00
Calvin Rose b10aaceab0 Work on dllimport option for janet. 2023-09-20 17:34:42 -07:00
Calvin Rose 169bd812c9 Update state.h to #include <windows.h>
Should fix usage with msvc in some pipelines.
2023-09-18 23:51:15 -05:00
Calvin Rose 34767f1e13
Merge pull request #1292 from sogaiu/tweak-janetconf-h 2023-09-18 18:50:46 -07:00
sogaiu 4f642c0843 Tweak janetconf.h 2023-09-19 10:34:50 +09:00
Calvin Rose 4e5889ed59 Prepare for 1.31.0 release. 2023-09-17 14:53:03 -05:00
Calvin Rose a1b848ad76
Merge pull request #1288 from sogaiu/more-error-loc-info-in-dobytes
Report line and col more in janet_dobytes
2023-09-14 08:21:52 -07:00
Calvin Rose dbcc1fad3e
Merge pull request #1289 from primo-ppcg/loop-unless
Add `:unless` loop modifier
2023-09-13 11:56:33 -07:00
primo-ppcg db366558e7 add `:unless` loop modifier 2023-09-13 15:21:46 +07:00
sogaiu a23c03fbd0 Report line and col more in janet_dobytes 2023-09-13 15:41:14 +09:00
Calvin Rose ff18b92eb0
Merge pull request #1287 from pepe/fix-arr-push-doc
Document array/push variadic argument
2023-09-12 07:07:42 -07:00
Josef Pospíšil 7f148522ab Document array/push variadic argument 2023-09-12 09:34:21 +02:00
Calvin Rose 159c612924 Update changelog.md 2023-09-09 11:03:14 -05:00
Calvin Rose b95dfd4bdf Update docstring. 2023-09-09 10:58:20 -05:00
Calvin Rose e69954af2f
Merge pull request #1283 from primo-ppcg/mean-partition
Update `partition`, `mean`
2023-09-09 10:30:11 -05:00
primo-ppcg a5ff26f602 add more test cases for `partition` and `mean` 2023-09-08 16:30:44 +07:00
primo-ppcg a7536268e1 update `partition` 2023-09-08 12:38:58 +07:00
primo-ppcg 541469371a update `mean` 2023-09-08 11:35:37 +07:00
Calvin Rose a13aeaf955
Merge pull request #1281 from primo-ppcg/interleave-interpose
Update `interleave`, `interpose`
2023-09-04 10:27:27 -05:00
primo-ppcg 9cf674cdcb update `interleave`, `interpose` 2023-09-04 17:09:53 +07:00
Calvin Rose 51c0cf97bc
Merge pull request #1280 from primo-ppcg/lengthable
Add `lengthable?`
2023-09-01 17:41:25 -05:00
primo-ppcg 4cb1f616c5 allow `reverse` on non-lengthable 2023-09-01 16:04:21 +07:00
primo-ppcg 645109048b update `keys`, `values`, `pairs` 2023-09-01 13:18:31 +07:00
primo-ppcg f969fb69e1 add `lengthable?` 2023-09-01 13:04:53 +07:00
Calvin Rose bfb60fdb84
Merge pull request #1278 from primo-ppcg/loop-range
Allow one-term `:range` and `:down` forms
2023-08-29 08:23:36 -05:00
primo-ppcg 2f43cb843e Allow one-term `:range` and `:down` forms 2023-08-29 10:59:16 +07:00
Calvin Rose 874fd2aba7 don't crash repl if someone sets a bad *pretty-format* 2023-08-27 13:09:22 -05:00
Calvin Rose 33d1371186 Update specials.c for formatting. 2023-08-25 16:28:41 -05:00
Calvin Rose d2dd241e6b
Merge pull request #1269 from primo-ppcg/check-nil-form
Optimize nil conditions for while and if
2023-08-24 09:30:58 -05:00
Calvin Rose 4ecadfabf4 Fix atomics - warnings on windows 2023-08-24 08:00:50 -05:00
Calvin Rose ffd79c6097 Allow multiple simultaneous interrupts cleanly for #1262
Instead of setting a flag, each interrupt increments an atomic
counter. When the interrupt is finally handled, either by scheduling
code to run on the event loop or executing some out of band code, the
user must now decrement the interrupt counter with
janet_interpreter_interrupt_handled. While this counter is non-zero, the
event loop will not enter the interpreter. This changes the API a bit but
makes it possible and easy to handle signals without race conditions
or scheduler hacks, as the runtime can ensure that high priority code is
run before re-entering possibly blocking interpreter code again.

Also included is a new function janet_schedule_soon, which prepends to
the task queue instead of appending, allowing interrupt handler to skip
ahead of all other scheduled fibers.

Lastly, also update meson default options to include the
interpreter_interrupt code and raise a runtime error if os/sigaction
is used with interpreter interrupt but that build option is not enabled.
2023-08-24 07:38:53 -05:00
primo-ppcg 35a8d2a519 Optimize nil conditions for while and if 2023-08-24 17:50:31 +07:00
Calvin Rose 21eab7e9cc Update sigaction to help address #1262.
Update example to have 4 cases - case 3 was previously broken but should
now work.
2023-08-23 09:16:59 -05:00
Calvin Rose d9605c2856 Allow iterating over generators with pairs, keys, and values. 2023-08-22 19:25:05 -05:00
Calvin Rose 70a467d469
Merge pull request #1266 from primo-ppcg/min-max
Speed up `min`, `max`
2023-08-21 22:32:03 -05:00
primo-ppcg 6e8979336d speed up `min`, `max` 2023-08-22 00:39:28 +07:00
Calvin Rose ee01045db5 Update CHANGELOG.md 2023-08-20 15:56:58 -05:00
Calvin Rose b7f8224588 Address #1263
Fix reference counting when cleaning up unused abstract types
per-thread.
2023-08-20 14:53:25 -05:00
Calvin Rose ca4c1e4259 Try to use atomics inside signal handler for ref count. 2023-08-20 08:49:49 -05:00
Calvin Rose 91712add3d Fix threaded abstracts in min build. 2023-08-19 20:19:05 -05:00
Calvin Rose 7198dcb416 Add sanboxing for signal handling. 2023-08-19 17:44:04 -05:00
Calvin Rose 08e20e912d Use pthread_sigmask when adding signal handlers. 2023-08-19 17:30:55 -05:00
Calvin Rose f45571033c Add os/sigaction for signal handling.
Also improve interrupts to work better with busy loops
and signals.
2023-08-19 13:26:29 -05:00
Calvin Rose 2ac36a0572
Merge pull request #1257 from primo-ppcg/any-every
Update `any?`, `every?`
2023-08-18 07:20:44 -05:00
Calvin Rose 3df1d54847
Merge pull request #1258 from primo-ppcg/each
Update `each` keys before body
2023-08-18 07:16:19 -05:00
Calvin Rose f3969b6066
Merge pull request #1259 from primo-ppcg/buffer-from-bytes
Add `buffer/from-bytes`
2023-08-18 07:15:08 -05:00
primo-ppcg 6222f35bc8 add `buffer/from-bytes` 2023-08-18 12:35:12 +07:00
primo-ppcg 2f178963c0 update `each` keys before body 2023-08-18 10:32:24 +07:00
primo-ppcg 15760b0950 update `any?`, `every?`
Updates `any?` and `every?` to be exact functional analogues to `or` and `and`.
2023-08-18 07:39:30 +07:00
Calvin Rose 43a6a70e1e
Merge pull request #1255 from primo-ppcg/sort
Special case common `sort` usages
2023-08-16 20:34:17 -05:00
Calvin Rose cd36f1ef5f Distinguish between threaded channels and non-threaded when marshalling.
Threaded channels _can_ be marshalled, just not for communication
between threads. This is a special case since the same abstract type
is used for both threaded and non-threaded channels.
2023-08-16 14:26:52 -05:00
primo-ppcg cdd7083c86 special case common `sort` usages 2023-08-15 11:58:22 +07:00
Calvin Rose 8df7364319 Quick fix for discussion #1253
Protect against garbage collection during connect.
2023-08-13 12:00:54 -05:00
Calvin Rose 63023722d1
Merge pull request #1246 from wooosh/use-object-typedefs
Use typedefs for strings, symbols, keywords, tuples, structs, and abstracts.
2023-08-13 08:33:19 -05:00
Calvin Rose 79c12e5116
Merge pull request #1252 from primo-ppcg/reverse
Rework `reverse`, again
2023-08-12 14:29:23 -05:00
primo-ppcg 53e16944a1 rework `reverse`, again 2023-08-13 00:54:17 +07:00
Calvin Rose 7475362c85
Merge pull request #1249 from primo-ppcg/compare
Speed up `compare` functions
2023-08-11 19:27:42 -05:00
primo-ppcg 9238b82cde speed up `compare` 2023-08-11 23:48:29 +07:00
Calvin Rose 7049f658ec
Merge pull request #1244 from primo-ppcg/bytes-indexed-dictionary
Move `bytes?`, `indexed?`, `dictionary?` to corelib
2023-08-09 17:56:35 -05:00
wooosh 701913fb19 Use typedefs for strings, symbols, keywords, tuples, structs, and abstracts. 2023-08-09 16:09:34 -04:00
primo-ppcg 831f41a62b move `bytes?`, `indexed?`, `dictionary?` to corelib 2023-08-08 10:00:05 +07:00
Calvin Rose 0ea1da80e7
Merge pull request #1242 from primo-ppcg/reverse
Rework `reverse`
2023-08-06 08:10:56 -05:00
Calvin Rose 06eea74b98
Merge pull request #1241 from primo-ppcg/keys-values-pairs
Rework `keys`, `values`, `pairs`
2023-08-06 08:10:43 -05:00
primo-ppcg c8c0e112bc rework `reverse` 2023-08-06 16:16:41 +07:00
primo-ppcg 7417e82c51 rework `keys`, `values`, `pairs` 2023-08-06 15:39:16 +07:00
Calvin Rose ecc4d80a5a Prepare for 1.30.0 release. 2023-08-05 18:58:04 -05:00
Calvin Rose 3df24c52f4
Merge pull request #1236 from primo-ppcg/range
Move `range` to corelib
2023-08-05 18:05:37 -05:00
primo-ppcg 8a70fb95b5 slight refactoring 2023-08-05 11:00:23 +07:00
primo-ppcg d8b45ecd61 better test coverage 2023-08-03 20:39:32 +07:00
primo-ppcg 61712bae9c speed up range creation 2023-08-02 01:26:03 +07:00
Calvin Rose 4ff81a5a25 Add strip in release process instead of local builds - Address #1233 2023-07-27 21:40:07 -05:00
Calvin Rose 08f0e55d8f Add strip in release process instead of local builds - Address #1233 2023-07-27 21:37:48 -05:00
Calvin Rose 080b37cb31 Update CHANGELOG. 2023-07-25 17:51:21 -05:00
Calvin Rose bbdcd035ba
Merge pull request #1231 from sogaiu/tweak-file-open-doc 2023-07-23 23:20:09 -05:00
sogaiu f9233ef90b Add fopen reference to file/open docstring 2023-07-23 18:39:20 +09:00
Calvin Rose cd3573a4d2
Merge pull request #1224 from primo-ppcg/array-remove 2023-07-15 06:42:15 -05:00
Calvin Rose 738fe24e6d Allow buffer/blit to take explicit nils for default args.
Also small changes for range checking code.
2023-07-14 20:04:10 -05:00
primo-ppcg c2e55b5486 update docstrings for `string/slice` and `tuple/slice` 2023-07-15 00:52:12 +07:00
Calvin Rose 989f0726e3 Make encoding of immediate values capture full range. 2023-07-14 10:06:20 -05:00
primo-ppcg bdefd3ba1e update final array index to be -1 2023-07-14 17:34:55 +07:00
Calvin Rose 4efcff33bd Update inttypes. 2023-07-13 19:58:38 -05:00
Calvin Rose 8183cc5a8d Disallow converting negative numbers to int/u64
The wrap-around rule doesn't make sense once subtraction is
properly fixed.
2023-07-09 22:25:20 -05:00
Calvin Rose f3bda1536d Remove some dead code in cfuns.c 2023-07-09 22:02:10 -05:00
Calvin Rose 3b6371e03d Add test case for issue #1217 2023-07-09 21:56:41 -05:00
Calvin Rose b5d3c87253 Add new opcode subtract immediate. 2023-07-09 21:51:16 -05:00
Calvin Rose f73b8c550a
Merge pull request #1213 from sogaiu/src-view-for-ppasm
Add source view to .ppasm output
2023-07-09 10:54:55 -05:00
Calvin Rose 5437744126
Merge pull request #1216 from sogaiu/tweak-test-grammar-peg
Update and ascii-sort string escapes in peg
2023-07-08 09:26:03 -05:00
sogaiu 5a5e70b001 Update and ascii-sort string escapes in peg 2023-07-08 17:54:00 +09:00
sogaiu 348a5bc0a9 Add source view to .ppasm output 2023-07-06 13:26:03 +09:00
Calvin Rose 026c64fa01 Formatting. 2023-07-02 15:23:22 -05:00
Calvin Rose e38663c457 Update CHANGELOG.md 2023-07-02 13:44:39 -05:00
Calvin Rose 117c741c29 Add test for marshalling channels. 2023-07-02 13:13:59 -05:00
Calvin Rose 9bc5bec9f1 More complete fix with some debugging tools. 2023-07-02 13:04:42 -05:00
Calvin Rose a5f4e4d328 Test small fix for marshalling. 2023-07-02 12:58:55 -05:00
Calvin Rose db0abfde72 Cache references when marshalling abstract types. 2023-07-01 18:02:56 -05:00
Calvin Rose edf263bcb5 Make some fixes to marshalling. 2023-07-01 17:59:07 -05:00
Calvin Rose 60fba585e3 Remove extra MARK_SEEN 2023-07-01 17:37:12 -05:00
Calvin Rose ebb6fe5be3 Patch fix for #1210 2023-07-01 10:34:11 -05:00
Calvin Rose d91c95bf92
Merge pull request #1210 from primo-ppcg/int-bnot
Add bnot for int types
2023-07-01 10:19:04 -05:00
primo-ppcg 2007438424 add tests for inttypes bnot 2023-07-01 21:49:49 +07:00
primo-ppcg 81423635ad Add bnot to int types 2023-07-01 21:41:55 +07:00
Calvin Rose 58d297364a Change code for marshalling abstract types. 2023-07-01 08:50:56 -05:00
Calvin Rose db902c90c4
Merge pull request #1207 from primo-ppcg/divmod
floor div, variadic mod
2023-07-01 08:47:06 -05:00
Calvin Rose 42ccd0f790
Merge pull request #1209 from pyrmont/bugfix.strip-macos
Avoid removing too many symbols with strip on macOS
2023-07-01 08:46:35 -05:00
Michael Camilleri 20ec6f574e
Avoid removing too many symbols with strip on macOS 2023-07-01 19:33:38 +09:00
primo-ppcg b3db367ae7 Add test cases for div and mod 2023-06-30 19:48:45 +07:00
primo-ppcg 8a62c742e6 define `(mod x 0)` as `x`
See: Knuth, Donald E., _The Art of Computer Programming: Volume 1: Fundamental Algorithms_, pp. 15 ([link](https://books.google.com/books?id=x9AsAwAAQBAJ&pg=PA15))
2023-06-30 16:15:04 +07:00
Calvin Rose b125cbeac9
Merge pull request #1203 from czkz/add-escapes
Add C escape sequences
2023-06-28 20:06:10 -05:00
Calvin Rose 3f7a2c2197 Try harder to avoid string copying with janet_getcbytes. 2023-06-28 08:30:09 -05:00
Calvin Rose f6248369fe Update janet_getcbytes to padd buffers with trailing 0. 2023-06-28 08:18:43 -05:00
primo-ppcg c83f3ec097 floor div, variadic mod 2023-06-28 18:31:20 +07:00
Calvin Rose 0cd00da354 Add `ffi/pointer-cfunction` to FFI.
This allows for more flexible C interop from DLLs. Users can skip the
usual extension loading mechanism and manage function pointers manually
if they need to.
2023-06-27 19:47:19 -05:00
bakpakin 4b7b285aa9 Remove MSVC compiler warning. 2023-06-25 17:29:09 -05:00
Dmitry d63379e777 Add parser escape sequences 2023-06-25 19:29:39 +04:00
Calvin Rose b219b146fa Squashed commit of the following:
commit fbb0711ae1
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 12:07:55 2023 -0500

    Distinguish between subprocess when testing.

commit 676b233566
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:59:17 2023 -0500

    Hack for qemu based testing (also should work with valgrind)

commit d7431c7cdb
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:54:04 2023 -0500

    Revert "Test removing 32bit ptr marshalling."

    This reverts commit 566b45ea44.

commit 566b45ea44
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:52:22 2023 -0500

    Test removing 32bit ptr marshalling.

commit ff2f71d2bc
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:42:10 2023 -0500

    Conditionally compile marshal_ptr code.

commit bd420aeb0e
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:38:34 2023 -0500

    Add range checking to bit-shift code to prevent undefined behavior.

commit b738319f8d
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 11:17:30 2023 -0500

    Remove range check on 32 bit arch since it will always pass.

commit 7248626235
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 10:56:45 2023 -0500

    Quiet some build warnings.

commit 141c1de946
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 10:50:13 2023 -0500

    Add marshal utilities for pointers.

commit c2d77d6720
Merge: 677b8a6f ff90b81e
Author: Calvin Rose <calsrose@gmail.com>
Date:   Sat Jun 24 10:40:35 2023 -0500

    Merge branch 'master' into armtest

commit 677b8a6f32
Author: Ico Doornekamp <ico@zevv.nl>
Date:   Mon Jun 12 21:01:26 2023 +0200

    Added ARM32 test
2023-06-24 12:13:51 -05:00
Calvin Rose ff90b81ec3 Add some utilitites for dealing with unsigned integers in janet.h 2023-06-24 10:38:35 -05:00
Calvin Rose 9120eaef79
Merge pull request #1201 from pyrmont/bugfix.dup-fds
Avoid prematurely closing file descriptors when redirecting IO
2023-06-24 09:51:34 -05:00
Michael Camilleri 1ccd879916
Make test cross-platform 2023-06-24 10:56:47 +09:00
Michael Camilleri f977ace7f8
Avoid prematurely closing file descriptors when redirecting IO 2023-06-23 15:50:19 +09:00
Calvin Rose c3f4dc0c15
Merge pull request #1200 from sogaiu/use-vm_commit
Use vm_commit
2023-06-22 20:40:03 -05:00
sogaiu 78eed9b11c Use vm_commit 2023-06-22 21:36:57 +09:00
Calvin Rose 3a4d56afca Patch release. 2023-06-19 07:18:35 -05:00
Calvin Rose 63bb93fc07 Fix isatty code to not use functions only defined if ev is enabled. 2023-06-19 07:14:56 -05:00
Calvin Rose 5a39a04a79 Prepare for 1.29.0 release. 2023-06-19 06:48:33 -05:00
Calvin Rose 2fde34b519 Remove extra function call that cannot ever trigger. 2023-06-18 09:41:53 -05:00
Calvin Rose 1ef5c038db
Merge pull request #1187 from CosmicToast/peg-boolean
peg: add support for "true" and "false" primitives to always/never match
2023-06-18 09:40:46 -05:00
Calvin Rose e2459cfb47
Merge pull request #1185 from chris-chambers/macro-lints-fix
Fix order in which *macro-lints* is set during expansion
2023-06-18 09:39:25 -05:00
Calvin Rose cfffc0bcf1
Merge pull request #1190 from primo-ppcg/if-let
update if-let
2023-06-18 09:38:44 -05:00
Calvin Rose 7272f43191
Merge pull request #1188 from primo-ppcg/if-let 2023-06-11 07:21:38 -05:00
primo-ppcg 2a7ea27bb7 do not expand false branch more than once
Fixes #1191
2023-06-11 19:15:48 +07:00
primo-ppcg 32c5b816ae use unquotes instead 2023-06-11 18:38:20 +07:00
Chloe Kudryavtsev e54ea7a1d8 fixup! peg: add support for "true" and "false" primitives to always/never match 2023-06-11 12:38:40 +02:00
primo-ppcg 1077efd03a update if-let
Fixes #1189
2023-06-11 17:19:29 +07:00
Chloe Kudryavtsev f9ab91511d peg: add support for "true" and "false" primitives to always/never match
The use cases involve user-expandable grammars.
For example, consider the IRC nickname specification.
> They SHOULD NOT contain any dot character ('.', 0x2E).
> Servers MAY have additional implementation-specific nickname restrictions.

To implement this, we can do something along these lines:
```janet
(def nickname @{:main '(some :allowed)
                :allowed (! (+ :forbidden/dot :forbidden/user))
	        # for lax mode, (put nickname :forbidden/dot false)
	        :forbidden/dot "."
		# to add your own requirements
		# (put nickname :forbidden/user 'something)
		:forbidden/user false})
```

Additionally, it's common in parsing theory to allow matches of the
empty string (epsilon). `true` essentially allows for this.

Note that this does not strictly add new functionality, you could
emulate this previously using `0` and `(! 0)` respectively, but this
should be faster and more intuitive.
The speed improvement primarily comes from `(! 0)` which is now a single
step.
2023-06-11 10:44:39 +02:00
primo-ppcg 2c3ca2984e simplify if-let logic 2023-06-11 12:09:58 +07:00
primo-ppcg 94722e566c if-let better test coverage 2023-06-11 12:07:13 +07:00
Christopher Chambers 163f7ee85d Add test for maclintf in nested macro invocations 2023-06-10 16:52:20 -04:00
Christopher Chambers 52d3470cbe Fix order in which *macro-lints* is set during expansion
Previously, `*macro-lints*` was set after the `macroexpand1` fiber was
resumed, rather than just before.  And, `*macro-lints*` was never
cleared.  This behavior was typically fine since the main users of
`compile` pass the same lint array repeatedly, and the first macro
expansion (somewhere in boot.janet) never produces a lint.  But, when
compiling with a fresh lint array, if the first macro invocation
produced a lint, the lint was always lost.
2023-06-09 12:53:10 -04:00
Calvin Rose 0bd6e85c61 update changelog 2023-06-08 19:54:01 -05:00
Calvin Rose e35c6b876f
Merge pull request #1183 from primo-ppcg/take-drop
Make take and drop more symmetric
2023-06-08 14:52:51 -05:00
Calvin Rose 9a2897e741 Run through astyle with manual corrections 2023-06-08 13:01:49 -05:00
primo-ppcg 70b2e8179d nitpick performance tweak 2023-06-08 23:57:07 +07:00
primo-ppcg 5317edc65d minor readability change
As suggested by @sogaiu

@zevv forget to push this change in a recent PR (https://github.com/janet-lang/janet/pull/1175#issuecomment-1576128152).

Incidentally, the affected lines were already reformatted in the current PR, via fmt/format-file.
2023-06-08 23:00:05 +07:00
Calvin Rose 866d83579e Address #1165 - Allow for partial ffi support without totally removing testing.
Query at runtime which calling conventions are supported, including
a placeholder :none.
2023-06-08 09:07:16 -05:00
primo-ppcg a238391b36 take-drop performance tweaks
Increase efficiency for `take` and `drop` with slices.
Check indexed types before bytes types.
2023-06-08 14:50:37 +07:00
Calvin Rose 5e152d30db
Merge pull request #1182 from chris-chambers/channel-close-resumptions 2023-06-07 17:15:45 -05:00
Christopher Chambers 57c954783d Fix resumption values when closing a channel.
When suspended in `ev/give` or `ev/take`, closing the channel should
cause the result of `ev/give` or `ev/take` to be `nil`.

When suspended in `ev/select`, closing the channel should cause the
result of `ev/select` to be `[:close ch]`.

The results were flipped before.
2023-06-07 15:01:56 -04:00
primo-ppcg b5407ac708 take-drop dictionaries
Return table for `take` of dictionary types.
Allow `drop` of dictionary types.
2023-06-07 19:20:05 +07:00
primo-ppcg 472ec730b5 take-drop symmetry
Allow `take` from the end of bytes or indexed (as `drop` does).
Allow `drop` from fibers (as `take` does).
2023-06-07 18:12:36 +07:00
Calvin Rose 8c819b1f91 Update README.md 2023-06-05 12:55:08 -05:00
Calvin Rose 528a516390 Add more sandbox capabilities.
Add more granularity to ffi sandbox capabilities - distinguish between
using FFI functions, creating FFI functions, and creating executable
memory.
2023-06-04 18:48:34 -05:00
Calvin Rose 6509e37c84 Update CHANGELOG.md and README.md 2023-06-04 16:11:17 -05:00
Calvin Rose 649173f661
Merge pull request #1175 from zevv/quicky
Added JANET_NO_AMALG flag to Makefile
2023-06-04 14:24:35 -05:00
Calvin Rose 1efb0adb35 Add 3 argument form to fiber/new
Allow passing in environment table at fiber creation since
it is a fairly common thing to do.
2023-06-04 14:17:18 -05:00
Calvin Rose 88a8e2c1df Define *task-id* since it is part of the event-loop runtime. 2023-06-04 14:05:37 -05:00
Ico Doornekamp bb4ff05d35 Added NO_AMALG flag to Makefile to build janet from the individual
source files instead of from the amalgamated janet.c; this considerably
speeds up parallel builds on modern CPUs
2023-06-04 20:02:47 +02:00
Calvin Rose dd3b601c87 Don't do fiber double arity check. 2023-06-04 12:56:03 -05:00
Calvin Rose e22d101a62
Merge pull request #1179 from zevv/zevv-tests
Added misc tests to increase test coverage
2023-06-04 12:53:43 -05:00
Calvin Rose 4b3c813f5a Revert to old behavior of janet_fiber returning NULL.
When there is a bad arity function passed in to the fiber
constructor, return NULL so the runtime can choose what to do.
This is not the prettiest API but does work, and gives better error
messages for instance in the compiler.
2023-06-04 11:21:52 -05:00
Calvin Rose 67f375bea2 Small code style change to boot.janet 2023-06-04 11:10:39 -05:00
Calvin Rose 88ba99b87e
Merge pull request #1181 from chris-chambers/ev-gather-cancel
Ensure ev/gather fibers are fully canceled on error
2023-06-04 11:10:24 -05:00
Christopher Chambers 53447e9d0b Ensure ev/gather fibers are fully canceled on error. 2023-06-04 10:49:30 -04:00
Calvin Rose c4c86f8671 Run boot.janet through janet-format. 2023-06-03 16:47:59 -05:00
Calvin Rose 658941d26d Fix macro declaration. 2023-06-03 14:24:41 -05:00
Calvin Rose e4bf27b01c Macro hack for meson-min build. 2023-06-03 14:22:16 -05:00
Calvin Rose 7d48b75f81 Update README.md 2023-06-03 14:19:02 -05:00
Calvin Rose 5f56bf836c Update meson.build file. 2023-06-03 13:55:49 -05:00
Ico Doornekamp c0f5f97ddb Added misc tests to increase test coverage 2023-06-03 19:06:51 +02:00
Calvin Rose 15177ac2e9
Merge pull request #1162 from sogaiu/reorg-tests-new
Reorganize tests
2023-06-03 08:01:34 -05:00
Calvin Rose 8360bc93ac
Merge pull request #1177 from zevv/zevv-isatty
added os/isatty, do not enable colors if stdout is not a tty
2023-06-03 07:58:16 -05:00
Ico Doornekamp e0ea844d50 added os/isatty, do not enable colors if stdout is not a tty 2023-06-02 16:59:54 +02:00
sogaiu 9675411f35 Reorganize tests 2023-06-02 07:04:07 +09:00
Calvin Rose e97299fc65 Fix #1174 - bad debug info causing stack traversal to segfault.
Coming from commit 77189b6e66, relating
to changes in source mapping debug info, this caused a segfault when
traversing a stack frame where the birth_pc was incredibly large due
to wrap around. This fix prevents the wrap around and does saturating
subtraction to 0.
2023-06-01 13:01:59 -05:00
Calvin Rose 26a113927e Add handling for new bytecode optimizations. 2023-06-01 12:47:59 -05:00
Calvin Rose d0aa7ef590 Add a few asserts to quiet some of the -fanalyze calls in gcc 13. 2023-06-01 10:52:34 -05:00
Calvin Rose 5de889419f Rename contains? and contains-key? to has-value? and has-key?
Shorten docstrings to be less like a tutorial. They get put into RAM
and memory ain't free.
2023-05-31 22:35:57 -05:00
Calvin Rose 0fcbda2da7
Merge pull request #1017 from Techcable/feature/helper-func-contains
Add `contains?` helper function to boot.janet
2023-05-31 22:28:41 -05:00
Calvin Rose 14e33c295f Make clock tests less fragile for CI. 2023-05-31 22:21:12 -05:00
Calvin Rose 644ac8caf8 Add compiler optimizations for #1163 - eachp
Should result in much better bytecode in the simple case.
2023-05-31 12:26:27 -05:00
Calvin Rose 77189b6e66 Fix some symbol mapping inside nested functions. 2023-05-31 08:19:24 -05:00
Calvin Rose 4f8f7f66ee Merge branch 'bytecode_opt' 2023-05-31 07:57:13 -05:00
Calvin Rose b099bd97f2 Merge branch 'master' into bytecode_opt 2023-05-30 18:13:02 -05:00
Calvin Rose 961c6ea15a
Merge pull request #1172 from zevv/windows-recvfrom
fix for crash on windows in src/core/ev.c: initialze state->fromlen
2023-05-30 16:54:24 -05:00
Calvin Rose 9c97d8f648
Merge pull request #1171 from zevv/zevv-net-connect
Fixed net/connect binding address
2023-05-30 16:53:24 -05:00
Ico Doornekamp ad7bf80611 fix for crash on windows in src/core/ev.c: initialze state->fromlen
before doing WSARecvFrom() to prevent crash (likely caused by the
memcpy() of `state->from` at line
2301 with the memcpy length set to -1)
2023-05-30 19:33:34 +02:00
Ico Doornekamp 40080b23ae Fixed net/connect binding address 2023-05-30 16:57:17 +02:00
Calvin Rose 7acb5c63e0 Remove bad windows10 check. 2023-05-29 18:17:22 -05:00
Calvin Rose fcca9bbab3 Add recursion to the pruning optimization. 2023-05-29 18:05:14 -05:00
Calvin Rose dbb2187425
Merge pull request #1167 from zevv/janet-formatbf-fix
Fix janet_formatbv() type when handling %d %u int specifiers
2023-05-29 18:03:13 -05:00
Calvin Rose 82e51f9e81
Merge pull request #1169 from zevv/fix-buffer-push-at-doc
Updated documentation for buffer/push-at
2023-05-29 18:02:05 -05:00
Calvin Rose 4782a76bca Add inital bytecode optimizations for #1163
This removes unnecessary movn, movf, lds, and a few other instructions.
Any instructions that has not side effects and writes to a slot that
isn't used can be removed. A number of other optimizations can follow
from this:

- Implement the def-aliasing-var optimization better
- This function can be iterated as a fix point until no more
  instructions are removed.
- If we implement slot renaming, then we no longer need to free slots
  and can simplify the initial code generation a lot.
2023-05-29 16:10:48 -05:00
Ico Doornekamp d13788a4ed Updated documentation for buffer/push-at 2023-05-29 22:03:37 +02:00
Ico Doornekamp e64a0175b1 change janet_formatbv() to handle int/unsigned int instead of long/unsigned long on '%d' and '%u' format specifiers. 2023-05-29 19:50:14 +02:00
Calvin Rose 4aca94154f Be more selective when testing FFI.
In the future, we really should get more FFI testing for
partially supported FFI on various platforms.
2023-05-28 15:28:17 -05:00
Calvin Rose ac5f118dac
Merge pull request #1164 from dressupgeekout/janet_h_symlink
More portable method of installing janet.h -> janet/janet.h symlink
2023-05-28 15:22:12 -05:00
Charlotte Koch a2812ec5eb More portable method of installing janet.h -> janet/janet.h symlink 2023-05-27 14:22:11 -07:00
Calvin Rose 70f13f1b62
Merge pull request #1157 from zevv/file-lines
Add file/lines iterator
2023-05-26 18:16:14 -05:00
Calvin Rose 77e62a25cb
Merge pull request #1160 from primo-ppcg/mapcat-et-al
Allow mapcat et al to accept multiple iterable arguments
2023-05-26 18:15:09 -05:00
Ico Doornekamp 09345ec786 file/linex now only acceps a file, not a path name 2023-05-26 17:50:26 +02:00
primo-ppcg bad73baf98 Add test cases for variadic arguments to map-like functions 2023-05-26 19:08:00 +07:00
primo-ppcg 3602f5aa5d Update boot.janet
`kvs` is not yet defined at this point.
2023-05-25 18:27:31 +07:00
primo-ppcg 672b705faf Allow mapcat et al to accept multiple iterable arguments
#1159
2023-05-25 18:12:38 +07:00
Ico Doornekamp 64e3cdeb2b Add file/lines iterator 2023-05-24 16:54:04 +02:00
Calvin Rose 909c906080 Fix yields inside nested fibers. 2023-05-23 20:09:46 -05:00
Calvin Rose 71bde11e95 Allow one argument to while. 2023-05-23 20:09:46 -05:00
Calvin Rose fc20fbed92
Merge pull request #1151 from zevv/document-string-format
Add docstring to string/format
2023-05-23 18:57:55 -05:00
Calvin Rose e6b7c85c37
Merge pull request #1152 from zevv/error-messages
Improved various error messages when handling unexpected types.
2023-05-23 18:57:20 -05:00
Ico Doornekamp b3a92363f8 Add docstring to string/format 2023-05-23 07:21:26 +02:00
Ico Doornekamp e9f2d1aca7 changed some error messages 'x|y' -> 'x or y' 2023-05-23 06:58:52 +02:00
Ico Doornekamp b4e3dbf331 Improved various error messages when handling unexpected types.
error: bad slot #1, expected string|symbol|keyword|buffer, got ...
error: bad slot #1, expected a string, symbol, keyword or buffer, got ...

bad s64 initializer: "donkey"
can not convert string "donkey" to s64
2023-05-23 06:57:12 +02:00
Calvin Rose c3620786cf Merge branch 'master' of github.com:janet-lang/janet 2023-05-22 20:41:05 -05:00
Calvin Rose 41943746e4 Fix #1149 - deep-not= should only return true/false.
Also improve perf at same time.
2023-05-22 20:40:30 -05:00
Calvin Rose 176e816b8c
Merge pull request #1153 from zevv/fix-warning
Fix warning in janet_gettime()
2023-05-22 18:46:55 -05:00
Ico Doornekamp 50a19bd870 Fix warning in janet_gettime() 2023-05-22 20:53:03 +02:00
Calvin Rose 57b751b994 Merge branch 'master' of github.com:janet-lang/janet 2023-05-21 16:23:44 -05:00
Calvin Rose 77732a8f44 inet_test change. 2023-05-21 13:36:11 -05:00
Calvin Rose c47c2e538d
Merge pull request #1137 from tionis/master
os/proc-kill now accepts an optional signal to send
2023-05-21 13:33:24 -05:00
Calvin Rose cc5545277d
Merge pull request #1147 from zevv/error-messages
improved error messages for special forms
2023-05-21 13:31:06 -05:00
Ico Doornekamp 63353b98cd improved error messages for special forms 2023-05-21 20:18:32 +02:00
tionis 4dfc869b8a fixed formatting in src/core/os.c 2023-05-21 15:55:11 +02:00
tionis b4b1c7d80b
Merge branch 'janet-lang:master' into master 2023-05-21 13:51:24 +00:00
tionis e53c03028f ignoring signals on windows in os/proc-kill again 2023-05-21 15:50:15 +02:00
Calvin Rose 8680aef42f
Merge pull request #1146 from zevv/os-clock
Add  clock sources to os/clock (:realtime, :monotonic, :cputime)
2023-05-21 08:35:24 -05:00
Calvin Rose c3fd71d643
Merge pull request #1142 from tionis/thaw
added thaw to complement freeze
2023-05-21 08:09:47 -05:00
Ico Doornekamp 30c47d685d Fixed :cputime because msdn does not implement clock() properly 2023-05-21 07:29:27 +02:00
Ico Doornekamp 80db682109 Added tests for os/clock 2023-05-21 07:29:27 +02:00
Ico Doornekamp e8e5f66f4c Implement janet_gettime() for win32 and macos; need testing 2023-05-21 07:29:27 +02:00
Ico Doornekamp aaf3d08bcd Added 'source' argument to os/clock to select the clock source 2023-05-21 07:29:27 +02:00
Ico Doornekamp 61132d6c40 os/time and janet_gettime now use CLOCK_MONOTONIC instead of CLOCK_REALTIM, this matches the description from the documentation of os/clock. Fixes issue #1144 2023-05-21 07:29:27 +02:00
tionis 9cc0645a1e added test for thaw and freeze 2023-05-20 17:35:25 +02:00
Calvin Rose fc8c6a429e Modulo should not be variadic. 2023-05-20 07:45:18 -05:00
Calvin Rose 2f966883d9 Fix #1145 - variadic imperative arith. macros.
Also update CHANGELOG
2023-05-20 07:42:50 -05:00
tionis 320ba80ca1 added support for tables/structs with prototypes in thaw 2023-05-20 14:00:33 +02:00
Calvin Rose b621d4dd2e
Merge pull request #1139 from zevv/async-connect
changed net/connect to be non-blocking / asynchronous
2023-05-19 21:12:16 -05:00
tionis 56d927c72d added thaw to complement freeze 2023-05-19 21:18:54 +02:00
tionis 53afc2e50a
Merge branch 'janet-lang:master' into master 2023-05-19 19:14:12 +00:00
Ico Doornekamp 89debac8f6 Fixed janet_loop1_impl stream use after dealloc 2023-05-19 20:00:59 +02:00
Calvin Rose f2197fa2d8
Merge pull request #1141 from zevv/mingw-test
Add CI test for mingw/wine on linux
2023-05-19 07:25:47 -05:00
Ico Doornekamp a6a097c111 Add CI test for mingw/wine on linux 2023-05-18 15:15:41 +02:00
Ico Doornekamp c3e28bc924 added deferred closing of streams after async connect() fails 2023-05-18 14:10:22 +02:00
Ico Doornekamp 8d78fb1f6b changed net/connect to be non-blocking / asynchronous 2023-05-18 10:55:48 +02:00
Calvin Rose 148917d4ca Move -g to CFLAGS to make it easier to remove/customize 2023-05-16 21:10:18 -05:00
Calvin Rose d8cf9bf942
Merge pull request #1140 from zevv/debug-symbols
Enable debug symbols in janet binary; strip target at 'make install'
2023-05-16 21:08:12 -05:00
Calvin Rose d6f5a060ed Squashed commit of the following:
commit 725b8749464895e21c761f1c5479692335282f62
Author: Calvin Rose <calsrose@gmail.com>
Date:   Tue May 16 20:58:34 2023 -0500

    Update header file.

commit 38bf2a5131
Author: Calvin Rose <calsrose@gmail.com>
Date:   Tue May 16 19:43:22 2023 -0500

    Run experiment on bsd.
2023-05-16 21:00:31 -05:00
Calvin Rose 692b6ef8ac
Merge pull request #1138 from zevv/setsockopt
add net/setsockopt
2023-05-16 19:29:25 -05:00
Ico Doornekamp ac5f1fe1be enable debug symbols in janet binary; strip target at 'make instal' 2023-05-16 19:48:18 +02:00
tionis 0f35acade1 use SIGTERM for os/proc-kill signal test 2023-05-16 18:47:38 +02:00
tionis 56d72ec4c5 support sending signals to processes on windows 2023-05-16 17:07:51 +02:00
tionis 71d51c160d added simple test for signal handling in os/proc-kill using :kill 2023-05-16 13:27:52 +02:00
tionis 0b58e505ee os/proc-kill now accepts an optional signal to send 2023-05-16 00:44:19 +02:00
Ico Doornekamp 2a6c615bec features.h: define _DARWIN_C_SOURCE for __APPLE__ 2023-05-15 16:55:09 +02:00
Ico Doornekamp ab8c5a0b5f net/setsockopt optname symbols are now lower case 2023-05-15 15:25:09 +02:00
Ico Doornekamp 68c35feaea Formatting 2023-05-15 12:33:37 +02:00
Ico Doornekamp 88d0c2ca0f add net/setsockopt 2023-05-15 12:15:36 +02:00
Calvin Rose 398833ebe3 Enable FFI module unconditionally. 2023-05-14 09:18:54 -05:00
Calvin Rose 358f5a03bf Version bump to 1.28.0 2023-05-13 09:59:55 -05:00
Calvin Rose fba1fdabe4 Update short-fn to fix #1123
Symbols are renamed on expansion to avoid the issue.
2023-05-13 09:44:30 -05:00
Calvin Rose d42afd21e5 Merge branch 'master' of github.com:janet-lang/janet 2023-05-12 19:08:35 -05:00
Calvin Rose 20ada86761 Fix NAN typo. 2023-05-12 19:08:26 -05:00
Calvin Rose 3b353f1855
Merge pull request #1133 from zevv/cross
Updated Makefile for better cross-compilation support.
2023-05-12 08:41:54 -05:00
Calvin Rose 1467ab4f93 Copy paste error. 2023-05-11 20:56:12 -05:00
Calvin Rose 7e65c2bdad Fix #1130 - mod flipped for signed integers. 2023-05-11 18:15:37 -05:00
Calvin Rose 84a4e3e98a Update CHANGELOG.
and format.
2023-05-11 18:03:38 -05:00
Calvin Rose bcbeedb001
Merge pull request #1128 from zevv/master
Added os.strftime()
2023-05-11 18:01:39 -05:00
Calvin Rose e04b103b5d
Merge pull request #1134 from CosmicToast/const_sourceline
Make JANET_FN_S* sourceline const
2023-05-11 17:59:27 -05:00
Chloe Kudryavtsev ac75b94679 Make JANET_FN_S* sourceline const
Otherwise attempts to use it on some platforms cause the following error
`error: initializer element is not a compile-time constant`
when attempting to use the corresponding `JANET_REG`.
2023-05-11 16:07:34 -04:00
Ico Doornekamp d3bb06cfd6 Updated Makefile for better cross-compilation support.
Building janet requires janet_boot to be run on the host at build time;

- $(UNAME) can now be overridden from the make cmdline
- Added $(RUN) variable to allow a emulator to be specified
- Added ".exe" extension to binaries when using MINGW

Examples:

Cross compiling for win32 and running under wine:

```
make test \
       CC=i686-w64-mingw32-gcc \
       LD=i686-w64-mingw32-gcc \
       UNAME=MINGW \
       RUN=wine

Janet 1.27.0-ad7c3bed mingw/x86/gcc - '(doc)' for help
```

Cross compiling for aarch64 and running under qemu:

```
make repl \
        CC=aarch64-none-linux-gnu-gcc \
        LD=aarch64-none-linux-gnu-gcc \
        RUN="qemu-aarch64 -L /tmp/aarch64/"

Janet 1.27.0-ad7c3bed linux/aarch64/gcc - '(doc)' for help
```
2023-05-11 07:46:36 +02:00
Ico Doornekamp 5cd729c4c1 Added os.strftime() 2023-05-11 06:08:19 +02:00
Calvin Rose c9fd2bdf39 Merge branch 'master' of github.com:janet-lang/janet 2023-05-10 18:46:42 -05:00
Calvin Rose e4be5992b3 Address issue with #1131 2023-05-10 18:43:33 -05:00
Calvin Rose 2ac4988f1b
Merge pull request #1124 from sogaiu/tweak-ev-select-docstring
Tweak ev/select docstring
2023-05-08 04:17:25 -05:00
Calvin Rose 19f14adb9e Update changelog. 2023-05-07 21:07:22 -05:00
Calvin Rose 86de039492 Merge branch 'master' of github.com:janet-lang/janet 2023-05-07 11:54:20 -05:00
Calvin Rose 2360164e4f Address #1125 - fix ev/select to only take and release locks once.
By take and releasing locks twice per channel in the case where nothing
is reading, there was an opportunity for ev/select to hang in the
multithreaded case. Also silence valgrind/helgrind errors.
2023-05-07 11:54:06 -05:00
Calvin Rose c93ddceadb
Merge pull request #1122 from CosmicToast/getcbytes
Add get/opt cbytes
2023-05-07 10:33:09 -05:00
sogaiu cd19dec44a Tweak ev/select docstring 2023-05-07 22:22:33 +09:00
Chloe Kudryavtsev 53ba9c800a Add get/opt cbytes
Like getcstring, but operates on a byteview.
When writing bindings (i.e what capi.c is primarily used for), it's
common to want to accept a buffer *or* a string rather than just
a string.
For this, a byteview is perfect (and why not accept keywords while
you're at it?).
However, there's no built-in function for getting a cstring out of
a byteview, this adds one.
This also reformulates getcstring to be an edge-case of getcbytes
(simply adding an explicit check for stringness).
2023-05-06 22:13:53 -04:00
Calvin Rose cabbaded68 Add support for the NO_COLOR environment variable. 2023-05-06 16:33:45 -05:00
Calvin Rose 9bb589f827 update readme 2023-05-06 15:56:27 -05:00
Calvin Rose c3a06686c2 Merge branch 'shell-win-feature-check' 2023-05-06 15:53:02 -05:00
Calvin Rose 7d57f87007 Address #1121 - disallow extra splices.
This turns splices that are ignored into compiler errors. Other
alternatives here should also be considered, for example making this
a compiler warning rather than an error. For example, the latest
spork as of a3ee63c137ee3234987dbbca71b566994ff8ae8c has an error of this
kind, but the resulting program does work correctly.

Also disallow splice propagation - code of the
form (+ 1 (do ;[2 3 4]) 5).
2023-05-06 13:12:31 -05:00
Calvin Rose 4cc4a9d38b (and ... <truthy-value> true) will return `true` as per docs. 2023-05-06 10:16:05 -05:00
Calvin Rose 02c7cd0194
Merge pull request #1116 from sogaiu/tweak-long-string-peg
Tweak long-string|bytes peg in test suite files
2023-04-30 16:21:12 -05:00
Calvin Rose 696efcb9e2 Add header file. 2023-04-30 12:19:55 -05:00
Calvin Rose 6e9cde8ac1 Add feature check for windows version shell.c
Tried to get console working on windows 7 and below
2023-04-30 10:36:42 -05:00
sogaiu a9fae49671 Tweak long-string|bytes peg in test suite files 2023-04-30 21:55:43 +09:00
Calvin Rose 440af9fd64 Remove extra allocation in drop. 2023-04-24 09:41:33 -05:00
Calvin Rose 347721ae40 Fix macos behavior - Closes #1097, Fixes #1015 2023-04-24 09:37:49 -05:00
Calvin Rose daea91044c Give different names to the user9 and user8 fiber statuses.
These now have semantic menaings that are pretty difficult to
work around. Code that tries to maniuplate user8 and user9 signals
right now may be affected
2023-04-24 09:19:15 -05:00
Calvin Rose 4ed3f2c662
Merge pull request #1114 from ianthehenry/drop-from-end
drop with a negative count now drops from the end
2023-04-24 09:16:10 -05:00
Calvin Rose 3641c8f60a
Merge pull request #1108 from wackbyte/read
README grammar and formatting changes
2023-04-24 09:15:07 -05:00
Calvin Rose e4b68cd940
Merge pull request #1109 from wackbyte/remove-double-space
Remove double space in help message
2023-04-24 09:11:45 -05:00
Calvin Rose b8c936e2fe
Merge pull request #1113 from ianthehenry/catseq
add catseq
2023-04-24 09:07:38 -05:00
Calvin Rose 83cd519702
Merge pull request #1112 from ianthehenry/dynamic-replace
string and peg replacement functions can now take functions
2023-04-24 09:07:03 -05:00
Ian Henry 54b54f85f3
drop with a negative count now drops from the end 2023-04-23 21:39:14 -07:00
Ian Henry ccd874fe4e
add catseq 2023-04-23 21:20:01 -07:00
Ian Henry 9dc7e8ed3a
peg replacement functions have access to captures
When peg/replace or peg/replace-all are given a function to serve as the text
replacement, any captures produced by the PEG are passed as additional
arguments to that function.
2023-04-23 09:15:46 -07:00
Ian Henry 485099fd6e
string and peg replacement functions can now take functions
Functions will be invoked with the matched text, and their result will be
coerced to a string and used as the new replacement text.

This also allows passing non-function, non-byteviewable values, which will be
converted into strings during replacement (only once, and only if at least
one match is found).
2023-04-23 08:36:17 -07:00
wackbyte d359c6b43e
Remove double space in help message 2023-04-22 21:46:24 -04:00
Calvin Rose d9ed7a77f8
Merge pull request #1106 from CosmicToast/1105
handle null-byte case in scanformat (fixes #1105)
2023-04-22 15:25:48 -05:00
wackbyte 4238a4ca6a README grammar and formatting changes 2023-04-20 21:06:33 -04:00
Chloe Kudryavtsev 0902a5a981 improve null format handling
there was a request to improve the error message, but the whole function
has non-informative errors. (both functions, actually, since the code is
duplicated)
as such, instead of catching it directly, address the assumption that
led to the SIGSEGV and let it be caught by the functions themselves,
thus reusing existing error messages (which can then be improved
separately).
2023-04-20 11:51:11 -04:00
Chloe Kudryavtsev f3192303ab check for NULL in get_fmt_mapping (fixes #1105)
When there is no format to be found after a %, get_fmt_mapping returns
NULL. It then gets called against strlen, which is a typical SEGV.
Check for NULL aginst mapping, which signals a null format being
specified.
2023-04-19 12:55:25 -04:00
Calvin Rose bef5bd72c2
Merge pull request #1095 from ml-2/ml
Add `keep-syntax` and `keep-syntax!` functions
2023-04-08 10:46:47 -05:00
ML b6175e4296 Add `keep-syntax` and `keep-syntax!` functions
These functions are designed to make it easier to properly preserve the
sourcemap and tuple type in macros. This commit also modifies the threading
macros to make use of these functions.
2023-04-07 21:09:52 -04:00
Calvin Rose 3858b2e177 Add `ev/all-tasks` to get running and pending root fibers. 2023-04-01 18:57:13 -05:00
Calvin Rose 9a76e77981 Update for undefined behavior sanitizer. 2023-03-24 18:49:21 -05:00
Calvin Rose 8182d640cd Merge branch 'master' of github.com:janet-lang/janet 2023-03-12 10:33:06 -05:00
Calvin Rose 1c6fda1a5c Address #1076 - unexpected shadowing behavior
While the old behavior was reasonable, it is not spelled out anywhere
in the documentation and was incidental rather than intentional.
Parameters of the same name of the function should probably take
precedence on name collision, following the principle of least surprise.
2023-03-12 10:30:59 -05:00
Calvin Rose c51db1cf2f
Merge pull request #1081 from ianthehenry/log-gamma-docstring
remove quotes in math/log-gamma docstring
2023-03-12 10:17:51 -05:00
Ian Henry 4e7930fc4c
remove quotes around log-gamma 2023-03-11 12:26:45 -08:00
Calvin Rose 3563f8ccdb
Merge pull request #1079 from dressupgeekout/charlotte_dragonfly
Some basic fixes for DragonFly
2023-03-08 15:05:51 -06:00
Charlotte Koch 575af763f6 os/which can return :dragonfly
While here, document that :bsd is another possible return value.
2023-03-07 06:45:31 -08:00
Charlotte Koch 8b16b9b246 Need to enable __BSD_VISIBLE on DragonFly in conjunction with -std=c99 2023-03-07 06:40:58 -08:00
Calvin Rose 01aab66667 Prepare for 1.27.0 release. 2023-03-05 09:48:25 -06:00
Calvin Rose aa5c987a94 Change semantics of bracketed tuple equality.
Comparison between different bracket and normal tuples
will now take into account the delimiter type. This solves strange
non-locality issues in the compiler due to this false equality, and is
more consistent with Janet's otherwise strong equality philosophy.
2023-03-03 18:24:02 -06:00
Calvin Rose 75229332c8
Merge pull request #1075 from sogaiu/math-rng-int-docs
Tweak math/rng-int docs
2023-03-03 18:09:11 -06:00
sogaiu 9d5b1ba838 Tweak math/rng-int docs 2023-02-24 19:55:47 +09:00
Calvin Rose f27b225b34
Merge pull request #1072 from sogaiu/ftell
Add file/tell
2023-02-21 07:13:00 -06:00
sogaiu 3c523d66e9 Add file/tell 2023-02-21 20:19:17 +09:00
Calvin Rose 1144c27c54
Merge pull request #1071 from ianthehenry/number-pegfault
fix a segfault in the (number) special
2023-02-20 21:01:33 -06:00
Ian Henry b442b21d3f
fix a segfault in the (number) special
This was an error about the base argument that referenced the tag argument,
which might not exist.
2023-02-20 17:07:42 -08:00
Calvin Rose 746ff5307d Update for more minimal builds. 2023-02-12 12:14:11 -06:00
Calvin Rose ef85b24d8f Add optional offset to ffi/write. 2023-02-12 12:08:28 -06:00
Calvin Rose c55d93512b Add buffer/push-at for easier manipulation of buffers
buffer/blit is difficult to use, and while buffer/push is the easiet
buffer manipulation function to use it only appends to the buffer.
buffer/push-at lets users manipulate buffers at any index - useful
for buffers used as an in-memory databases, for example.
2023-02-12 11:26:00 -06:00
Calvin Rose 2e38f9ba61 Allow passing pointer-buffers to other threads. 2023-02-12 11:07:45 -06:00
Calvin Rose 1cadff8e58 Add ffi/pointer-buffer for easier memory manipulation in FFI.
Added underlying buffer support for buffer instances that cannot
reallocated underlying memory - useful for (small) memory mapped
files and other FFI utilties.
2023-02-12 09:20:05 -06:00
Calvin Rose d1eba60ba8 Add separate sandbox flag for file/temp
Doesn't really impart (much) file systtem information when used, and
can be used for a lot of things where file functions are used to process
in a stream.
2023-02-09 08:57:53 -06:00
Calvin Rose 057dccad8f Turn on nanboxing by default for risc-v 64. 2023-02-09 03:09:53 -06:00
Calvin Rose 4285200b4b Add a sandbox option to disable native modules.
Also sort the sandbox docstring list.
2023-02-09 00:19:56 -06:00
Calvin Rose 73c2fbbc2a Check sandbox capabilities instead of ignoring unknown ones. 2023-02-06 17:38:00 -06:00
Calvin Rose 37b7e170fa Update changelist. 2023-02-06 12:31:49 -06:00
Calvin Rose b032d94877 Add sandboxing API.
The sandboxing API is meant to make janet a bit more attractive
for certain application embedding use cases. The sandboxing API
puts limits on what system resources the interpreter can access.
2023-02-06 09:05:57 -06:00
Calvin Rose 9476016741 Update asm.c 2023-02-05 23:49:18 -06:00
Calvin Rose 7a1c9c7798 Add support for debugging upvalues.
Upvalues are stored in the symbol slots structure as well, but
since they are always live, we repurpose the death_pc field to
refer to the environment index that we want to look at at runtime.
2023-02-05 15:30:01 -06:00
Calvin Rose c7fb7b4451 Merge branch 'master' into localbindings 2023-02-05 11:36:57 -06:00
Calvin Rose 67c474fc7a More fixes to ev/gather (tested on httpf server). 2023-02-05 10:21:37 -06:00
Calvin Rose 4e8154cf8a Fix ev/gather to cancel children on cancellation.
Otherwise, we would be leaving zombie fibers around.
2023-02-05 09:43:16 -06:00
Calvin Rose 9582d3c623 Allow infinite wait to work without issues. 2023-02-05 09:29:39 -06:00
Calvin Rose 0079500713 Merge branch 'master' into localbindings 2023-02-04 13:39:24 -06:00
Calvin Rose 55af6ce834 Fix write after free with printing to files. 2023-02-04 13:36:30 -06:00
Calvin Rose 3e82fdc125 Update symbolmapping code with marshal/unmarshal. 2023-02-03 17:33:11 -06:00
Calvin Rose 7344a6cfc0 Fix null check. 2023-02-03 16:24:50 -06:00
Calvin Rose 0aded71343 Fix issue with environments in asm.c 2023-02-03 16:24:50 -06:00
Calvin Rose 7663b1e703 Fix null check. 2023-02-02 22:03:18 -06:00
Calvin Rose 282546c03f Fix issue with environments in asm.c 2023-02-02 21:12:17 -06:00
Calvin Rose f4bc89d1c0 Progress. 2023-02-02 21:08:48 -06:00
Jona Ekenberg fa277c3797 added future test for upvalues and symbolslots 2023-02-01 21:26:29 +01:00
Jona Ekenberg c0c8ab25e6 added symbolslots to asm 2023-02-01 21:12:42 +01:00
Jona Ekenberg b685bf3026 updated symbolslots-test 2023-02-01 11:46:36 +01:00
Jona Ekenberg ce31db09e4 symbolslots should be gc'd, local_symbols always pushed in case *debug* is set in middle of function 2023-02-01 11:45:13 +01:00
Jona Ekenberg 624a6cf619 symbolslots nil when there are no symbols, changed debugger to not have special case 2023-02-01 11:25:52 +01:00
Jona Ekenberg 587aa87d28 symbolslots now use janet_v vectors, flat structure 2023-02-01 11:06:33 +01:00
Jona Ekenberg 88813c4f87 initial slotsyms implementation 2023-02-01 09:39:24 +01:00
Calvin Rose dacbe29771 Allow round-tripping more functions with disasm and asm.
Nested functions that captured with environments didn't
work well with asm.
2023-01-30 09:04:42 -06:00
Calvin Rose 244833cfa1
Merge pull request #1040 from lgtm-migrator/codeql
Add CodeQL workflow for GitHub code scanning
2023-01-29 09:04:18 -06:00
Calvin Rose 05e7f974e3 Add os/compiler to the core.
Allows querying what compiler was used to compile Janet.
2023-01-28 14:00:02 -06:00
Calvin Rose 0dbef65a73
Merge pull request #1065 from sogaiu/comment-tweaks
Misc comment tweaks
2023-01-27 11:26:05 -06:00
Calvin Rose 9106228787 Add :riscv32 and :riscv32 values for os/arch. 2023-01-27 11:23:57 -06:00
Calvin Rose 6ae3bdb25c Add RISC-V 64 bit detection in janet.h 2023-01-26 22:40:05 -06:00
sogaiu 310bcec260 Misc comment tweaks 2023-01-25 18:45:19 +09:00
Calvin Rose 8c4cc4e671
Merge pull request #1064 from sogaiu/realpath-doc-tweak
Update os/realpath docstring
2023-01-24 09:50:44 -06:00
Calvin Rose c6eaaa83ed Buffer initialized with janet_buffer_init will not be gced.
Set an internal flag that disables garbage collection on such
buffers. For all currently correct usage, this should have no effect,
and will fix use cases where buffers are initialized this way and then
passed to the interpreter.
2023-01-23 20:57:30 -06:00
sogaiu 8f598d6f96 Update os/realpath docstring 2023-01-23 12:55:04 +09:00
Calvin Rose 20bc323d17 Use gcc explicitly in mingw build. 2023-01-22 11:21:28 -06:00
Calvin Rose 8b0bcf4db9 Add the mingw toolchain. 2023-01-22 11:10:04 -06:00
Calvin Rose 8955e6f536 Merge branch 'master' of github.com:janet-lang/janet 2023-01-22 11:05:39 -06:00
Calvin Rose f8ddea6452 Add msys2 testing with github actions. 2023-01-22 11:05:27 -06:00
Calvin Rose 987e04086d
Merge pull request #1063 from AlecTroemel/1062-io-flag-types
use int32_t type for file flags, just like header
2023-01-22 10:56:19 -06:00
Calvin Rose 85f2acbf52 Fix tools/format.sh file permissions. 2023-01-22 10:47:33 -06:00
alectroemel 1acf4c3ab7
add int32_t type for file flags, just like header
Signed-off-by: alectroemel <alectroemel@hotmail.com>
Signed-off-by: alectroemel <alec@mirusresearch.com>
2023-01-22 10:24:46 -06:00
Calvin Rose 07a3158fba
Merge pull request #1060 from ianthehenry/doc-typos
Fix some docstring typos
2023-01-21 16:21:57 -06:00
bakpakin 2f8bed9d82 Build and install an import library on mingw 2023-01-21 14:31:48 -06:00
bakpakin a490937cd9 Add :mingw value when getting the OS setting when compiled with mingw. 2023-01-21 11:50:03 -06:00
bakpakin 8ee5942481 Fix windows build with JANET_NO_NET - #1055 2023-01-21 10:56:20 -06:00
bakpakin 93b469885a Initial Mingw support with Makefile.
Also add a macro JANET_MSVC to distinguish between
a windows build (JANET_WINDOWS) and a build with msvc.
2023-01-21 10:37:34 -06:00
Calvin Rose d8d1de2dcb Don't compile library loading code on windows if it is disabled. 2023-01-21 09:36:03 -06:00
Ian Henry ab224514f0
Fix some docstring typos. 2023-01-18 19:41:56 -08:00
Calvin Rose 75179de8da
Merge pull request #1056 from fd00/use-dev-urandom-on-cygwin
Use `/dev/urandom` for `janet_cryptorand` on cygwin
2023-01-08 09:29:52 -06:00
Calvin Rose c28df14e6b Prepare for 1.26.0 release 2023-01-07 15:08:40 -06:00
Calvin Rose b73855b193 Merge branch 'master' of github.com:janet-lang/janet 2023-01-07 15:05:16 -06:00
Calvin Rose 2093ab2baa Update copyrights. 2023-01-07 15:04:56 -06:00
Calvin Rose a0f40042cb Update copyright year. 2023-01-07 15:03:35 -06:00
Daisuke Fujimura (fd0) 3254c2c477 Use /dev/urandom for janet_cryptorand on cygwin 2023-01-07 08:58:35 +09:00
Calvin Rose 0a8eb9e3ba
Merge pull request #1057 from sogaiu/update-tests-for-meson
Add test files to meson suite 11 - 14
2023-01-04 04:13:18 -06:00
sogaiu 70e0c6f9ef Add test files to meson suite 11 - 14 2023-01-04 12:59:26 +09:00
Calvin Rose a8a78d4525
Merge pull request #1052 from dressupgeekout/cpu_count_reduced_os
(os/cpu-count) should not be defined at all with JANET_REDUCED_OS
2022-12-16 11:11:30 -06:00
Calvin Rose 57e6ee963d
Merge pull request #1046 from dressupgeekout/charlotte_sort_doc
Explicitly mention that `sort-by` sorts a list in place.
2022-12-16 11:11:07 -06:00
Calvin Rose ce6bfb8420
Merge pull request #1049 from harryvederci/patch-1
Improve documentation for the `all` function.
2022-12-16 09:51:59 -06:00
Calvin Rose f0672bdc59
Merge pull request #1051 from sogaiu/math-abs-vs-fabs-issue
Tweak math/abs to improve doc result
2022-12-16 09:51:43 -06:00
Charlotte Koch 23de953fbd (os/cpu-count) should not be defined at all with JANET_REDUCED_OS 2022-12-15 20:16:43 -08:00
Calvin Rose 03c496bdd8 Update changelog 2022-12-15 21:38:36 -06:00
Calvin Rose d5ee6cf521 Add malloc and free to ffi.
Very "unsafe", but a good tool of last resort. In most cases
a buffer is preferable, but the lifetime can be a bit unclear.
This allows very granular control over memory.
2022-12-15 21:35:44 -06:00
sogaiu fb7981e053 Tweak math/abs to improve doc result 2022-12-11 00:09:50 +09:00
harryvederci 846123ecab
Improve documentation for the `all` function. 2022-12-09 11:16:42 +00:00
Calvin Rose 373cb444fe Merge branch 'master' of github.com:janet-lang/janet 2022-12-04 11:08:28 -06:00
Calvin Rose 90f212df92 Add length method ffi/jitfn abstract values. 2022-12-04 11:08:17 -06:00
Calvin Rose 12286e4246 Add length method ffi/jitfn abstract values. 2022-12-04 10:27:28 -06:00
Calvin Rose aa60c1f36a Add ffi jit example. 2022-12-03 17:52:23 -06:00
Calvin Rose c731f01067 Address windows compilation warning. 2022-12-03 12:10:22 -06:00
Calvin Rose 6c9c1cdb30 MAP_ANON(YMOUS) not strictly needed. 2022-12-03 11:45:33 -06:00
Calvin Rose 9ba2b40e87 Add MAP_ANON instead of MAP_ANONYMOUS for mac 2022-12-03 11:31:04 -06:00
Calvin Rose 7a3d055012 Add ffi/jitfn for JIT compilation.
Convert a byte sequence of machine code to an
an executable pointer that can be used with ffi/call.
2022-12-03 11:26:23 -06:00
Calvin Rose 0824f45e29 Format compile.c 2022-11-27 10:15:01 -06:00
Charlotte Koch 4debe3446c Explicitly mention that `sort-by` sorts a list in place. 2022-11-20 20:51:49 -08:00
Calvin Rose 07fe9bcdf6 Update state header to include pthread 2022-11-11 11:48:50 -06:00
Calvin Rose 6a557a73f5 Simplify eval.
Also add more conventional handling of nil to the `compile` function.
2022-11-11 11:25:06 -06:00
Calvin Rose 8d1cfe0c56 Simplify eval-string implementation. 2022-11-11 11:15:53 -06:00
Calvin Rose a3a42eebea Create pthread threads with detached attribute.
Rather than calling pthread_detach on a default thread.
2022-11-11 11:01:59 -06:00
Calvin Rose 76be8006a4 Add channel marshalling. 2022-11-10 16:32:54 -06:00
Calvin Rose bfcfd58259 Update for TCC to include stdatomic.h 2022-11-09 07:55:21 -06:00
Calvin Rose 914a4360e7 Indicate version bump since header file changed. 2022-11-05 16:38:52 -05:00
Calvin Rose 8c31874eeb Remove unused assert.h 2022-11-05 11:44:14 -05:00
Calvin Rose ef7afeb2ea Add 64 bit integer support to printf and other formatting functions. 2022-11-05 11:33:19 -05:00
LGTM Migrator 4067f883a2
Add CodeQL workflow for GitHub code scanning 2022-11-05 10:22:49 +00:00
Calvin Rose c8974fffbe Fix docstring. 2022-11-04 11:23:08 -05:00
Calvin Rose b75fb8dc9e Add :@all: to module/expand-path
Allow more easily importing modules from custom directories
without jumping through too many hoops. Technically, this was
possible before but required circumventing the built-in module/paths
and was just a hassle.

Also add entries to module/path (and module/add-path) to allow code
like the following.

(setdyn :my-libs "/home/me/janet-stuff/")

(import @my-libs/toolbox)

Intended for things like test harnesses where code might not
be installed to the usual directories.
2022-11-04 11:15:48 -05:00
Calvin Rose 57356781a9 Fix typo. 2022-10-30 13:36:13 -05:00
Calvin Rose e43eab5fd6 Fix panicf call. 2022-10-30 09:57:40 -05:00
Calvin Rose 894cd0e022 Prepare for 1.25.1 release. 2022-10-29 11:58:29 -05:00
Calvin Rose db2c63fffc Update CHANGELOG.md 2022-10-24 20:32:02 -05:00
Calvin Rose 60e0f32f1a Fix os/open with :rw permissions on posix. 2022-10-24 19:39:58 -05:00
Calvin Rose e731996a68 Allow overriding JANETCONF_HEADER in Makefile.
This allows a configuration workflow that is a bit simpler than before
and doesn't requiring applying patches. Instead, add a config.mk to
source dir with JANETCONF_HEADER=myconfig.h and compile as usual.

The patching workflow will of course still work exactly as before.
2022-10-24 09:49:51 -05:00
Calvin Rose 2f69cd4209 Add easier option for adding config.mk in root directory. 2022-10-23 13:11:07 -05:00
Calvin Rose fd59de25c5 Add memcmp to the core. Useful in binary protocol implementations. 2022-10-18 11:54:07 -05:00
Calvin Rose af12c3d41a Typo fixes. 2022-10-10 18:38:24 -05:00
Calvin Rose 54b52bbeb5 Prepare for 1.25.0 release. 2022-10-10 18:24:48 -05:00
Calvin Rose 1174c68d9a Update CHANGELOG.md 2022-10-10 18:23:15 -05:00
Calvin Rose 448ea7167f Add CLOEXEC when calling accept on Linux.
Prevents leakage of file descriptors to subprocesses.
The symptom of the above issue is sockets that don't seem to close
until a subprocess completes.
2022-10-10 18:06:31 -05:00
Calvin Rose 6b27008c99 Fix os/date with nil argument. 2022-10-10 15:24:28 -05:00
Calvin Rose 725c785882 Formatting. 2022-10-10 14:24:03 -05:00
Calvin Rose ab068cff67 Remove WNOWAIT code on linux.
Would cause os/proc-wait to block in some circumstances.
2022-10-10 14:23:17 -05:00
bakpakin 9dc03adfda Fix pass by reference in windows FFI to accomodate stack shift. 2022-09-22 10:58:16 -05:00
bakpakin 49f9e4eddf Fix ifdef in capi.c for janet_getuinteger64 and janet_getinteger64 2022-09-20 15:42:20 -05:00
bakpakin 43c47ac44c Address #1037 - move stack hack after arg writing logic to avoid
clobber.
2022-09-20 15:37:20 -05:00
Calvin Rose 1cebe64664 Add some soft test cases for #1037. 2022-09-20 10:01:12 -05:00
Calvin Rose f33c381043 Improve sysv64 classify algorithm. 2022-09-20 09:45:17 -05:00
Calvin Rose 3479841c77 Address #1034 - add handling for 8-16 byte structs in FFI. 2022-09-20 09:28:46 -05:00
Calvin Rose 6a899968a9 Allow passing user signals to (signal) as keywords. 2022-09-17 21:18:07 -05:00
Calvin Rose bb8405a36e
Merge pull request #1029 from locriacyber/patch-0
Fix documentation for ev/go, ev/spawn
2022-09-16 07:32:25 -05:00
bakpakin c7bc711f63 Add windows FFI example test case for void functions with double
argument.
2022-09-15 13:58:54 -05:00
bakpakin e326071c35 Fix void returns in windows FFI - address #1025 2022-09-15 13:51:11 -05:00
Locria Cyber ad6a669381
Add doc for ev/go
Document that you can pass a function instead of a fiber to ev/go
2022-09-14 00:17:53 +00:00
Locria Cyber e4c9dafc9a
Fix typo in ev/spawn doc 2022-09-13 23:49:42 +00:00
Calvin Rose dfc0aefd87
Merge pull request #1028 from autumnull/master
Made peg 'not' and 'if-not' drop their captures on success
2022-09-13 15:20:10 -05:00
Calvin Rose 356b39c6f5 Add test case for #1027 2022-09-12 19:00:59 -05:00
Calvin Rose 8da7bb6b68 Fix peg/replace-all and family - Fix #1027 2022-09-12 18:58:48 -05:00
Autumn! 9341081a4d Made peg 'not' and 'if-not' drop their captures on success 2022-09-12 23:07:56 +01:00
Calvin Rose 324a086eb4
Merge pull request #1023 from ScriptDevil/set-manpath
Set JANET_MANPATH environment variable while installing.
2022-09-10 09:55:01 -05:00
Ashok Gautham ed595f52c2
Set JANET_MANPATH environment variable while installing.
JPM on windows currently installs its manpage to C:\ directly because this isn't set when installing Janet through the MSI installer
2022-09-09 13:24:36 +05:30
Calvin Rose 64ad0023bb
Merge pull request #1022 from autumnull/master
Removed unnecessary backslashes from documentation
2022-09-08 08:52:55 -05:00
Autumn! fe5f661d15 Removed unnecessary backslashes from documentation 2022-09-08 13:21:17 +01:00
Calvin Rose ff26e3a8ba Remove end of string check that is now redudant.
The addition of some code to avoid valgrind warnings made this code
redundant.
2022-09-05 20:13:15 -05:00
Calvin Rose 14657a762c Fix peg RULE_SET op code when at tail of string in some cases. 2022-09-05 14:11:03 -05:00
Calvin Rose 4754fa3902 Fix issue #1021 - bad format specifiers in run.c 2022-09-03 14:03:51 -05:00
Calvin Rose f302f87337
Merge pull request #1019 from Techcable/fix/inttypes-overflow
Signed integer overflow is undefined behavior in C, avoid it in inttypes.c
2022-08-30 23:23:11 -05:00
Calvin Rose 94dbcde292
Merge pull request #1020 from pepe/comment-typo
Fix typo in define comment
2022-08-30 22:57:52 -05:00
Josef Pospíšil 4336a174b1 Fix typo in define comment 2022-08-30 09:21:20 +02:00
Techcable 0adb13ed71
inttypes.c: Avoid signed integer overflow (U.B.)
In C, signed arithmetic overflow is undefined behvior
but unsigned arithmetic overflow is twos complement

Unconditionally switch to unsigned arithmetic internally for +, -, *
This will not affect the result thanks to twos complement awesomeness.

I don't think this will be an issue in these functions,
but it has a history of causing bugs.....
2022-08-29 18:38:51 -07:00
Techcable e78a3d1c19
Add unit tests for contains? 2022-08-26 21:47:18 -07:00
Techcable c099ec05ee
Remove documentation on type error from index-of
Three reasons:
1. This same behavior is not documented on the `next` function
2. This function does not throw the error directly,
   it only throws an error because `next` does.
3. Following the same idea as the previous commit, this behavior is
   more or less implementation-defined for nonsensical types
  > In dynamic languages, the usual idea is garbage in, garbage out.

Various other documentation cleanup.
2022-08-26 21:46:58 -07:00
Techcable a20612478e
Remove try from contains?, allowing type errors
> Remove the try. In dynamic languages, the usual idea is garbage in, garbage out. You misunderstood my point about the type error. “Test” functions are not special in that regard.
> - @bakpakin
2022-08-26 20:36:17 -07:00
Techcable f778e8bbd1
Fix incorrect usage of the test macro
I need unit tests....
2022-08-26 15:35:26 -07:00
Techcable 7203c046f9
Remove collection? type test
No longer used to guard the type tests.
2022-08-26 15:23:52 -07:00
Techcable 754b61c593
Clarify documentation of contains?
Also contains-value?
2022-08-26 15:19:39 -07:00
Techcable 927e9e4e4d
Make contains? consistently iterate over values.
Remove `contains-value?` because it is now redundant.

Clarify in the documentation that it checks dictionary values.
2022-08-26 15:06:09 -07:00
Techcable 699f9622d7
Warn about index-of type errors when not iterable
This is just documentation of existing behavior, it does not change anything.

The reason index-of throws a type error on non-iterable types is because `next` does.
This is hardcoded into the JOP_NEXT opcode (see src/core/value.c:janet_next_impl).

Unfortunately, there is currently no corresponding `iterable?` check.
2022-08-26 15:05:39 -07:00
Techcable 765eb84c33
on bad type, contains? shuld return false (not error)
Note this actually changes behavior from a thin wrapper over `index-of`.
This is because `(index-of 3 3)` throws "error: expected iterable type, got 3"
2022-08-26 14:23:36 -07:00
Calvin Rose 03ba1f7021 Update CHANGELOG and version numbers. 2022-08-26 13:15:30 -05:00
Calvin Rose 1f7f20788c Add line loop example for awk or sed like processing. 2022-08-26 12:29:23 -05:00
Calvin Rose c59dd29190 Add stress test for marshalling to examples. 2022-08-26 12:27:53 -05:00
Calvin Rose 99f63a41a3 Improve pointer hashing to avoid hash collisions. 2022-08-26 12:18:10 -05:00
Calvin Rose a575f5df36 Add option to marshal values without cycle detection. 2022-08-26 11:20:02 -05:00
Techcable 12a1849090
Add utilities for contains? and contains-key?
This is significantly clearer than using (not (nil? (index-of col val)))

Most major programming languages offer some sort of contains function (Python, Java, C, Rust).
The only exception I know of is C.
2022-08-25 21:00:02 -07:00
Calvin Rose 0817e627ee Prepare for 1.24.1 release. 2022-08-24 13:23:53 -05:00
Calvin Rose 14d90239a7 Merge branch 'master' of github.com:janet-lang/janet 2022-08-24 11:35:37 -05:00
Calvin Rose f5d11dc656 Address #1014 improve parse errors when bad delimiters are found.
Reuse some existing logic for eof errors.
2022-08-24 11:34:59 -05:00
Calvin Rose 6dcf5bf077
Merge pull request #1012 from Techcable/doc/clarify-flag-E
Clarify the documentation of janet -E flag
2022-08-21 13:45:17 -05:00
Calvin Rose ac2082e9b3 Allow adding name to short-fns.
When short-fn is used in a macro, it can be useful to
give the function a nicer name then a raw pointer.
2022-08-18 14:33:59 -05:00
Techcable dbac495bee
Clarify the documentation of janet -E flag
This confused me, despite having a fair deal of janet experience.
2022-08-18 12:16:14 -07:00
Calvin Rose fe5ccb163e Merge branch 'master' of github.com:janet-lang/janet 2022-08-16 12:38:59 -05:00
Calvin Rose 1aea5ee007 Remove stack inversion code for sysv64 FFI. 2022-08-16 12:38:44 -05:00
Calvin Rose 13cd9f8067 Remove stack inversion code for sysv64 FFI. 2022-08-16 12:20:38 -05:00
bakpakin 34496ecaf0 Prepare for 1.24.0 release. 2022-08-14 20:20:09 -05:00
bakpakin c043b1d949 Add win32 ffi example. 2022-08-14 15:40:09 -05:00
bakpakin 9a6d2a7b32 Fix FFI for reference return values and stack parameter passing. 2022-08-14 15:20:30 -05:00
bakpakin f8a9efa8e4 Allow binding pre-loaded symbols in windows FFI.
Mimic the posix RTLD_NOW setting for dlopen by iterating
opened DLLs to look for symbols.
2022-08-14 13:26:13 -05:00
Calvin Rose 5b2169e0d1 Fix docstring. 2022-08-02 14:58:32 -05:00
Calvin Rose 2c927ea768 Add testcase for issue #1005 2022-08-02 12:34:24 -05:00
Calvin Rose f4bbcdcbc8 Get rid of disabled tracing. #1005 2022-08-02 12:19:22 -05:00
Calvin Rose 79c375b1af Address #1005 - Fix janet_call stack clobbering on dirty stack. 2022-08-02 12:13:56 -05:00
Calvin Rose f443a3b3a1 Remove type_array option to meson_min build 2022-07-26 14:27:22 -05:00
Calvin Rose 684d2d63f4 Emphasize the ldconfig error is expected. 2022-07-20 11:19:09 -05:00
Calvin Rose 1900d8f843 Fix build warnings on Linux GCC version 12.1.0 x64 2022-07-20 08:04:03 -05:00
Calvin Rose 3c2af95d21 Update CHANGELOG.md 2022-07-19 20:05:21 -05:00
Calvin Rose b35414ea0f Merge branch 'master' of github.com:janet-lang/janet 2022-07-19 20:04:44 -05:00
Calvin Rose fb5b056f7b Address #1001 - don't process names passed to dlopen. 2022-07-19 20:04:17 -05:00
bakpakin 7248c1dfdb Give up if ln fail. 2022-07-09 19:10:25 -05:00
bakpakin 4c7ea9e893 Merge branch 'master' of github.com:janet-lang/janet 2022-07-09 11:44:20 -05:00
bakpakin c7801ce277 Address #997 - clang undefined behavior warning. 2022-07-09 11:43:51 -05:00
Calvin Rose f741a8e3ff
Merge pull request #998 from autumnull/master
stop doc-format detecting other modes within code blocks
2022-07-09 11:40:51 -05:00
bakpakin 6a92e8b609 Update CHANGELOG and make tweaks to win32 shell 2022-07-09 11:39:06 -05:00
bakpakin 9da91a8217 Update shell.c to have smart behavior on windows. 2022-07-09 11:23:02 -05:00
bakpakin 69853c8e5c Merge branch 'master' of github.com:janet-lang/janet 2022-07-08 09:49:56 -05:00
Autumn! 1f41b6c138 doc-format no longer detects other modes within code blocks 2022-07-07 14:41:46 +01:00
Calvin Rose e001efa9fd Fix #996 - linking command works on busybox. 2022-07-04 16:48:07 -05:00
Calvin Rose 435e64d4cf Allow shorthand for setting task-id on new threads with flag.
Avoids the need to wrap function bodies in closures in many cases.
2022-07-03 12:08:21 -05:00
Calvin Rose f296c8f5fb Merge branch 'master' of github.com:janet-lang/janet 2022-07-02 21:11:55 -05:00
Calvin Rose 8d0e6ed32f Fix function handlers for :out and :err.
They were not properly handled for formatting functions.
2022-07-02 21:11:05 -05:00
Calvin Rose b6a36afffe
Merge pull request #994 from shassard/master
Use relative path for include/janet.h symlink
2022-07-02 12:30:39 -05:00
Stephen Hassard e422abc269
Use relative path for include/janet.h symlink
When using make to build an rpm, the current symlink is
created with an absolute path to the buildroot as causes
the make install target to fail with:

error: Symlink points to BuildRoot: /usr/include/janet.h -> /home/stephen/rpmbuild/BUILDROOT/janet-1.23.0-3.x86_64/usr/include/janet/janet.h

We can create the link relatively which makes this more
portable, where:

ln -sf -t '/home/stephen/rpmbuild/BUILDROOT/janet-1.23.0-3.x86_64/usr/include' janet.h janet/janet.h

Resulting in the following symlink:

ls -la BUILDROOT/usr/include/janet.h
lrwxrwxrwx. 1 stephen stephen 13 Jul  2 08:17 BUILDROOT/usr/include/janet.h -> janet/janet.h

This symlink can then be properly packaged without path
issues.

Signed-off-by: Stephen Hassard <steve@hassard.net>
2022-07-02 08:52:17 -07:00
Calvin Rose 221d71d07b
Merge pull request #993 from pepe/test-tabseq
Add basic test for tabseq
2022-07-02 09:30:59 -05:00
Calvin Rose 9f35f0837e
Merge pull request #991 from pepe/master
Trace function to the stderr
2022-07-02 09:29:18 -05:00
Josef Pospíšil 515891b035 Add basic test for tabseq 2022-07-02 07:43:28 +02:00
Josef Pospíšil 94a506876f Trace function to the stderr 2022-07-01 12:23:25 +02:00
Calvin Rose 9bde57854a Add `tabseq` macro. 2022-06-28 22:51:41 -05:00
Calvin Rose f456369941 Add support for a dyn :task-id
Adds extra information to default information from supervisor
channels. For threaded channels as supervisors, we don't get
the source fiber so identifying the source of messages was not
possible. This change allows better multithreading with  supervisors.
2022-06-25 18:51:21 -05:00
Calvin Rose 8f0a1ffe5d Github showing old git attributes. 2022-06-20 11:23:21 -05:00
Calvin Rose e4bafc621a Remove ssize_t usage. 2022-06-20 11:09:41 -05:00
Calvin Rose cfa39ab3b0 Prepare for 1.23.0 release. 2022-06-20 10:49:25 -05:00
Calvin Rose 47e91bfd89 Fix docstring. 2022-06-19 18:52:37 -05:00
Calvin Rose eecc388ebd Add support for 0-element arrays in FFI.
Allows for flexible array member construct mapping.
2022-06-19 16:29:55 -05:00
Calvin Rose 0a15a5ee56 Prepare for 1.23.0 release. 2022-06-19 15:07:35 -05:00
Calvin Rose cfaae47cea Fix trailing :pack-all or :pack in struct. 2022-06-19 13:06:19 -05:00
Calvin Rose c1a0352592 Fix unset field in JanetFFIType. 2022-06-19 12:58:45 -05:00
Calvin Rose 965f45aa3f Update changelog to say FFI initially only available on non-windows
platforms.
2022-06-19 12:42:44 -05:00
Calvin Rose 6ea27fe836 Error message sounded a bit unsure. 2022-06-19 10:29:42 -05:00
Calvin Rose 0dccc22b38 Improve error messages when using bad metadata
Print metadata value as well as binding name.
2022-06-19 10:28:18 -05:00
Calvin Rose cbe833962b Remove bad suite0009 test. Close #871
The issue is that there was no synchronization on writes.
The stability of the test relied on the fact that the server
would read in an entire message in one call to ev/read, which
would _almost_ always happen since the messages are so small.
2022-06-19 10:01:10 -05:00
Calvin Rose b5720f6f10 On suite0009 errors for localname/peername, add info
Tag when the issue in the server or in the client. On windows, sometimes
these seemed to get swapped for strange reason.
2022-06-19 09:31:43 -05:00
Calvin Rose 56b4e0b0ec Update CONTRIBUTING.md 2022-06-19 09:18:59 -05:00
Calvin Rose e316ccb1e0 Use _tzset() on windows before localtime_s 2022-06-19 08:49:54 -05:00
Calvin Rose a6f93efd39 Support for array types in ffi. 2022-06-19 08:03:32 -05:00
Calvin Rose 20511cf608 Cast NULL pointer to nil in return in ffi. 2022-06-18 16:53:01 -05:00
Calvin Rose 1a1dd39367 Use __builtin_alloca if no other option. 2022-06-18 13:54:47 -05:00
Calvin Rose 589981bdcb BSD systems put alloca in the stdlib 2022-06-18 12:18:06 -05:00
Calvin Rose 89546776b2 alloca 2022-06-18 12:15:16 -05:00
Calvin Rose f0d7b3cd12 No alloca.h? 2022-06-18 11:19:14 -05:00
Calvin Rose e37be627e0 Allow loading current process on windows as well. 2022-06-18 10:31:00 -05:00
Calvin Rose d803561582 Fix ffi/defbind for non-lazy bindings.
Add testing to bind to symbols in current binary.
2022-06-18 10:14:42 -05:00
Calvin Rose a1aab4008f Update FFI example. 2022-06-18 10:06:39 -05:00
Calvin Rose a1172529bf Fix named arguments with optional args. 2022-06-18 09:46:28 -05:00
Calvin Rose 1d905bf07f SRWLock is the size of a void pointer. 2022-06-17 17:49:02 -05:00
Calvin Rose eed678a14b Include windows.h for windows builds 2022-06-17 17:41:50 -05:00
Calvin Rose b1bdffbc34 Don't inlcude pthread on windows. 2022-06-17 17:35:58 -05:00
Calvin Rose cff718f37d Add suite0012 stub with delay test. 2022-06-17 17:27:42 -05:00
Calvin Rose 40e9430278 Move examples to example directory. 2022-06-17 17:24:52 -05:00
Calvin Rose 62fc55fc74 Remove pthread.h from janet.h
Should make janet a bit easier to use. Also changes the
header to not expose the size of native mutexes and rwlocks, except
with janet_os_mutex_size and janet_os_rwlock_size.
2022-06-17 17:13:58 -05:00
Calvin Rose 80729353c8 Add :lazy option for ffi/context for jpm quickbin usage. 2022-06-13 21:26:03 -05:00
Calvin Rose 105ba5e124 Add ffi/context and ffi/defbind helpers.
Wrap the very bare-bones FFI library to be a bit more
useful out of the box.
2022-06-12 18:48:47 -05:00
Calvin Rose ad1b50d1f5 Update dofile function signature. 2022-06-12 18:03:23 -05:00
Calvin Rose 1905437abe Merge branch 'master' into ffi 2022-06-12 13:59:37 -05:00
Calvin Rose 87fc339c45 Add named arguments with the &named symbol.
Similar to &keys, but more ergonomic.
2022-06-12 13:53:18 -05:00
Calvin Rose 3af7d61d3e Update gtk example. 2022-06-12 12:51:06 -05:00
Calvin Rose a45ef7a856 Update CHANGELOG to reflect new function renames. 2022-06-12 10:17:25 -05:00
Calvin Rose 299998055d Update meson min build to turn off ffi. 2022-06-12 10:15:36 -05:00
Calvin Rose c9586d39ed Add a :none calling convention.
The ffi module is useful even when true ffi calls
are not yet implemented. This lets the ffi be enabled
on any architecture, albeit with a degraded feature set
where calling conventions are not implemented.
2022-06-12 10:12:45 -05:00
Calvin Rose 2e9f67f4e4 Change all "native-*" to ffi/. Move new dll loading funcs.
native-close, raw-native and native-lookup have become
ffi/close, ffi/native, and ffi/lookup instead.

The new ffi module will be useful for any architecture even if we don't
support making calls to certain functions. We can simple add a
do-nothing calling convetion that panics on call. ffi/read and ffi/write
are useful in their own right.
2022-06-12 10:02:02 -05:00
Calvin Rose e318170fea Begin working on windows calling convetion.
Also remove inline assembly for making sysv64 calls.
Instead, use crafted function signatures to set all needed registers.
2022-06-12 09:16:10 -05:00
Calvin Rose 73c4289792 Fix define check. 2022-06-11 21:50:34 -05:00
Calvin Rose ea45d7ee47 Convert to one big blob of assembly for sysv cc.
Also begin working on win64 calling convention.
2022-06-11 21:43:35 -05:00
Calvin Rose 6d970725e7 Update boot.janet for typos. 2022-06-11 21:19:42 -05:00
Calvin Rose 458c2c6d88 Make calling convention optional for trampoline 2022-06-11 15:47:51 -05:00
Calvin Rose 0cc53a8964 Get a GTK example working. Good proof of concept. 2022-06-11 14:47:35 -05:00
Calvin Rose 0bc96304a9 Add r32 and r64 aliases for real numbers in ffi types. 2022-06-11 09:40:37 -05:00
Calvin Rose c75b088ff8 Format boot.janet with janet-format. 2022-06-10 19:13:23 -05:00
Calvin Rose 181f0341f5 Add :pack and :pack-all keywords to allow for struct packing.
Syntax may need some work but covers both fully packed structs
as well as packing of individual members.
2022-06-10 18:53:22 -05:00
Calvin Rose 33bb08d53b Merge branch 'master' into ffi 2022-06-10 16:24:55 -05:00
Calvin Rose 6d188f6e44 Improve .ppasm function. 2022-06-10 16:24:40 -05:00
Calvin Rose c3648331f1 Expose an easy to use `debugger` function. 2022-06-10 15:39:29 -05:00
Calvin Rose a5b66029d3 Expose the built-in debugger in more places. 2022-06-10 15:23:15 -05:00
Calvin Rose 49bfe80191 Make sure void return types work as expected. 2022-06-10 12:33:01 -05:00
Calvin Rose a5def77bfe Add support for struct return values. 2022-06-10 12:25:08 -05:00
Calvin Rose 9ecb5b4791 Add native-read function as inverse to native-write. 2022-06-10 09:38:52 -05:00
Calvin Rose 1cc48a370a Add native-write, which will write structs to buffers.
Useful for testing as well as useful in its own right. Begs
for an inverse, native-read which would convert byte data
to native structs.
2022-06-10 08:46:20 -05:00
Calvin Rose f1ec8d1e11 Beginning of struct support.
TODO:
- struct return values
- support for unions in signatures
- more testing
- complex types
- packed structs
- writing structs to buffers (useful and we have most of the machinery).
2022-06-09 20:27:56 -05:00
Calvin Rose 55c34cd84f
Merge pull request #985 from masukomi/readme_update
added make install & install-jpm-git to Readme
2022-06-09 10:02:58 -05:00
masukomi aca52d1e36
added make install & install-jpm-git to readme 2022-06-08 21:58:55 -04:00
Calvin Rose 6f90df26a5 Alloca included by default on some OS, but not all.
Do explcitly include alloca on non-msvc compilers.
2022-06-08 10:01:19 -05:00
Calvin Rose 9d9cb378ff Don't include alloca.h, not in MSVC. 2022-06-08 09:59:13 -05:00
Calvin Rose f92aac14aa Only enable FFI on x86-64, non-windows OSes. 2022-06-08 09:50:31 -05:00
Calvin Rose 3f27d78ab5 Add some FFI testing and more improvements to sysv abi.
Add support for integer return and floating point return variants, as
well as arguments on the stack. Start flushing out struct arguments.

Still needed:
- structs (packed and unpacked)
- complex numbers
- long doubles
- MASM alternative for windows (you can technically use sysv abi on
  windows)
- more calling conventions.
2022-06-08 09:44:49 -05:00
Calvin Rose 282d1ba22f Implement sys v abi on x64 partially. 2022-06-06 18:54:17 -05:00
Calvin Rose 94c19575b1 Fix when clib is not pointer type. 2022-06-06 13:37:07 -05:00
Calvin Rose e3e485285b Prevent double usage of native objects after closing. 2022-06-06 13:36:03 -05:00
Calvin Rose 986e36720e Update windows builds for raw-natives. 2022-06-06 13:08:12 -05:00
Calvin Rose 74348ab6c2 Fix symbol lookup when symbol isn't found. 2022-06-06 10:53:00 -05:00
Calvin Rose 8d1ad99f42 Add stubs that are precursor to FFI.
FFI may be best implemented as an external library
(libffi has incompatible license to Janet) or as code
that takes void * and wraps then into Janet C functions
given a function signature. Either way, we need to some way
to load symbols from arbitrary dynamic libraries.
2022-06-06 10:49:30 -05:00
Calvin Rose e69bbff195 Update CHANGELOG.md 2022-06-05 17:40:50 -05:00
Calvin Rose c9f33bbde0 Add rwlocks. 2022-06-05 16:42:18 -05:00
Calvin Rose 9c9f9d4fa6 Add some thread coordination primitives.
Due to the nature of event loops, it is a bit difficult to integrate
lock and other primitives such that they don't block fibers on the same
thread.
2022-06-05 15:24:34 -05:00
Calvin Rose 2f64a6b0cb Add `parse-all` function as a natural extension to the `parse` function. 2022-05-28 19:02:17 -05:00
Calvin Rose dfa78ad3c6 typo 2022-05-28 12:23:28 -05:00
Calvin Rose 677ae46f0c Fix README links for sourcehut. 2022-05-28 12:22:28 -05:00
Calvin Rose 6ada2a458f Fixes on bsd for os/cpu-count. 2022-05-28 12:21:44 -05:00
Calvin Rose 8145f3b68d On linux, available CPUs is more useful information. 2022-05-28 12:19:25 -05:00
Calvin Rose 48289acee6 Add os/cpu-count functionality. 2022-05-28 12:01:23 -05:00
Calvin Rose e5a989c6f9 Remove multiple outputs with same name for old meson versions. 2022-05-27 21:14:47 -05:00
Calvin Rose 4c56704935
Merge pull request #979 from turrisxyz/Pinned-Dependencies-GitHub
chore: Set permissions for GitHub actions
2022-05-27 17:03:54 -05:00
naveen 9cda44f443 chore: Set permissions for GitHub actions
Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much.

- Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs

[Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)

Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
2022-05-27 00:32:28 +00:00
Calvin Rose 431451bac2 Make install work ok if meson is old. 2022-05-25 22:35:20 -05:00
Calvin Rose 395ca7feea Fix meson.build for older versions of meson. 2022-05-14 10:27:28 -05:00
bakpakin e0b7533c39 Add toggle macro. 2022-05-12 15:36:29 -05:00
bakpakin 5b2a402930 Fix version bump. 2022-05-09 10:28:09 -05:00
bakpakin 85129a1873 Prepare for 1.22.0 release. 2022-05-09 10:19:40 -05:00
Calvin Rose 487d333024 Add `module/value` function to make grabbing bindings out module tables. 2022-05-05 19:24:44 -05:00
Calvin Rose fe7d35171f Remove file/popen - address #974 2022-05-05 18:33:34 -05:00
Calvin Rose b3aed13567 Use janet_getnat when non-negative integer needed. 2022-05-05 18:27:29 -05:00
Calvin Rose a9d4d2bfa3
Merge pull request #976 from rick2600/master
Fix #975 - null ptr dereference when a table is created with negative capacity
2022-05-05 08:56:15 -05:00
rick2600 1ff521683f Fix #975 - null ptr dereference when a table is created with negative capacity 2022-05-05 02:11:43 -03:00
Calvin Rose 0395a03b6b
Merge pull request #973 from rick2600/master
fix negative count passed to cfun_array_new_filled
2022-05-02 11:13:20 -05:00
rick2600 7fda7709ff fix negative count passed to cfun_array_new_filled 2022-05-02 12:57:47 -03:00
Calvin Rose 65a9200cff
Merge pull request #972 from uvtc/patch-2
os.c doc formatting typo
2022-04-29 23:04:31 -05:00
John Gabriele 473eec26c1
os.c doc formatting typo 2022-04-29 23:57:37 -04:00
Calvin Rose 9fa945ad93 Don't include captures of last match from `to` combinator. 2022-04-29 19:21:10 -05:00
Calvin Rose a895219d2f Fix #971 - remove to rule optimization
For to and thru, we need to restore eveytime through the loop since rules need
run with the right captures on the stack, especially if they have any
sort of backrefs.
2022-04-29 19:15:56 -05:00
bakpakin 427f7c362e Fix os/execute regression. 2022-04-27 22:59:27 -05:00
Calvin Rose 73f5c41fae Address #968 Ignore :pipe arguments in os/execute.
They are only useful in os/spawn. Also update docstrings.
2022-04-27 20:13:10 -05:00
Calvin Rose b4ec168401 Address #950 - add defn suggestion on bad def.
While generally we are not in the business of making a very chatty
compiler, this is a simple improvement that involves compiling
metadata before the binding, as well as adding a suggestion for `defn`
in case the compiler encounters an unexpected tuple.
2022-04-23 22:27:34 -05:00
Calvin Rose 726d35c766 Update changelog with a few fixes. 2022-04-22 23:13:08 -05:00
Calvin Rose 6db796e10c Add janet.h (in addition to janet/janet.h) on install.
A number of bindings (many of which I have written) include
<janet.h> rather than <janet/janet.h>.
2022-04-22 22:29:12 -05:00
Calvin Rose c38d9134cd
Merge pull request #967 from uvtc/patch-2
boot.janet docstrings (part 3, last part)
2022-04-20 20:53:30 -05:00
John Gabriele 471204b163
boot.janet docstrings (part 3, last part)
Added some backticks around code in docstrings to distinguish them from prose.

Also some light editing.
2022-04-20 18:31:06 -04:00
Calvin Rose 7f23bfa66d
Merge pull request #966 from uvtc/patch-2
boot.janet docstrings (part 2)
2022-04-19 20:24:32 -05:00
John Gabriele 9287b26042
boot.janet docstrings (part 2)
Added some backticks around code in docstrings to distinguish them from prose.

Also some light editing.
2022-04-19 01:55:37 -04:00
Calvin Rose e22936fbf8
Merge pull request #964 from uvtc/patch-9
tuple.c docstrings
2022-04-18 14:07:41 -05:00
Calvin Rose 04ace9fc16
Merge pull request #963 from uvtc/patch-8
table.c docstrings
2022-04-18 14:07:26 -05:00
Calvin Rose 8466b333fb
Merge pull request #965 from uvtc/patch-2
boot.janet docstrings
2022-04-18 14:07:16 -05:00
John Gabriele 96602612ba
boot.janet
Added some backticks around code in docstrings to distinguish them from prose.
2022-04-17 22:35:04 -04:00
John Gabriele 690b98bff9
tuple.c docstrings
Added some backticks around code in docstrings to distinguish them from prose.
2022-04-17 21:26:53 -04:00
John Gabriele 8329131bfe
table.c docstrings
Added some backticks around code in docstrings to distinguish them from prose.

Light editing to `table/raw-get`. Is my change there correct? (t --> the key)
2022-04-17 21:21:01 -04:00
Calvin Rose 9986aab326
Merge pull request #960 from uvtc/patch-5
math.c
2022-04-17 20:03:25 -05:00
Calvin Rose 0b105bc535
Merge pull request #959 from uvtc/patch-4
io.c docstrings
2022-04-17 20:03:11 -05:00
Calvin Rose 51ac9c9506
Merge pull request #961 from uvtc/patch-6
os.c docstrings
2022-04-17 20:02:56 -05:00
Calvin Rose 0310176696
Merge pull request #962 from uvtc/patch-7
parse.c docstrings
2022-04-17 20:02:26 -05:00
Calvin Rose 84a7a2bc3e
Merge pull request #958 from uvtc/patch-3
buffer.c docstrings
2022-04-17 20:01:57 -05:00
Calvin Rose 1e66a7e555
Merge pull request #957 from uvtc/patch-2
array.c docstrings
2022-04-17 20:01:31 -05:00
John Gabriele 2bffb9d682
parse.c docstrings
Added some backticks around code in docstrings to distinguish them from prose.
2022-04-17 20:53:36 -04:00
John Gabriele 811125a760
os.c docstrings
Some code backticks in docstrings where useful. Also some light editing of punctuation, etc.
2022-04-17 20:42:32 -04:00
John Gabriele 0dd91082a1
math.c
Fix typo, and backticks around one word.
2022-04-17 20:15:41 -04:00
John Gabriele c80587868e
io.c docstrings
Added some backticks around code in docstrings to distinguish them from prose.
2022-04-17 20:07:05 -04:00
John Gabriele 8c52dc86c7
buffer.c docstrings
Added backticks around code in docstrings to distinguish from prose.
2022-04-17 19:49:29 -04:00
John Gabriele be24592bc3
array.c docstrings
Added some backticks around code in docstrings to distinguish from prose.
2022-04-17 19:35:57 -04:00
Calvin Rose 0d1a5c621d
Merge pull request #955 from uvtc/patch-2
string.c docstrings
2022-04-17 12:33:52 -05:00
Calvin Rose 8a3eff3b65
Merge pull request #956 from uvtc/patch-3
Update .gitattributes
2022-04-17 12:33:37 -05:00
John Gabriele b1050b884d
Update .gitattributes
Github now supports Janet.
2022-04-17 12:17:54 -04:00
John Gabriele 181d883a1d
string.c docstrings
Add backticks around code values to distinguish them from prose.
2022-04-17 12:08:26 -04:00
Calvin Rose e01b65fd3d Fix some printing issues for docs. 2022-04-16 11:40:33 -05:00
Calvin Rose bbd74b5ae2
Merge pull request #952 from rick2600/master
#951 - fix unchecked count in cfun_buffer_new_filled
2022-04-15 16:43:11 -05:00
rick2600 d5a5c49357 #951 - fix unchecked count in cfun_buffer_new_filled 2022-04-14 16:20:04 -03:00
Calvin Rose a964b164a6 Merge branch 'master' of github.com:janet-lang/janet 2022-04-13 17:20:49 -05:00
Calvin Rose 1aac0489d7 Add a number of defs for used dynamic bindings. 2022-04-13 17:20:33 -05:00
Calvin Rose e474755887
Merge pull request #949 from sogaiu/syspath-defdyn
Use defdyn for syspath in boot.janet
2022-04-13 15:52:14 -05:00
sogaiu bf9a60f70d Use defdyn for syspath in boot.janet 2022-04-13 19:39:41 +09:00
Calvin Rose a2ba0913d3
Merge pull request #943 from cellularmitosis/make
Produce dylibs on macOS
2022-04-05 20:18:17 -05:00
Calvin Rose f74df41fff
Merge branch 'master' into make 2022-04-05 20:18:12 -05:00
Calvin Rose 2a950e4ce9 Fix patch release - (version info) 2022-04-01 21:59:01 -05:00
Calvin Rose f05e5f908e Update SONAME in Makefile. 2022-04-01 21:41:07 -05:00
Jason Pepas 43139b43b1 Produce dylibs on macOS 2022-03-31 00:17:59 -05:00
Calvin Rose 5811b47aad
Merge pull request #942 from Techcable/patch-1
Correct version 1.21.1 in meson.build
2022-03-30 18:13:55 -05:00
Techcable 54e3db4d8c
Correct version 1.21.1 in meson.build
This causes incorrect version meson compiles (including homebrew)
2022-03-29 23:13:09 -07:00
Calvin Rose 7491421c31 Release patch relase due to bad version bumping. 2022-03-27 11:21:24 -05:00
Calvin Rose 9d0da74347
Merge pull request #937 from cellularmitosis/clock1012
Mac clock shim not needed after 10.12
2022-03-23 13:02:03 -05:00
Jason Pepas e9870b293f Remove unneeded includes 2022-03-21 21:28:13 -05:00
Jason Pepas ab910d060b Move AvailabilityMacros.h import into util.c 2022-03-21 21:23:09 -05:00
Calvin Rose b60ef68ac6 Prepare for 1.21.0 Release. 2022-03-21 20:30:32 -05:00
Jason Pepas c9986936ed Mac clock shim not needed until 10.12 2022-03-21 20:20:20 -05:00
Calvin Rose d77be46644 Fix master - check last change with stackn 2022-03-21 19:41:06 -05:00
Calvin Rose 3715d7a184 Auto update copyright date. 2022-03-21 18:22:59 -05:00
Calvin Rose 1c96c7163a Address #926 - enter the event loop from janet_dobytes or
janet_dostring.
2022-03-21 18:06:14 -05:00
Calvin Rose 9f733b25db
Merge pull request #935 from jgarte/jgarte-patch-1
typo fix
2022-03-21 17:44:01 -05:00
Calvin Rose 1419a33b64
Merge pull request #936 from cellularmitosis/janetapple
Refactor __MACH__ to JANET_APPLE
2022-03-21 17:43:45 -05:00
Jason Pepas f270739f9f Refactor __MACH__ to JANET_APPLE 2022-03-17 01:20:55 -05:00
jgart e51a391286
typo fix 2022-03-12 17:54:44 -05:00
Calvin Rose c815185574
Merge pull request #931 from saikyun/norm-neg
normalize zero without branching
2022-03-07 09:18:22 -06:00
Calvin Rose 8045e29a52
Merge pull request #932 from ishehadeh/feature/int-to-bytes
Add int/to-bytes: Serialize int/[su]64 to a buffer
2022-03-06 13:11:08 -06:00
Ian Shehadeh bbb3e16fd1 int/to-bytes: return a buffer instead of a tuple
Buffers make more sense for this function because one of their primary
use cases is working with bytes.
The tuple implementation was an array of floats,  which is less
performant and ergonomic for common operations. (i.e: bit manipulation)

Buffers also have the advantage they are mutable, meaning the user
can write ints to an existing buffer.
2022-03-05 08:21:53 -05:00
Jona Ekenberg 3cd1657387 normalize zero without branching 2022-03-05 09:58:00 +01:00
Calvin Rose d7ea122cf7 Fix #928 - Fix hashing of negative 0. 2022-03-04 21:20:20 -06:00
Ian Shehadeh 6aea7c7f70 add int/to-bytes
int/to-bytes unpacks the bytes of a 64-bit integer into a tuple.
2022-03-04 08:48:54 -05:00
Calvin Rose 56ba1d9cd3 Formatting cleanup. 2022-02-24 18:07:22 -06:00
Calvin Rose 408b03ae0d
Merge pull request #924 from uvtc/patch-2
Update docs for `describe`
2022-02-24 18:04:51 -06:00
Calvin Rose d94fd746af
Merge pull request #923 from ishehadeh/feature/int64-unwrap
add `(int/to-number)`: convert int/s64 and int/u64 to a number
2022-02-24 18:03:48 -06:00
John Gabriele dbd1316d1e
Update docs for `describe`
closes #524
2022-02-23 00:36:24 -05:00
Ian Shehadeh 75845c0283 int/to-number: restrict input to JANET_INTMAX/MIN
Previously int/to-number would fail if the input was outside
the range of an int32.
Because Janet numbers are doubles,
they can safely store larger ints than an int32.
This commit updates int/to-number to restrict the
value to the range of integers a double can hold, instead of an int32.
2022-02-21 12:54:38 -05:00
Ian Shehadeh 88db9751d7 add int/to-number: converts s64 and u64 to numbers
(int/to-number value) converts an s64 or u64 to a number.
It restricts the value to the int32 range,
so that `int32?` will always suceeded when called on the result.
2022-02-20 16:16:52 -05:00
Calvin Rose 6f645c4cb7 Update CHANGELOG.md 2022-02-12 11:04:24 -06:00
Calvin Rose 4e31d85349 Address #804 - save and restore module cache when flychecking.
Calling flychecking cannot change the module cache.
2022-02-12 10:36:45 -06:00
Calvin Rose de542a81c0 Merge branch 'master' of github.com:janet-lang/janet 2022-02-11 20:38:10 -06:00
Calvin Rose 461576e7a2 Add `defdyn` macro to allow docs and checking for dyns.
Using keywords for the names of dynamic bindings emphasized their
dynamic nature and how they actually work, but is opaque when it comes
to documentation and error detection. Janet uses early binding for name
resolution by default in most places, dyns should be no different.

The `defdyn` macro allows one to create aliases for keywords that can
have docstrings, be imported and exported, etc. The aliases _must_
follow the usual lisp convention of earmuffs - this is not
restricting since the underlying keyword lookup mechanism is still
completely accessible to users.

Example:

(defdyn *my-dynamic-binding* "Sends the plumbus to the thingamizer when
 enabled")

The above creates a normal binding (as created with `def`) for
`*my-dynamic-binding*` that is bound to the keyword
`:my-dynamic-binding`.

There is an optional prefix for defdyns that can be used to avoid name
collisions - *defdyn-prefix*

Example:

(setdyn *defdyn-prefix* "mylib/")
(defdyn *my-dynamic-binding* "Plumbus thingamizer")
(pp *my-dynamic-binding*)

> :mylib/my-dynamic-binding
2022-02-11 20:37:52 -06:00
Calvin Rose 21bd62b1ce
Merge pull request #922 from paulsnar/paulsnar/ev-fix-timeout-pruning
ev: Fix timeout pruning logic
2022-02-11 20:07:51 -06:00
paulsnar 838cd1157c
ev: Fix timeout pruning logic 2022-02-11 09:25:23 +02:00
Calvin Rose 2f068b91d8 Mark a fiber as a root fiber during scheduling, not resumption.
This is more intuitive and avoids the possibilty of strange code
to resume or cancel a fiber after it was scheduled but before it was
entered for the first time.
2022-02-10 17:40:08 -06:00
Calvin Rose aba87bf1bd MSVC unwilling to concatenate strings across preprocessor directives. 2022-02-09 22:36:37 -06:00
Calvin Rose e64da8ede4 Update CHANGELOG.md 2022-02-09 22:31:27 -06:00
Calvin Rose a9f38dfce4 Address #920 - fiber cancellation can hang event loop.
The main issue was cancellation of fiber using `cancel` rather than
`ev/cancel` could cause issues with the event loop internal ref count.
Since this is almost certainly bad usage (and is not something I want to
encourage or support), we will warn against trying to resume or error
fibers that have already been suspended or scheduled on the event loop.
The distinction between "task" fibers and normal fibers is now kept by a
flag that is set when a fiber is resumed - if it is the outermost fiber
on the stack, it is considered a root fiber. All fibers scheduled with
ev/go or by the event loop are root fibers, and thus cannot be cancelled
or resumed with `cancel` or `resume` - instead, use `ev/cancel` or
`ev/go`.
2022-02-09 22:16:49 -06:00
Calvin Rose a097537a03 Fix #919 - strange quasiquote behavior.
Nested expression in the quasiquote were being compiled with the "hint"
flag passed to the expression compilation, essentially telling the
compiler to put intermediates into the final slot, possibly overwriting
other intermediate values. This fix removes that flags on any recursive
calls to quasiquote.
2022-02-09 20:31:10 -06:00
Calvin Rose 66e0b53cf6
Merge pull request #918 from paulsnar/paulsnar/shell-read-intr
Handle interrupts during `read` properly in mainclient
2022-02-04 22:39:22 -06:00
paulsnar 06f2e81dd5
shell: Handle EINTR on long reads
Many system I/O operations can fail due to being interrupted by a
signal. In the REPL's case, this poses a problem because in most cases
it's assumed that a read error is not recoverable and is equivalent to
EOF. This, however, is not the case for EINTR, in which case the I/O
should be tried again.

This commit fixes the most egregious violations of this, notably the
line getters, which would otherwise make the REPL exit on any signal,
even if the signal was caught and processed outside the REPL's purview.
2022-02-04 02:31:40 +02:00
Calvin Rose 40ae2e812f Prepare for 1.20.0 release. 2022-01-27 21:38:07 -06:00
Calvin Rose 06f613e40b Update signature of :missing-symbol hook.
don't take env table as explicit argument - it is already available
as the env table of the fiber.
2022-01-27 21:24:01 -06:00
Calvin Rose 61c8c1e8d2
Merge pull request #914 from pyrmont/feature.missing-symbols
Support looking up missing symbols during compilation
2022-01-24 18:16:53 -06:00
Michael Camilleri ee924ee310
Fix declaration error in switch statement 2022-01-24 11:16:35 +09:00
Michael Camilleri fad0ce3ced
Move missing symbol lookup to compiler 2022-01-24 11:08:33 +09:00
Michael Camilleri d396180939
Avoid panicking when calling :missing-symbol lookup function 2022-01-23 17:29:52 +09:00
Calvin Rose 0d089abe67 Update CHANGELOG.md 2022-01-22 19:38:08 -06:00
Michael Camilleri ed5c1dfc3c
Remove :modules dynamic binding 2022-01-23 01:54:58 +09:00
Calvin Rose 6b949a7375 Merge branch 'master' of github.com:janet-lang/janet 2022-01-21 17:16:29 -06:00
Calvin Rose 3028e2908f Avoid possible infinite loop in rest destructuring. 2022-01-21 17:16:06 -06:00
Calvin Rose 578803b01f
Merge pull request #915 from AlbertoGP/master
Add ppc64 to os/arch
2022-01-21 16:44:59 -06:00
Calvin Rose 46738825c0 Fix formating on master. 2022-01-21 16:44:11 -06:00
Calvin Rose 56357699cb
Merge pull request #913 from ishehadeh/feature/destructuring-rest
Support for `& rest` pattern in destructure and match
2022-01-21 16:39:35 -06:00
Alberto González Palomo fe8e718183 Add ppc64 to os/arch
Same as #431 (Add ppc to os/arch) but for the 64-bit version.
This is tested on a Power9 CPU in Little-Endian mode, on Linux.
2022-01-21 23:08:57 +01:00
Michael Camilleri 1eb34989d4
Support looking up missing symbols during compilation 2022-01-21 13:07:11 +09:00
Michael Camilleri 2f3b4c8bfb
Consolidate related tests 2022-01-21 13:02:56 +09:00
Ian Shehadeh 6412768000 Add match documentation for & rest pattern 2022-01-20 09:19:21 -05:00
Ian Shehadeh 82688b9a44 add checks to & _ pattern in match macro
This commit adds 2 checks for & rest pattern in the match macro:
- & is followed by exactly 1 item
- & is followed by a symbol
2022-01-20 09:16:02 -05:00
Ian Shehadeh 651e12cfe4 test nested '& destructure and empty rest array
This commit adds two new tests for destructure patterns with '&:
- Test that the rest array can be empty
- Test that & can be nested
2022-01-20 08:54:56 -05:00
Ian Shehadeh 4118d581af error if '& is followed by 2+ items in destructure
The current destructure pattern ends when '& is encountered.
This commit adds an error if it is followed by more than
a symbol to bind the array to.

Although its not critical since the extra items can be ignored,
they're a sign of some kind of mistake so its best to complain.
2022-01-20 08:52:37 -05:00
Ian Shehadeh 62608bec03 use janet_checktype over janet_type and ==
In destructure janet_type(_) == JANET_SYMBOL was used to check if a
value was a symbol.
This commit replaces that with the janet_checktype function,
because that function is used for the same purpose in other places.
2022-01-20 08:12:05 -05:00
Ian Shehadeh 71cffc973d add test: destructure with a nested tuple before &
This test ensures rest patterns work when
preceded by a more complicated pattern.
2022-01-19 14:01:28 -05:00
Ian Shehadeh a8e49d084b add checks for & _ destructuring pattern
This commit adds three checks to ensure & rest patterns are valid:
1. When checking for '& ensure the value is a symbol before unwrapping
2. Make sure '& is followed by a value
3. Make sure the value following '& is a symbol
2022-01-19 13:55:05 -05:00
Ian Shehadeh db631097b1 add support for & _ to match macro
This commit adds support for using & _ syntax to bind the remaining
values in an array in the match macro.

The commit also adds a few tests for the new syntax in suite0008
2022-01-19 13:29:34 -05:00
Ian Shehadeh 0d31674166 remove debug print in test suite0001 2022-01-19 12:49:02 -05:00
Ian Shehadeh cb5af974a4 POC "rest" pattern in destructuring
Add support for using [& rest] to match the remaining values
in an array or tuple when destructuring.

the rest pattern is implemented by pushing remaining values in the
rhs to the stack once & is found on the lhs.
Then tuple is called and the result is assigned
to the next symbol on the lhs.

This commit DOES NOT implement handling for malformed patterns.
2022-01-15 14:51:44 -05:00
Calvin Rose f2f421a0a2
Merge pull request #910 from pyrmont/bugfix.redefinable-macros
Fix redefinable macros
2022-01-14 07:45:54 -06:00
Michael Camilleri 413c46e2ee
Fix redefinable macros 2022-01-14 17:15:42 +09:00
Calvin Rose 3b412d51f0
Merge pull request #909 from ishehadeh/master
correct stack frame table keys in debug/stack doc
2022-01-09 12:01:05 -06:00
Ian Shehadeh 4931e2aee2 correct stack frame table keys in debug/stack doc
doc for debug/stack listed :column and :line as keys in the frame table.
But doframe actually sets :source-column and :source-line.
2022-01-08 16:25:43 -05:00
Calvin Rose ffadf673cf Merge branch 'master' of github.com:janet-lang/janet 2022-01-08 11:27:48 -06:00
Calvin Rose 5b5a7e5a24 Make top level vars reuse ref cell when redefined at the top level.
This improves the repl experience while not messing with existing code
very much, if at all.
2022-01-08 11:27:08 -06:00
Calvin Rose ab53208f47
Merge pull request #908 from ishehadeh/master
Windows: Fix `ev/read` hanging when called on stream from `os/open`
2022-01-08 11:26:48 -06:00
Calvin Rose 7c407705e8
Merge pull request #907 from pyrmont/bugfix.redefs-typo
Fix 'redefs' typo in test suite
2022-01-08 10:51:17 -06:00
Ian Shehadeh 60378ff941 windows: fix ev/read hang when called on fs stream
handles returned by CreateFileA and FILE_FLAG_OVERLAPPED
support reading from arbitrary offsets.
The offset is passed to ReadFile in through the OVERLAPPED structure.
Since state->overlapped is zeroed ev_machine_read
ReadFile would always read from the start of the file and never finish

This commit changes ev_machine_read to update the offset to
the number of bytes read before calling ReadFile.
2022-01-07 16:32:39 -05:00
Michael Camilleri 30a0c77d19
Fix 'redefs' typo in test suite 2022-01-07 13:28:22 +09:00
Calvin Rose 07ec89276b Disable file read test to help CI. 2022-01-06 20:52:21 -06:00
Calvin Rose a37dc1af9d Merge branch 'redefs-work'
- Change the global binding name from :redefs to :redef
- Simplify internal representation of "redefinable bindings"
- Store "redefinable bindings in :ref rather than :value inside the
  environment entries. This makes such bindings more like vars that
  can't be set rather than defs.
2022-01-06 20:45:20 -06:00
Calvin Rose 03458df140
Merge pull request #898 from pyrmont/feature.redefs
Support redefinable `def` and `defmacro` bindings using `:redef`
2022-01-06 20:44:18 -06:00
Calvin Rose 164eb9659e
Merge pull request #905 from ishehadeh/master
Fix typo in janet_epoll_sync_callback, add test for "async" read from normal fd
2022-01-06 20:43:48 -06:00
Calvin Rose 99cfbaa63b Tweaks on redef feature branch. 2022-01-06 20:38:15 -06:00
Ian Shehadeh 8d8a6534e3 add test for calling ev/read on normal fd
The test is almost identical to the os/open + :write test.
The only difference is the content is read back in with :read, not slurp
2022-01-06 19:35:30 -05:00
Ian Shehadeh 938c5013c9 fix typo in `janet_epoll_sync_callback`
JANET_ASYNC_LISTEN_WRITE was checked instead of JANET_ASYNC_EVENT_READ.
This caused ev/read to hang if it was called on a normal fd.
2022-01-06 19:33:34 -05:00
Michael Camilleri ea9d5ec793
Change metadata keyword back to :redef 2022-01-02 12:35:22 +09:00
Michael Camilleri ec65f038a8
Support :dynamic-defs dynamic binding 2021-12-29 16:39:00 +09:00
Calvin Rose 199ec36d40
Merge pull request #902 from sogaiu/tweak-match-doc
Tweak match docstring
2021-12-25 07:41:58 -06:00
sogaiu 1326ded048 Tweak match docstring 2021-12-25 16:56:10 +09:00
Michael Camilleri 8347439644
Support redefinable bindings 2021-12-18 13:05:16 +09:00
Calvin Rose cddc2a8280
Merge pull request #896 from pyrmont/bugfix.run-context-current-file
Only set :current-file in run-context if source is a path
2021-12-16 17:19:48 -06:00
Michael Camilleri 97a8938407
Ensure value is of specified type or panic 2021-12-15 12:17:35 +09:00
Michael Camilleri 939d1dcae9
Only set :current-file in run-context if source is a path 2021-12-13 12:06:58 +09:00
Calvin Rose 9d5cc5c11f Proper locking on select. 2021-12-09 18:59:59 -06:00
Calvin Rose d998f24d26 Merge branch 'master' of github.com:janet-lang/janet 2021-12-09 18:47:36 -06:00
Calvin Rose d543f8857b Fix #892 - Remove racy ref counts for channels
Rather than manual reference counting for suspended fibers, we
automate the process by incrementing "extra_listeners" every time
we suspend a fiber in the event loop, and decrement when that fiber
is resumed. In this manner, we keep track of the number of suspending
fibers in a simpler, more correct way.
2021-12-09 18:44:55 -06:00
Calvin Rose c48a942d22
Merge pull request #893 from pyrmont/docs.nested-loops
Clarify nested loop behaviour in loop macro
2021-12-09 14:09:59 -06:00
Calvin Rose e1602618c3
Merge pull request #894 from pepe/fix-numarray-example
Improve numarray example
2021-12-09 14:09:11 -06:00
Calvin Rose 36be240623
Merge pull request #895 from pepe/add-path-to-async-execute-example
Add search on PATH for async execute example
2021-12-09 14:08:53 -06:00
Josef Pospíšil 04e499c97f Add search on PATH for async execute example 2021-12-09 11:57:21 +01:00
Josef Pospíšil f586a8a9dc Add length to method and lib fn to numarray 2021-12-09 11:18:05 +01:00
Josef Pospíšil 5112ed77d6 Fix test import, and add sum as library fn too 2021-12-09 11:12:08 +01:00
Michael Camilleri bf29a54272
Clarify nested loop behaviour in loop macro 2021-12-09 10:41:56 +09:00
Calvin Rose 6d9286a202 Add some more changes to hashing to improve pointer hashing. 2021-12-07 08:36:08 -06:00
Calvin Rose 92fdd07ca3 Address #889 - Switch high and low bits of part of number hash (Knuth's multiplicative hash)
Also make sure we weren't throwing away 3 bits of entropy.
2021-12-07 08:24:04 -06:00
Calvin Rose 1c937ad960 Prepare for 1.19.2 release. Update CHANGELOG.md 2021-12-06 17:27:09 -06:00
Calvin Rose f9891a5c04 More improvements to hashing for #889 2021-12-06 17:23:00 -06:00
Calvin Rose e8ad311d84 Don't use janet_stacktrace anymore.
Behavior of janet_stacktrace_ext is more consistent.
2021-12-06 08:51:40 -06:00
Calvin Rose 545c09e202 Update hash mixing behavior - address #889
Try to have better behavior when mixing sub-hashes that are not uniform and
randomly distributed. Premultiply by a large prime before mixing to
"spread entropy" if it is concentrated in a certain subset of bits.
2021-12-05 16:34:26 -06:00
Calvin Rose 4dc281a05f Prepare for 1.19.1 release. 2021-12-04 13:34:41 -06:00
Calvin Rose 3a0af8caad Update changelog.md 2021-12-04 13:28:35 -06:00
Calvin Rose 8ff2fecb26 Update readme. 2021-12-04 13:25:02 -06:00
Calvin Rose 1855c6aed5 Remove appveyor. 2021-12-04 13:23:34 -06:00
Calvin Rose d4c6643311 Merge branch 'master' of github.com:janet-lang/janet 2021-12-04 13:03:33 -06:00
Calvin Rose e8c738002b Add extra "prefix" parameter to debug/stacktrace. 2021-12-04 13:03:05 -06:00
Calvin Rose 309c3aaeb8
Merge pull request #867 from pyrmont/feature.custom-out-functions
Support sending output to a function
2021-12-04 11:17:58 -06:00
Calvin Rose 1f8bcadb3b Update changelog.md 2021-12-04 11:11:57 -06:00
Calvin Rose 6f4af5fef8 Merge branch 'master' of github.com:janet-lang/janet 2021-12-04 10:28:16 -06:00
Calvin Rose 868cdb9f8b Fix channel packing bug. 2021-12-04 10:28:00 -06:00
Calvin Rose 2f76a429ef
Merge pull request #886 from Grazfather/patch-1
map: Fix indexing for 3+ data structures
2021-12-04 08:03:33 -06:00
Grazfather a69799aa42 Add tests for mapping different length sequences 2021-12-03 20:47:48 -05:00
Grazfather 139bef2142 map: Fix indexing for 3+ data structures 2021-12-03 16:15:43 -05:00
Calvin Rose 8ba142bcf4 Merge branch 'master' of github.com:janet-lang/janet 2021-11-30 14:19:10 -06:00
Calvin Rose c49e4966f6 Update to dev versions. 2021-11-30 14:19:03 -06:00
Calvin Rose 516fa4e49d
Merge pull request #883 from pyrmont/feature.netrepl-relative-imports
Update location of current file in run-context
2021-11-30 14:17:34 -06:00
Michael Camilleri 6bf9f89429
Update location of current file in run-context 2021-11-29 10:05:04 +09:00
Calvin Rose a0ddfcb109 Prepare for 1.19.0 release. 2021-11-27 10:00:36 -06:00
Calvin Rose 3df7921fdc Don't call wait twice when closing or gcing. 2021-11-27 09:05:43 -06:00
Calvin Rose 6172a9ca2d Merge branch 'master' of github.com:janet-lang/janet 2021-11-26 18:44:33 -06:00
Calvin Rose 4a40e57cf0 Fix leaking file descriptors to subprocess causing hangs. 2021-11-26 18:44:11 -06:00
Calvin Rose cdedda4ca1
Merge pull request #880 from pepe/gamma-fix
Fix math/gamma and add math/log-gamma
2021-11-26 12:34:54 -06:00
Josef Pospíšil e6babd84f7 Fix math/gamma and add math/log-gamma 2021-11-24 10:55:32 +01:00
Calvin Rose 868ec1a7e3 Add test case for missing struct proto 2021-11-23 23:17:24 -06:00
Calvin Rose e08394c870 Fix struct proto missing when making a struct with a nil value. 2021-11-23 23:16:06 -06:00
Calvin Rose a99500aebf Update suite0009 assert again. 2021-11-18 20:46:26 -06:00
Calvin Rose aa5095c23b Update assert message in suite0009 2021-11-18 20:39:29 -06:00
Calvin Rose 9e0f36e5a7 Fix unused variable warnings. 2021-11-18 20:35:41 -06:00
Calvin Rose d481d079ba Try bsd fix. 2021-11-18 20:30:06 -06:00
Calvin Rose bc9ec7ac4a Fix unitialized memory access in net/ module. 2021-11-18 20:10:10 -06:00
Calvin Rose 6f7e81067c Address #876 Don't allow scheduling a fiber once it has been canceled already.
We were effectively cancelling the cancellation.
2021-11-18 20:06:29 -06:00
Calvin Rose af946f398e Turn off raw mode in shell on ctrl-C. 2021-11-18 19:58:52 -06:00
Calvin Rose c7ca26e9c7 Merge branch 'master' of github.com:janet-lang/janet 2021-11-18 19:04:43 -06:00
Calvin Rose ef7129f45d Address #874 - Call waitpid on waiter thread with WNOWAIT.
This doesn't destory the pid until the original thread decides to
call waitpid again. Since the pid is exposed in the C API and now
in the Janet API, we don't want to destroy it until we are ready.
2021-11-18 19:03:08 -06:00
Calvin Rose a20bdd334a
Merge pull request #873 from andrewchambers/procsig
Use kill instead of raise for SIGINT.
2021-11-15 07:44:30 -06:00
Andrew Chambers 2ef49a92cc Use kill instead of raise for SIGINT.
Raise signals can only be handled by the current thread while
kill signals can be handled by background threads.
2021-11-15 20:38:23 +13:00
Calvin Rose 75f56b68c6
Merge pull request #872 from jgarte/jgarte-patch-aesthetics
Typo fix
2021-11-14 14:03:21 -06:00
jgart d34d319d89
Typo fix 2021-11-14 14:19:04 -05:00
Calvin Rose 6660c1da38 Don't truncate test output on failures. 2021-11-12 20:06:28 -06:00
Michael Camilleri 4e263b8c39
Support using functions with :out dynamic binding 2021-11-13 01:42:44 +09:00
Calvin Rose 3cb604df02
Merge pull request #870 from andrewchambers/exposepid
Expose process :pid on unix like platforms.
2021-11-12 08:20:39 -06:00
Calvin Rose af9dc7a69e
Merge pull request #869 from andrewchambers/typo2
Fix os/proc-kill doc typo.
2021-11-12 08:20:00 -06:00
Calvin Rose 1247e69c78
Merge pull request #868 from andrewchambers/sigint
Allow C code to block SIGINT.
2021-11-12 08:19:43 -06:00
Andrew Chambers aab0e4315d Expose process :pid on unix like platforms.
This at least means users can use something like jsys
or the kill command to signal processes when they want
to send unsupported signals (like SIGTERM).
2021-11-12 23:43:36 +13:00
Andrew Chambers 14f6517733 Fix os/proc-kill doc typo. 2021-11-12 23:29:13 +13:00
Andrew Chambers 5d75effb37 Allow C code to block SIGINT.
Previously the repl always exits on SIGINT, this change
means the repl will only exit on SIGINT if the SIGINT handler
causes it to exit.
2021-11-12 23:24:33 +13:00
Calvin Rose ab4f18954b
Merge pull request #866 from pyrmont/fix.example-urlloader
Fix URL loader example to use os/spawn
2021-11-11 14:55:24 -06:00
Michael Camilleri e1460c65e8
Fix URL loader example to use os/spawn 2021-11-11 17:33:25 +09:00
Calvin Rose 425a0fcf07 Add quoted literal support in the match macro. 2021-11-08 15:33:11 -06:00
Calvin Rose 7205ee5e0a Update test output. 2021-11-06 19:29:15 -05:00
Calvin Rose 72c5db8910 Update test suite to better distinguish functional errors with
localname/peername.
2021-11-06 19:19:49 -05:00
bakpakin 3067f4be3a Address #815 - gc mark issue in windows accept state machine.
We were casting a pointer to the wrong type, which caused all sorts of
wonderful chaos, but only on windows and only when the garbage collector
ran after setting up a server in a specific configuration. We were
casting a closure pointer to an abstract type during the mark phase,
        which resulted in memory corruption.
2021-11-06 17:50:54 -05:00
Calvin Rose 2aa1ccdd76 Update test helper to be even les noisy. 2021-11-06 11:20:09 -05:00
Calvin Rose 0284df503f Make test output less verbose 2021-11-06 11:01:21 -05:00
Calvin Rose 2833a983d8
Merge pull request #860 from sogaiu/short-fn-docstring-tweak
Tweak short-fn docstring
2021-11-04 19:39:55 -05:00
Calvin Rose 39c6be7cb7 Fix #861 - parser/produce caused state to be invalid for parser/state.
parser/produce was leaving a counter in the root state undecremented.
2021-11-04 19:38:37 -05:00
sogaiu fdc94c1353 Tweak short-fn docstring 2021-11-04 18:11:53 +09:00
Calvin Rose 9cc4e48124 Update changelog and allow evaluating streams with dofile. 2021-10-30 14:43:06 -05:00
Calvin Rose 34c7f15d6d Always return port in peername and localname 2021-10-30 10:56:40 -05:00
Calvin Rose 899a9b025e Merge branch 'struct-proto' 2021-10-30 09:31:22 -05:00
Calvin Rose deb4315383 Fix parse.c parser/state :args 2021-10-30 09:30:56 -05:00
Calvin Rose 9a06660fdb fix call to table/proto-flatten 2021-10-30 09:15:23 -05:00
Calvin Rose 5c35d24e13 Fix nil check issue. 2021-10-29 19:29:54 -05:00
Calvin Rose 03f99752a7 Merge branch 'master' into struct-proto 2021-10-29 16:42:34 -05:00
Calvin Rose fd37567c18 Docstring fix. 2021-10-29 11:13:07 -05:00
Calvin Rose 6e38bf1578 Use more inclusive check for the %j formatter for valid symbols.
We did not allow arbitrary utf8 to be printed with %j, even though the parser
allows. Thos changes uses the existing built in utf8 detectiotion to
exclude only unprintable symbols from the docstring.
2021-10-29 11:08:53 -05:00
Calvin Rose 8b2d278840 Add min-of and max-of. 2021-10-26 17:46:24 -05:00
Calvin Rose 06aa0a124d Add `math/gcd` and `math/lcm` to the core. 2021-10-24 11:43:07 -05:00
Calvin Rose eb4595158d Allow compiling tables as peg grammars. 2021-10-23 09:59:36 -05:00
Calvin Rose 32103441f1
Merge pull request #850 from pyrmont/bugfix.anonymous-union
Use named union in JanetGCObject
2021-10-22 07:56:38 -05:00
Michael Camilleri 7ed0aa6630
Use named union in JanetGCObject 2021-10-22 09:52:57 +09:00
Calvin Rose f690229f31
Merge pull request #848 from pyrmont/bugfix.uname-switches
Fix error for uname switch -o on macOS
2021-10-21 18:17:41 -05:00
Michael Camilleri f3bab72a86
Add comment to explain Linux check in Makefile 2021-10-21 14:23:23 +09:00
Michael Camilleri 2bd63c2d27
Fix error for uname switch -o on macOS 2021-10-21 14:13:51 +09:00
Calvin Rose 545d9e85e9 Update CHANGELOG.md 2021-10-20 19:57:02 -05:00
Calvin Rose 21a4ab4ec7 Hang forever instead of exit early on channel deadlock.
While not technically needed, the behavior is more intuitive and will
prevent people from writing bad scripts.
2021-10-20 19:53:29 -05:00
Calvin Rose 66fbbeb5ec Why is the copyright gone... 2021-10-20 18:05:32 -05:00
Calvin Rose 55879c7b6d Fix checked for fiber being dead. 2021-10-19 09:03:24 -05:00
Calvin Rose 66c4e5a5e2 Prepare for patch release. 2021-10-16 15:05:48 -05:00
Calvin Rose 884139e246
Merge pull request #843 from jgarte/jgarte-patch-typo
Fix typo in docstring
2021-10-16 12:51:45 -05:00
Calvin Rose c3d7b1541e
Merge branch 'master' into jgarte-patch-typo 2021-10-16 12:51:38 -05:00
Calvin Rose 51ada4d70b
Merge pull request #840 from bradms/android-termux
Support Android (termux)
2021-10-16 12:50:24 -05:00
jgart e3a5d52c5e
Fix typo in docstring 2021-10-16 11:48:59 -04:00
Brad Svercl 559fd70737 Add android-spawn to meson.build if found 2021-10-15 21:39:03 -05:00
Brad Svercl e0dba85cbb Support Android (termux) 2021-10-14 21:18:35 -05:00
Calvin Rose 74c9cf03d0 Fix -r switch in repl 2021-10-14 17:25:12 -05:00
Calvin Rose 0774e79e4f Pass non-blocking pipes to subprocesses on non-windows platform. 2021-10-14 13:57:51 -05:00
Calvin Rose a3ec37741a
Merge pull request #835 from MorganPeterson/update-string-docs
Updated string/bytes docs to reflect return value as tuple
2021-10-12 00:22:50 -05:00
MorganPeterson 9bf5cd83c3 updated string/bytes docs to reflect return value as tuple 2021-10-11 13:45:31 -04:00
Calvin Rose f0da793f99 Prepare for 1.18.0 release 2021-10-10 09:27:31 -05:00
Calvin Rose 684f3ac172 Add optional base to scan-number. 2021-10-10 09:07:56 -05:00
Calvin Rose 3e5bd460a5 Add line/col info to parse error in janet_[dobytes, dostring] 2021-10-08 09:25:00 -05:00
Calvin Rose 3b1d787fbe Address #829 - Set state->event inside linked list traversal for epoll. 2021-10-08 08:35:47 -05:00
Calvin Rose 980f55ff69
Merge pull request #828 from sogaiu/add-argument-to-janet-panicf-call
Add argument to some janet_panicf calls
2021-10-08 08:23:55 -05:00
sogaiu 52ed68bfeb Add argument to janet_panicf call (2) 2021-10-07 20:58:50 +09:00
sogaiu be0d4c28e4 Add argument to janet_panicf call 2021-10-07 16:38:40 +09:00
Calvin Rose 79807bf2ab
Merge pull request #827 from sogaiu/tweak-format-strings
Tweak format strings
2021-10-06 17:48:53 -05:00
Calvin Rose e48ca1a03f
Merge pull request #826 from rick2600/fix-uaf-cfun_array_concat
fix issue #825
2021-10-06 17:48:27 -05:00
sogaiu eae18ce973 Tweak format strings 2021-10-06 20:34:33 +09:00
rick2600 591344ca9d fix issue #825 2021-10-05 01:45:59 -03:00
Calvin Rose fbe067823e
Merge pull request #824 from GrayJack/rnd-double-capi
Expose `janet_rng_double` to the C API
2021-10-04 13:54:10 -05:00
GrayJack ffece911e6
Expose `janet_rng_double` to the C API 2021-10-03 00:52:34 -03:00
Calvin Rose 186afa9651
Merge pull request #823 from llmII/fix-kqueue-hang
Fix #822 - kqueue hang in suite 9.
2021-09-30 10:50:04 -05:00
llmII 6b3037106a
Fix #822 - kqueue hang in suite 9.
Priorly we only checked exactly one state when an event was received.
This was incorrect. A state may have a next state, an action to take
after the first in the list of states has been taken. This change
acknowledges that and makes the code work with the state list vs just
the head of the list.
2021-09-30 06:56:09 -05:00
Calvin Rose 1bf22288ee
Merge pull request #821 from llmII/fix-kqueue
Fix #819 timeouts under kqueue on FreeBSD broken
2021-09-29 15:51:46 -05:00
llmII 3cec470f25
Change the way timeouts work in kqueue.
Don't use a timer filter, just set the timeout on each call to kevent.
Should hopefully work around the 1ms minimum on NetBSD and be possibly
more performant.
2021-09-29 15:19:30 -05:00
llmII e1ec0d13ae
Fixing kqueue under the BSDs.
FreeBSD is the only BSD supporting ABSTIME timers, whereas the rest
demand intervals. Janet operates on timestamps, which are absolute
times, as per ABSTIME. The idea was to use that under FreeBSD but not
the other BSDs. This commit changes that since ABSTIME breaks when the
timeout supplied is for a time prior to whatever the time is
now (invalid argument). We now utilize the same logic we use on the
other BSDs with FreeBSD to effect interval timeouts since intervals are
absolutely sometime beyond now, be it now and less than a millisecond,
or more than a millisecond. This will hopefully unbreak BSD builds when
running the test suite.
2021-09-28 17:40:38 -05:00
bakpakin 924fe97fc3 Address #820 - ev/cancel to work on already scheduled fibers. 2021-09-28 15:42:16 -05:00
bakpakin 504411eade Update suite 009 to do read and write in parallel. 2021-09-28 12:05:28 -05:00
Calvin Rose 038ca1b9ca Update README.md 2021-09-27 21:20:06 -05:00
Calvin Rose 544b192f8c Fix bad docstring change. 2021-09-25 14:32:23 -05:00
Calvin Rose 7748ccdb8e Fix network byte order port. 2021-09-25 14:31:19 -05:00
Calvin Rose 64e29c6fce More simplification and removal of macros. 2021-09-25 13:53:27 -05:00
Calvin Rose acdf097998 Refactor of peername and localname to be much more direct.
Also remove a lot of overly general code from cqueues. Janet has more
opinionated error handling so we can avoid a lot error propagation code.
2021-09-25 13:38:36 -05:00
Calvin Rose ba3107c1fa Merge branch 'master' of github.com:janet-lang/janet 2021-09-21 18:03:25 -05:00
Calvin Rose 9985f787eb Add custom base option to number peg combinator.
Allows parsing custom bases without needed Janet specific prefixes.
2021-09-21 18:02:42 -05:00
Calvin Rose d6f41bcf98
Merge pull request #811 from sogaiu/use-deprecation-mechanism-for-file-popen
Apply deprecation machinery to file/popen
2021-09-21 15:16:20 -05:00
Calvin Rose 50bced49ad
Merge branch 'master' into use-deprecation-mechanism-for-file-popen 2021-09-21 15:15:36 -05:00
Calvin Rose 4fd7470bbf Remove accidental limit on max read size. 2021-09-21 09:55:40 -05:00
Calvin Rose 033c6f1fdb Add -i flag to run .jimage files as scripts. 2021-09-19 19:47:57 -05:00
Calvin Rose 6c58347916 Remove thread module.
Instead, use the more general and non-blocing `ev/` module.
2021-09-19 14:19:32 -05:00
Calvin Rose cccbdc164c Add (number combinator to peg).
This allows using Janet's number parser without creating
intermediate strings.
2021-09-19 13:02:16 -05:00
Calvin Rose cea14a6869 Fix typo in changelog. 2021-09-19 00:16:08 -05:00
Calvin Rose 9b4b24edf7 Prepare for 1.17.2 release. 2021-09-18 13:42:26 -05:00
Calvin Rose 8b10a5fb7c Format and update CHANGELOG.md 2021-09-18 13:40:32 -05:00
Calvin Rose b0d0d9cad2 Address #809 - treat first docstring line different from others.
Only do this if the docstring starts with an open parentheses.
2021-09-18 12:41:11 -05:00
sogaiu d5c8eb048a Apply deprecation machinery to file/popen 2021-09-18 17:08:56 +09:00
Calvin Rose 9abee3f29a Add semi-colon. 2021-09-17 19:20:59 -05:00
Calvin Rose bf9b6b1301 Avoid including windows.h in janet.h for JanetOSMutex. 2021-09-17 16:59:50 -05:00
Calvin Rose 8cd57025a0 Add makefile var to fix jpm to a tag/branch 2021-09-17 16:38:11 -05:00
Calvin Rose faf60b6b1f Pass DESTDIR directly to jpm bootstrap script. 2021-09-16 18:36:29 -05:00
Calvin Rose da2c1be49c Fix #801 threaded abstract cyclic references in marshalling.
We forgot to mark threaded abstract types as "seen" when marshalling so
we would mistakenly marshal them twice. This messed up unmarshalling.
2021-09-14 21:12:02 -05:00
Calvin Rose 92c02449f4
Merge pull request #800 from marler8997/fixUbInGC
add NULL check in gc.c to avoid UB
2021-09-14 16:04:12 -05:00
Jonathan Marler e381622a9a add NULL check in gc.c to avoid UB
After the UB was fixed in value.c, I tried running the build again and encoutered another instance of UB in gc.c.  With this fixed I can now build janet with ubsan enabled, meaning there's no more UB encountered in janet_boot during the build.
2021-09-11 19:50:52 -06:00
bakpakin b799223ebc Merge branch 'master' of github.com:janet-lang/janet 2021-09-11 10:34:22 -05:00
bakpakin 40ef224a95 Update test code. 2021-09-11 10:34:08 -05:00
Calvin Rose a4c20b6e1c
Merge pull request #797 from sogaiu/math-nan-doc-tweak
Tweak math/nan docstring
2021-09-11 09:13:38 -05:00
sogaiu e6ee867f72 Tweak math/nan docstring 2021-09-11 16:54:35 +09:00
bakpakin 468a31f515 Address #795 - add NULL check to avoid UB 2021-09-09 07:20:26 -05:00
bakpakin 4d746794cc Merge branch 'bindport' 2021-09-07 22:45:22 -05:00
bakpakin 02d2a66ef2 Merge branch 'master' of github.com:janet-lang/janet 2021-09-07 22:44:59 -05:00
Calvin Rose 4638baf545
Merge pull request #790 from llmII/feature-getsockname-getpeername
Work in progress - more socket functions
2021-09-07 22:44:40 -05:00
bakpakin 2be23d3768 Fix meson build. 2021-09-07 22:11:45 -05:00
bakpakin b39b1746ba Support bindport. 2021-09-07 21:59:17 -05:00
bakpakin 24f97510b0 Fix incorrect code that created socket twice. 2021-09-07 20:51:33 -05:00
llmII 325d5399fa
Code cleanup and attribution set.
All that is left is to test unix sockets.
2021-09-07 20:00:00 -05:00
Calvin Rose d8f6fbf594
Merge pull request #789 from llmII/feature-bind-connect
Add bind option to net/connect
2021-09-07 18:47:17 -05:00
llmII 21b3e4052c
Don't print stuff in tests, CI looks wacky 2021-09-07 17:21:10 -05:00
llmII bf2928805e
Had an extra plen definition, removed. 2021-09-07 17:03:34 -05:00
llmII 7d2bf334c8
Fix incorrect error when argv[3] is null
The `janet_get_addrinfo` function retained code that was meant for
compliance with 3 separate function signatures under a single function
name. Changing things to be a single function signature was broken until
the code pertaining to the aforementioned was stripped out.
2021-09-07 16:11:37 -05:00
llmII 7446802a70
Quit trying to make it 3 different functions
Prior commits was an attempt to make this one function adhere to 3
different function signatures! This puts an end to that and makes it
where it's a single function signature and if one wants to use the 4th
argument they'll need to explicitly set the 3rd argument (to nil for
default).
2021-09-07 14:56:13 -05:00
llmII 077bf5ebae
Create test case for localname/peername 2021-09-07 07:12:43 -05:00
llmII c9bef39f96
Make net/connect special
Keeps net/listen from being affected by changes necessary to make bind
on connect work (while keeping from breaking the API).
2021-09-07 05:40:48 -05:00
llmII 3740eadb7d
Seeing if this fixes the last warnings for Windows 2021-09-06 19:57:56 -05:00
llmII e29fa66a74
More Windows fixes 2021-09-06 19:42:45 -05:00
llmII ca5406c8e4
More windows fixes
MSVC's output via appveyor is a little lacking in indication of all
issues so I'm hitting them as I can find them.
2021-09-06 19:31:16 -05:00
llmII 7217caacd1
Attempting some more windows related fixes. 2021-09-06 19:26:33 -05:00
Calvin Rose 8081082251
Merge pull request #785 from llmII/feature-kqueue
Add kqueue support to Janet
2021-09-06 18:42:05 -05:00
llmII 1597ca0de5
Cleanup code a bit
Inconsistent indentation and such fixed, superfluous newlines removed,
documentation of new functions.
2021-09-06 18:32:23 -05:00
llmII 8c938ceff9
Fix for Windows (possibly)
Windows does not have <arpa/inet.h> so only include it when not Windows.
2021-09-06 17:48:17 -05:00
llmII 65a6945ea5
Finalize peername and localname
Both now do the right thing and give back all information (host and
port) when possible as a tuple of (host port).
2021-09-06 17:35:49 -05:00
llmII 02640812af
Add getsockname (net/localname) 2021-09-06 17:01:09 -05:00
llmII ba761d5c35
Work in progress - more socket functions
When this is complete we'll have getpeername, getsockname and possibly
getpeerid in the net/* API.
2021-09-06 16:15:01 -05:00
llmII 48a3b1f07f
Enable kqueue on MacOS
Make sure JANET_EV_KQUEUE is defined when JANET_APPLE is defined unless
disabled by configuration.
2021-09-06 16:01:06 -05:00
llmII 4370cb77e7
Update documentation.
Documenting the new bindhost parameter to net/connect.
2021-09-06 10:54:11 -05:00
llmII 470e8f6fc7
Reused address info struct incorrectly
Wrongly assumed that `ai` was done being used before binding, it's not,
so create a separate address info for binding...
2021-09-06 10:44:23 -05:00
llmII b270d88427
More off by one error fixes 2021-09-06 10:12:36 -05:00
llmII 66ce247129
Fixing off by one indexing errors... 2021-09-06 10:01:16 -05:00
llmII 6ad016c587
Check type when getting socket type
janet_get_sockettype expects a keyword but we're making it optional that
the call to the functions that use it with arity >=3 will be guaranteed
to have it as a keyword value! If it's not a keyword then it's the same
as NULL.
2021-09-06 09:53:53 -05:00
llmII 532dac1b95
Check type instead of value
Primarily because trying to check the value results in a panic when the
value is not the type of value requested from the API. Also probably
cheaper and the previous idea of just getting the value then comparing
was pretty stupid (needed a string comparison... and was going to do
pointer comparison).
2021-09-06 09:48:29 -05:00
llmII 2a4bcc262f
Don't bind when address info doesn't exist
Simple logic issue, something overlooked.
2021-09-06 09:06:40 -05:00
llmII 1ce2361daf
Better error message in connect
Quick thing to help check when failing tests.
2021-09-06 09:02:56 -05:00
llmII 6e8584e8e0
Add bind option to net/connect
This will allow us to set the address we use for outgoing connections.

Builds, haven't checked it passes current tests, haven't checked it
actually works either.
2021-09-06 08:54:24 -05:00
llmII 121aa91139
Fixes for NetBSD (again)
Minimum interval for a timer must be 1 or more (or we get EINVAL) and
Janet fails tests and halts events that the programmer may still be
interested in.
2021-09-05 21:48:53 -05:00
llmII bbc07c72d3
More NetBSD fixes
A comptime known value of 0 for data in EV_SET with EVFILT_TIMER causes
a complete compilation failure (fails to link). This fixes it by making
it a 1 instead of a 0 for amount of milliseconds in the interval to wait
under NetBSD.
2021-09-05 21:17:41 -05:00
llmII 43b48fdbea
More fixes for NetBSD
Kills compiler warnings with regards to implicit conversion of intptr_t
to void*
2021-09-05 21:01:24 -05:00
llmII 604f97aba1
Fixes for BSD where BSD != FreeBSD
NetBSD and OpenBSD lack NOTE_ABSTIME and NOTE_MSECONDS, so we define
those and create a macro that we use for all timeout values in EV_TIMER
events that will on all BSD excepting FreeBSD change an absolute time
into an interval.
2021-09-05 20:48:42 -05:00
Calvin Rose dc980081cd Fix #783 - change docstring for x86-64 to x64. 2021-09-05 12:32:33 -05:00
llmII 981f03fef3
Remove comments regarding NetBSD breakage
Since those no longer should apply, don't keep them around.
2021-09-05 10:45:45 -05:00
llmII d40133dc72
NetBSD support
Checking throught NetBSD's man pages, excepting for NetBSD-current,
NetBSD uses `intptr_t` as the type for `.udata`. This change allows for
`.udata` to match whatever type (by cast) the underlying system uses.
2021-09-05 07:30:22 -05:00
llmII c9fa586fce
Code style fixes (pt 2).
Missed some.
2021-09-04 09:37:07 -05:00
llmII b847a7d90b
Code style fixes.
Pretty obvious I thought control statements were glued to their opening
parenthesis at first and then I realized not and voila, a bundle of
mixed style. Hopefully this fixes all of it.
2021-09-04 09:34:47 -05:00
llmII 8b67108dc8
Complete kqueue feature
From this point things should be bug fixes or code formatting most
likely.

Updated commentary (removed superfluous comments, and commented out
code). Refined commentary where it seemed important and may help whoever
comes behind me keep from making bad assumptions similar to the ones I
made.

All tests ran with `gmake test` now pass. `valgrind` with FreeBSD does
not support forking so `gmake valtest` fails once child processes are
started. Determined not an issue, can't fix valgrind.
2021-09-04 08:23:03 -05:00
llmII b559f9625a
Timeout is an absolute time, not an interval.
Fixes the wrong assumption, passing all tests at that point.
2021-09-04 08:02:50 -05:00
llmII 1736c9b0f8
Handle null state, don't read/write on error
Need to guard against errors when reading/writing probably, if there is
an error, forgo those events.

Guard against null state (and the byproduct, a segfault), check if the
state is null before utilizing it.
2021-09-03 23:22:07 -05:00
llmII 4fb2d8d318
Logical error regarding length fixed. 2021-09-03 22:41:59 -05:00
llmII 95891eb0a5
Fix incorrect use of EV_SET on pipes (part 2)
Forgot that we use nearly the same routine for adding and deletion...
can't go around deleting things we haven't put into the changeset!
2021-09-03 22:33:28 -05:00
llmII c133443eb7
Fix incorrect use of EV_SET on pipes.
It would seem adding a read and a write event filter on a pipe which is
unidirectional might just be a bad idea.
2021-09-03 19:44:27 -05:00
llmII 8f0641f36c
Disabling superfluous code
The code in question may be checking things in an erroneous manner?
2021-09-03 17:18:40 -05:00
llmII f48dbde736
Better exit (error?) message
The prior calls to exit(-1) were wrong anyway and they may at this point
be hindering figuring out what's going on in suite 9.
2021-09-03 17:13:54 -05:00
llmII f2e4c1ae9a
Forgot a semicolon... 2021-09-03 16:31:20 -05:00
llmII a4aef38cc0
More typo and syntax fixes. 2021-09-03 16:29:39 -05:00
llmII b445ecde51
Add kqueue option to meson, janetconf, fix typoes 2021-09-03 16:23:15 -05:00
llmII a209a01284
Add kqueue support to Janet
Note that this is a work in progress and simply a first attempt at
getting some code into place before being able to test it. This code
follows of sorts both the poll and epoll sections of the codebase hoping
to achieve the exact same.
2021-09-03 14:33:47 -05:00
Calvin Rose 7037532943 Errored threads always emit stacktrace or supervisor event.
That way, it is much harder to swallow errors. Error swallowing behavior
would have to be done explicitly by wrapping fibers with `protect` or
`try`.
2021-09-01 21:05:05 -05:00
Calvin Rose bb405ee1aa Address #778
Relax check that number of closure environments in a function matches
that of the def.

The def could be partially constructed, and so there may be a false
negative. The runtime will check that this is consistent, and the
garbage collector should handle when this constraint is not kept.
2021-08-31 22:58:44 -05:00
Calvin Rose ef23356309 Threaded supervisors return fiber->last_value instead
of the fiber itself.
2021-08-31 14:50:27 -05:00
Calvin Rose 1613e2593c Update CHANGELOG.md 2021-08-30 22:24:34 -05:00
Calvin Rose 5464a7a379 Allow passing a function to directly to ev/go.
Makes ev/call less useful but ev/go more useful. No need
to construct as many identical intermediate fibers.
2021-08-30 22:22:22 -05:00
Calvin Rose bb1331e449 Update changelog. 2021-08-30 22:06:28 -05:00
Calvin Rose acbebc5631 Allow passing function to ev/thread.
Convenient when there is no need to create an entire fiber.
2021-08-30 22:04:15 -05:00
Calvin Rose e1c4fc29de Prepare for 1.17.1 release. 2021-08-29 11:29:41 -05:00
Calvin Rose b903433284 Merge branch 'master' of github.com:janet-lang/janet 2021-08-29 11:15:43 -05:00
Calvin Rose 31a7fdc7b6 Add Make task to more easily install jpm. 2021-08-29 11:15:15 -05:00
Calvin Rose 9909adb665 Remove JANER_HEADERPATH from boot process.
That is a jpm thing.
2021-08-29 10:43:58 -05:00
Calvin Rose 26f8ba48ee
Merge pull request #775 from pepe/ev-docs
Fix typos in ev/go ev/select
2021-08-28 16:20:25 -05:00
Josef Pospíšil 29ea408980 Fix spawn-thread doc about its return 2021-08-28 15:39:49 +02:00
Josef Pospíšil 0bb7ca7441 Fix typos in ev/go ev/select 2021-08-28 15:35:55 +02:00
Calvin Rose a992644c62 Merge branch 'master' of github.com:janet-lang/janet 2021-08-27 11:52:19 -05:00
Calvin Rose 1c15926e6f Fix #773 - fix docstring. 2021-08-27 11:52:03 -05:00
Calvin Rose c921315b3e
Merge pull request #774 from sogaiu/tweak-fiber-last-value-docstring
Tweak fiber/last-value docstring
2021-08-27 11:51:13 -05:00
Calvin Rose ab740f92db Fix ev thread swallowing error in some case. 2021-08-27 11:46:42 -05:00
sogaiu 1d7390fa7c Tweak fiber/last-value docstring 2021-08-27 17:29:20 +09:00
Calvin Rose 0ab96b8e47 Fix #771 2021-08-26 22:23:21 -05:00
Calvin Rose 6f6edd37ef
Merge pull request #772 from pyrmont/feature.gh-test
Add GitHub Workflow to test
2021-08-26 22:20:48 -05:00
Michael Camilleri f4282de068
Add GitHub Workflow to test 2021-08-25 10:49:56 +09:00
Calvin Rose 85c85c07b7
Merge pull request #770 from pyrmont/feature.gh-release
Use GitHub Workflow to create release (including building for Linux and macOS)
2021-08-24 08:36:57 -05:00
Michael Camilleri 7abcb1579a
Set JANET_DIST_DIR before making artifact 2021-08-23 15:47:25 +09:00
Michael Camilleri 7ce733cc16
Change lowercase step 2021-08-23 15:24:25 +09:00
Michael Camilleri 41a3c5f846
Add GitHub Workflow to draft release 2021-08-23 14:55:59 +09:00
bakpakin 7734e77dfc Readd the janet_register function. 2021-08-22 10:38:15 -05:00
Calvin Rose 257c8b65c2 Fix destruction order. 2021-08-21 13:30:09 -05:00
Calvin Rose 846c9e5e12 Fix #759 - Add -E flag for one-liners.
Use the `short-fn` DSL here for argument passing.
2021-08-21 13:16:41 -05:00
Calvin Rose 685d2b460c Address #765. Make `assert` into a macro. 2021-08-21 12:27:58 -05:00
Calvin Rose bd71e1cd02 Silence clang warning about comparing function pointers.
The comparison is used to create a set of function pointers.
2021-08-21 12:10:19 -05:00
Calvin Rose 43a5e12449 Merge branch 'master' of github.com:janet-lang/janet 2021-08-21 12:07:39 -05:00
Calvin Rose ca97510a52 Prepare for 1.17.0 release. 2021-08-21 12:07:28 -05:00
Calvin Rose 50b753cb44
Merge pull request #768 from sogaiu/remove-threads-example
Remove threads example
2021-08-21 11:15:54 -05:00
sogaiu 5ca6704c4d Remove threads example 2021-08-21 14:52:51 +09:00
Calvin Rose 49142fa385 Update for windows compiler warning. 2021-08-20 19:48:48 -05:00
Calvin Rose d631d29cb4 Fix typo in header. 2021-08-20 18:53:22 -05:00
Calvin Rose 01b7891347 Windows header issues. 2021-08-20 18:49:13 -05:00
Calvin Rose c786a4cbeb Expose JanetOSMutex to make abstract types easier to write. 2021-08-20 17:57:23 -05:00
Calvin Rose 1920ecd668 Decrement thread channel pointer during cleanup without adding to heap. 2021-08-20 16:41:19 -05:00
Calvin Rose c8827424e7 Fix memory leak and use after free
Use after free was caused by missing janet_gcroot call when
setting up thread.
2021-08-19 21:51:53 -05:00
Calvin Rose cc066dd6a1 Add basic runtime support for threaded abstracts.
A threaded abstract is an abstract type that can be freely shared
between threads. While no synchronization is provided, refcounting
and transport between threads is. This will let implementers more easily
exploit OS-level parallelism in C library code. The caveat with these
types is that they need to be careful in how they interact with objects
on other heaps.
2021-08-19 21:16:20 -05:00
Calvin Rose eb0b37f729 Initial threaded abstract types. 2021-08-19 20:56:48 -05:00
Calvin Rose e552757edc Fix threaded supervisor channels - Fix #766
Some pointer casting with abstract types was incorrect, resulting
in strange behavior when trying to use supervisor channels that were
threaded. This fix also adds the ability to supply a supervisor channel
directly when creating a thread.
2021-08-16 21:14:06 -05:00
Calvin Rose 87b8dffe23 Deprecate the thread module. 2021-08-15 17:36:47 -05:00
Calvin Rose 81b5904188 Add marshal/unmarshal to items pushed to threaded channel. 2021-08-15 16:12:40 -05:00
Calvin Rose 894a3b2fe2 Fix memory leak with threaded channels. 2021-08-15 15:33:26 -05:00
Calvin Rose b75b3e3984 Working example for threaded channels.
Still no marshalling more complex values.
2021-08-15 15:25:07 -05:00
Calvin Rose dea4906144 Merge branch 'master' of github.com:janet-lang/janet 2021-08-15 13:15:41 -05:00
Calvin Rose 97e5117a3f Fix some issues and improve channel closing.
Still not fully working, seems to be deadlock/channel issue when
sending events between threads.
2021-08-15 13:14:33 -05:00
Calvin Rose 037215f7c4 Initial working draft of threaded channels.
Introduces close semtantics to channels as well, but otherwise
threaded channels behave much like non-threaded channels. They have
different marshalling behavior though, and can only send values over by
packing and unpacking them. For now, this means only primitive values
although this will be expanded.

Also missing some implementation for closing threaded channels, and a
whole lot of testing. Achtung!, Caveat emptor, here be dragons and bugs.
2021-08-15 11:48:13 -05:00
Calvin Rose 0277187fde
Merge pull request #763 from sogaiu/rng-uniform-doc-tweak
Tweak docstring for math/rng-uniform
2021-08-14 19:10:45 -05:00
sogaiu c80a3c1401 Fix error 2021-08-15 06:57:46 +09:00
Calvin Rose 5614f85ea1
Merge pull request #762 from andrewchambers/race
Fix init race for environ lock.
2021-08-14 10:27:32 -05:00
sogaiu 1a3c8692e6 Tweak docstring for math/rng-uniform 2021-08-10 20:09:24 +09:00
Andrew Chambers f2e8691ad5 Fix init race for environ lock. 2021-08-09 14:47:41 +12:00
Calvin Rose c94d7574bc
Merge pull request #754 from harryvederci/patch-1
Improve docstring for the invert function.
2021-08-08 12:51:24 -05:00
Calvin Rose a38cb5df18
Merge pull request #757 from subsetpark/document-match
Add documentation of @ pattern in match
2021-08-08 12:51:00 -05:00
Zach Smith 5407868620 Add documentation of @ pattern in match 2021-08-07 15:09:37 -04:00
Harry Prins 7edf77561b
Refer to argument. Change past tense to present. 2021-08-07 18:03:10 +02:00
Calvin Rose a78cbd91da Address #753 - fix gensym regression. 2021-08-06 16:25:53 -05:00
Calvin Rose bb5c3773f1 Fix fiber aware combinators to use general iteration instead of fiber
specifics.
2021-08-06 16:17:47 -05:00
Calvin Rose 2e641a266d
Merge pull request #752 from sogaiu/get-in-tweak
Tweak get-in behavior
2021-08-06 15:14:33 -05:00
Calvin Rose 3a787afec6
Merge pull request #756 from subsetpark/take-streams
Make take/take-while/take-until fiber-aware
2021-08-06 15:13:35 -05:00
Zach Smith 34019222c2 Make take/take-while/take-until fiber-aware 2021-08-06 15:40:29 -04:00
Harry Prins 5f3378213b
Improve docstring for the invert function. 2021-08-06 18:33:49 +02:00
sogaiu 547fda6a40 Add tests 2021-08-06 10:05:34 +09:00
sogaiu 2080ac3bda Tweak get-in behavior 2021-08-06 08:24:26 +09:00
Calvin Rose 61769c8f16
Merge pull request #747 from dbready/fractional_seconds
Note "int" vs "double" representation of seconds in os API
2021-07-31 15:49:09 -05:00
Damien Ready 934e091410 Note "int" vs "double" representation of seconds 2021-07-31 11:02:48 -05:00
Calvin Rose 7f7ee75954 Patch util.c 2021-07-31 10:00:43 -05:00
Calvin Rose e76b8da269 Add semantics for closing channels.
This makes certain algorithms simpler as channels
now have an explicit lifetime - multiple readers can coordinate
closing without needing to ensure the same number of reads as writes.
2021-07-30 19:26:42 -05:00
Calvin Rose 7e5f226480 Put source mapping info in stack traces. 2021-07-29 21:29:08 -05:00
Calvin Rose 2f634184f0 Merge branch 'master' of github.com:janet-lang/janet 2021-07-28 21:41:34 -05:00
Calvin Rose e3e01466ee
Merge pull request #741 from sogaiu/remove-duplicate-method
Remove duplicate of method recv-from
2021-07-28 20:35:33 -05:00
sogaiu 025918cfcc Remove duplicate of method recv-from 2021-07-28 14:44:49 +09:00
Calvin Rose 28fb76e602
Merge pull request #740 from yumaikas/hotfix-new-style-math-bindings
Fix macro stringification for one-arg math functions
2021-07-27 23:56:16 -05:00
Andrew Owen b0f97393a3 Fix macro stringification for one-arg math functions 2021-07-27 21:40:25 -06:00
Calvin Rose 2a7041e751
Merge pull request #739 from sogaiu/new-style-core-fn-decl-for-array
Update array.c with new style core function declarations
2021-07-27 22:37:35 -05:00
Calvin Rose 58c78d0d78
Merge pull request #730 from yumaikas/new-style-math-bindings
Update math.c for the new style
2021-07-27 22:37:13 -05:00
sogaiu eed158afdd
Merge branch 'janet-lang:master' into new-style-core-fn-decl-for-array 2021-07-28 10:24:11 +09:00
Andrew Owen 1c7505e04a
Merge branch 'master' into new-style-math-bindings 2021-07-27 19:19:39 -06:00
Calvin Rose 617da24942
Merge pull request #726 from yumaikas/new-style-ev-bindings
Update ev.c to use the new binding style that provides source information
2021-07-27 20:17:19 -05:00
Andrew Owen 98bdbfd3d5 Add JANET_DEF and co, use in math.c 2021-07-27 19:13:09 -06:00
Andrew Owen b289f253c7 Remove static function from the JANET_FN family of macros 2021-07-27 18:43:32 -06:00
Andrew Owen aabae03305 Add rselect bindings 2021-07-27 00:48:28 -06:00
sogaiu 194d645551 Update array.c with new style core function declarations. 2021-07-27 15:34:12 +09:00
Calvin Rose 889d6f9e43
Merge pull request #737 from sogaiu/new-style-core-fn-decl-for-corelib
Update corelib.c with new style core function declarations.
2021-07-26 22:07:17 -05:00
Calvin Rose 151de093d0
Merge pull request #736 from sogaiu/new-style-core-fn-decl-for-debug
Update debug.c with new style core function declarations.
2021-07-26 22:06:17 -05:00
Calvin Rose cc13e45f21
Merge pull request #738 from sogaiu/new-style-core-fn-decl-for-buffer
Update buffer.c with new style core function declarations.
2021-07-26 22:01:28 -05:00
sogaiu 7492a4c871 Update buffer.c with new style core function declarations. 2021-07-27 11:34:03 +09:00
sogaiu d20543b92c Update corelib.c with new style core function declarations. 2021-07-27 11:18:54 +09:00
sogaiu 59aab2ebbd Update debug.c with new style core function declarations. 2021-07-27 08:01:56 +09:00
Calvin Rose 08f7b1b9e5 Run the formatter. 2021-07-26 17:54:26 -05:00
Calvin Rose f2ac1c15e6
Merge pull request #735 from sogaiu/new-style-core-fn-decl-for-fiber
Update fiber.c with new style core function declarations.
2021-07-26 17:36:54 -05:00
Calvin Rose eaf8f198c1
Merge pull request #733 from sogaiu/new-style-core-fn-decl-for-io
Update io.c with new style core function declarations.
2021-07-26 17:36:37 -05:00
sogaiu 2955286606 Update fiber.c with new style core function declarations. 2021-07-27 07:00:59 +09:00
Calvin Rose 40561340a8
Merge pull request #721 from uvtc/patch-1
docs for doc, searching for strings
2021-07-26 15:21:39 -05:00
Calvin Rose 4f00a7db88
Merge pull request #729 from sogaiu/new-style-core-fn-decl-for-os
Update os.c with new style core function declarations.
2021-07-26 15:21:15 -05:00
Calvin Rose acc21d0b76
Merge pull request #724 from sogaiu/new-style-core-fn-decl-for-thread
Update thread.c with new style core function declarations.
2021-07-26 15:19:19 -05:00
Calvin Rose db5df70d0c
Merge pull request #727 from sogaiu/new-style-core-fn-decl-for-string
Update string.c with new style core function declarations.
2021-07-26 15:19:07 -05:00
Calvin Rose a6073dc237
Merge pull request #734 from sogaiu/new-style-core-fn-decl-for-inttypes
Update inttypes.c with new style core function declarations.
2021-07-26 10:29:53 -05:00
sogaiu 92c132381e Update inttypes.c with new style core function declarations. 2021-07-26 21:52:02 +09:00
sogaiu d0575e4087 Update io.c with new style core function declarations. 2021-07-26 21:39:13 +09:00
Calvin Rose 5ca48b96af
Merge pull request #728 from sogaiu/new-style-core-fn-decl-for-parse
Update parse.c with new style core function declarations.
2021-07-26 07:22:46 -05:00
Calvin Rose 2a9f30fc8a
Merge pull request #725 from sogaiu/new-style-core-fn-decl-for-table
Update table.c with new style core function declarations.
2021-07-26 07:16:28 -05:00
Calvin Rose ba89a81a3e
Merge pull request #731 from sogaiu/new-style-core-fn-decl-for-net
Update net.c with new style core function declarations.
2021-07-26 07:11:15 -05:00
Calvin Rose 5f32300592
Merge pull request #732 from sogaiu/new-style-core-fn-decl-for-marsh
Update marsh.c with new style core function declarations.
2021-07-26 07:04:29 -05:00
sogaiu 15b4d9363b Update marsh.c with new style core function declarations. 2021-07-26 18:29:59 +09:00
sogaiu ceca0e7f0e Update net.c with new style core function declarations. 2021-07-26 18:20:06 +09:00
Andrew Owen 700770b883 Update math.c for the new style 2021-07-26 01:51:13 -06:00
sogaiu 8365037be5 Update os.c with new style core function declarations. 2021-07-26 16:48:04 +09:00
sogaiu dfaba7daa6 Update parse.c with new style core function declarations. 2021-07-26 15:42:33 +09:00
sogaiu 5756934144 Update string.c with new style core function declarations. 2021-07-26 15:23:04 +09:00
Andrew Owen 7b3ab2727f Fix copy/paste mistake in ev/take docs 2021-07-26 00:11:05 -06:00
Andrew Owen 714ba808dd Update ev.c to use the new binding style that provides source information 2021-07-25 23:25:38 -06:00
sogaiu 6e94e03baa Update table.c with new style core function declarations. 2021-07-26 14:03:01 +09:00
sogaiu ac98dbccb8 Update thread.c with new style core function declarations. 2021-07-26 13:46:31 +09:00
Calvin Rose 6e3355d7f2
Merge pull request #723 from sogaiu/new-style-core-fn-decl-for-tuple
Update tuple.c with new style core function declarations.
2021-07-25 22:41:42 -05:00
Calvin Rose 97907906c5
Merge pull request #722 from sogaiu/new-style-core-fn-decl-for-compile
Update compile.c with new style core function declarations.
2021-07-25 22:41:11 -05:00
Calvin Rose eb84200f28 Fix linux issues with epoll on normal files.
We use the selfpipe trick if epoll fails with EPERM when trying to
register a file descriptor.
2021-07-25 21:47:52 -05:00
sogaiu caaa26e153 Update tuple.c with new style core function declarations. 2021-07-26 11:33:46 +09:00
Calvin Rose 030dd747e9 Merge branch 'master' of github.com:janet-lang/janet 2021-07-25 20:21:59 -05:00
sogaiu dccb98bb92 Update compile.c with new style core function declarations. 2021-07-26 09:07:53 +09:00
John Gabriele e356b7141c
Update boot.janet 2021-07-25 17:26:31 -04:00
bakpakin 4cae7e6d5d When building amalgamated build on windows, patch source-map.
We don't want any backslahes cropping up in the offical distribution of
janet.c.
2021-07-25 15:53:38 -05:00
bakpakin cc07b4a89a Merge branch 'master' of github.com:janet-lang/janet 2021-07-25 14:54:45 -05:00
bakpakin 7e8154e648 Update peg.c with new style core function declarations. 2021-07-25 14:54:25 -05:00
Calvin Rose dfee997e45
Merge pull request #718 from uvtc/patch-1
Add some clarifying backticks to docs
2021-07-25 14:10:44 -05:00
Calvin Rose f6b7cb9c49
Merge pull request #719 from uvtc/patch-2
Clarify docs on take and drop functions
2021-07-25 14:10:01 -05:00
bakpakin 4452d0e0f5 Update CHANGELOG.md 2021-07-25 13:08:17 -05:00
bakpakin 7fba44ccce Add macro mechanism for defining C source information for functions.
This wil let us track source code for C functions more easily.
2021-07-25 13:03:01 -05:00
bakpakin 6f1695ecd4 Add utitities for interrupting the event loop.
janet_loop1_interrupt makes the event loop compatible
with safe interruptions for custom scheduling. Does this by exposing
custom events on the event loop. A custom event schedules a function pointer
to run in a way that can interrupt
epoll_wait/poll/GetQueuedCompletionStatus.
2021-07-25 09:08:46 -05:00
John Gabriele 76acbf9bb6
Clarify docs on take and drop functions
Pass in indexed and bytes, return tuples and strings, respectively.
2021-07-24 18:44:49 -04:00
John Gabriele 2769a62bb3
Add some clarifying backticks to docs 2021-07-24 16:58:21 -04:00
bakpakin 160dd830a0 Add janet_interpreter_interrupt for custom scheduling.
This would allow an embedder to suspend the current Janet fiber
via an external event like a signal, other thread, or really anything.
This is a useful primitive for custom schedulers that would call
janet_interpreter_interupt periodically (say, in an interval with SIG_ALRM),
do some work, and then use janet_continue on the janet_root_fiber, or
for embedding into other soft-realtime applications like a game. To say,
only allow about 5ms per frame of interpreter time.
2021-07-24 15:14:37 -05:00
bakpakin aafc595e3a Fix typo. 2021-07-24 12:47:51 -05:00
bakpakin 202783c67a Add :d switch to os/spawn.
This allows for starting processes that can be turned into zombies.
2021-07-24 11:55:04 -05:00
Calvin Rose f11b2c5a0d
Merge pull request #717 from yumaikas/fix-os-open-write-windows
Fix os open write windows, and add TerminateProcess calls
2021-07-24 07:52:40 -05:00
Andrew Owen e8a86013da Add fixes for :write on filestreams that come from os/open 2021-07-24 02:30:00 -06:00
Calvin Rose a89c377c92 Add the `fiber-fn` macro which slightly generalizes `coro`. 2021-07-22 17:59:01 -05:00
Calvin Rose 54d73f6722 Make epoll the default on Linux for event loop implementations. 2021-07-21 21:46:26 -05:00
Calvin Rose 2e58f5f0d4 Add table/clear. 2021-07-21 19:58:42 -05:00
Calvin Rose e7ea39f410 Prevent possible bad garbage collection when finalizing streams.
The GC finalizer for streams would sometimes try and use other objects
after they had already been freed.
2021-07-20 19:42:35 -05:00
Calvin Rose a125218d03 Move some defines. 2021-07-20 18:24:56 -05:00
Calvin Rose 55b8563c08 Add janet_loop_fiber C function to run a fiber to completion from C.
This is mainly meant for use as the entry point to a C wrapper for a
janet program. This maeans the programmer doesn't need to use an ifdef
to handle if the event loop is enabled.
2021-07-18 09:39:37 -05:00
Calvin Rose aea1f59f6e Add option to build janet without thread library. 2021-07-17 15:13:28 -05:00
Calvin Rose ab27b789e4 Fix minimal build. 2021-07-17 13:10:55 -05:00
Calvin Rose 3a1a59f1eb Address windows build issue. 2021-07-16 21:10:02 -05:00
Calvin Rose c20a76cddb Update CHANGELOG and indicate next release will be 1.17.0 2021-07-16 21:05:42 -05:00
Calvin Rose 1ef6db16ed Add janet_vm_save and janet_vm_load.
This lets a user multiplex multiple Janet VMs on a single
thread or process if they are willing to implement context switching
themselves.
2021-07-16 20:59:03 -05:00
Calvin Rose 230b734663 Delete jpm and related testing from this repository.
JPM and related functionality has been moved to it's own repository
and will be versioned separately from Janet. The distribution process
could later be modified to bundle a version of jpm with Janet but this
is perhaps not needed.
2021-07-15 20:49:41 -05:00
Calvin Rose dc414f1239
Merge pull request #713 from yumaikas/fix-process-terminate-windows
Add TerminateProcess to janet_proc_gc and os_proc_kill on Windows
2021-07-11 09:30:07 -04:00
Calvin Rose dafd2329c5
Merge pull request #712 from sogaiu/tweak-function-name
Tweak function name
2021-07-11 08:11:48 -05:00
Andrew Owen 12cfda1f58 Add TerminateProcess to janet_proc_gc and os_proc_kill on Windows 2021-07-11 04:05:11 -06:00
Andrew Owen 96b4e71704 Add TerminateProcess to janet_proc_gc and os_proc_kill on Windows 2021-07-11 03:56:08 -06:00
sogaiu edb415d1a8 Tweak function name 2021-07-11 12:27:15 +09:00
Calvin Rose 72c1d1c484 Fix some error condiditions to have the right number of arguments. 2021-07-10 14:09:59 -04:00
Calvin Rose 41a7154aa5 Remove jhydro from CI pipeline. 2021-06-27 12:49:19 -05:00
Calvin Rose 346d024e48 Remove travis CI integration. 2021-06-27 12:48:07 -05:00
Calvin Rose 04a248dc37 Update CHANGELOG.md 2021-06-27 10:54:03 -05:00
Calvin Rose 5defc3b914 Fix bug with ev/go when passing supervisor and value.
value was incorrectly set to nil in these cases. Also
fix some typos in core docstrings.
2021-06-25 18:58:19 -05:00
Calvin Rose 04ca945ecf Address #711 - don't persist `(dyn :exit)` 2021-06-24 14:51:08 -05:00
Calvin Rose d687db71e7
Merge pull request #708 from subsetpark/patch-1
Update CHANGELOG.md [typo]
2021-06-12 10:34:45 -05:00
Calvin Rose 87f8fe14dd Prepare for 1.16.1 release. 2021-06-09 19:08:24 -05:00
Zach Smith af08124229
Update CHANGELOG.md 2021-06-08 12:22:54 -04:00
Calvin Rose 2eadb21eb7 Update changelog. 2021-05-31 16:51:53 -05:00
Calvin Rose 8b97a0dbbf
Merge pull request #707 from pepe/fix-shadow
Rename level const to not to shadow line in eval1
2021-05-31 16:05:41 -05:00
Calvin Rose 69afa2a7a3
Merge branch 'master' into fix-shadow 2021-05-31 16:05:29 -05:00
Calvin Rose da5328bae5 Merge branch 'master' of git.sr.ht:~bakpakin/janet 2021-05-31 15:14:39 -05:00
Josef Pospíšil a4325372e2 Rename level const to not to shadow line in eval1 2021-05-31 21:51:31 +02:00
Calvin Rose 4b96b73858 Add -w and -x flags to janet for linting. 2021-05-31 14:36:25 -05:00
Calvin Rose bbae43f259 Update copyright dates. 2021-05-31 13:46:02 -05:00
bakpakin 14fedbf063 Update copyright. 2021-05-31 09:53:52 -05:00
Calvin Rose ab974c409d Remove externeous typedarray defines in janet.h 2021-05-31 09:23:45 -05:00
Calvin Rose 2040709585 Re-add `make docs`.
Wasn't hurting anything.
2021-05-30 16:44:37 -05:00
Calvin Rose 60214dc659 Update for windows compiler warning. 2021-05-30 16:42:58 -05:00
Calvin Rose b990d77f16 Prepare for 1.16.0 release. 2021-05-30 12:15:56 -05:00
Calvin Rose d204e06e11 Use lint information in run-context. 2021-05-30 10:33:46 -05:00
Calvin Rose f6b37dbc77 Merge branch 'master' into linting 2021-05-30 09:34:32 -05:00
Calvin Rose fab65d6c40 Merge branch 'master' into struct-proto 2021-05-30 09:33:59 -05:00
Calvin Rose ff4d49f556 Set JANET_DIST_DIR on release. 2021-05-30 09:23:52 -05:00
Calvin Rose dfa5fa1187 Remove some stupid shell gymnastics in Makefile. 2021-05-30 09:14:34 -05:00
Calvin Rose 1f4f69a5b6 Fix windows syntax issue. 2021-05-29 20:40:26 -05:00
Calvin Rose 84f82f5465 Remove code delimtiers from defn and defmacro. 2021-05-29 20:37:30 -05:00
Calvin Rose c911f7c47e Address #694 - Update doc-format with more features.
Also allows having doc-format print in color with
(dyn :doc-color).
2021-05-29 20:34:22 -05:00
Calvin Rose 4d983e54b5 Initial struct prototype code.
Also add a number of cfunctions for manipulating structs
with prototypes.
2021-05-29 11:43:18 -05:00
Calvin Rose 33c000daea Expose linting array to macros.
This has a lot of possible uses, and would let users add a macro-based
type system on top of Janet that would integrate with the usual linting
and warning system.
2021-05-28 15:15:34 -05:00
Calvin Rose 7ff204ec44 Work on system for adding compiler warnings.
This is the beginning of a system for compiler warnings. This includes
linting, deprecation notices, and other compiler warnings that are best
detected by the `compile` function and don't require the partial
evalutaion of the flychecker.
2021-05-28 15:12:05 -05:00
Calvin Rose 7c757ef3bf Make jpm configurable for environments like MinGW. 2021-05-26 10:07:11 -05:00
Calvin Rose 2db7945d6f Fix peg bug when there is no default grammar set.
This could result in a segfault when we attempt to
read from a NULL pointer.
2021-05-20 21:57:22 -05:00
Calvin Rose 81186bf262 Merge branch 'master' of github.com:janet-lang/janet 2021-05-19 18:43:50 -05:00
Calvin Rose eeef5b0896 Add `as-macro` and `module/add-syspath` 2021-05-19 18:18:00 -05:00
Calvin Rose 8189b6fc11
Merge pull request #690 from sogaiu/specials-doc
Make doc work for special forms
2021-05-09 13:54:46 -05:00
sogaiu e5a2df93ab Make doc work for special forms 2021-05-07 08:47:33 +09:00
Calvin Rose c3f770da27 Fix meson build. 2021-04-29 15:59:44 -05:00
Calvin Rose 49f66a936c Merge commit 'f4c9064b79d5b32fd74e5ddf25266356c22dd53b' 2021-04-29 15:58:41 -05:00
Calvin Rose 83dda98240 Update jpm to work post patch. 2021-04-29 14:28:54 -05:00
Calvin Rose b4ddbd0097 Address #670 - Allow modifying jpm to link to extra libraries. 2021-04-29 14:04:18 -05:00
Calvin Rose cbe92bb985 Merge branch 'master' of github.com:janet-lang/janet 2021-04-29 13:13:55 -05:00
Calvin Rose 60c6a0d334 Add :native-deps option to `jpm`.
Use is like:

```
(declare-native
 :name "my-nuermical-library"
 :source @["numerical_lib.c"]
 :native-deps ["tarray"])

```

Where `tarray` is a native generated by o ne of the project
dependencies. This will lets us move more C functionality out of the
core of Janet while still allowing it's use from natives.
2021-04-29 13:11:46 -05:00
Calvin Rose 1baab5eb61 Remove typed arrays from the core.
Typed arrays will instead live in an external jpm nodule.
Also, changes have been made to `jpm` to allow other natives to use the
typedarray headers.
2021-04-29 12:33:49 -05:00
Calvin Rose 8fc8974b60 Add `from-pairs` to core. #683
This always creates a table, use `table/to-struct` to
create a struct.
2021-04-29 12:06:24 -05:00
Calvin Rose ecb49c2e5e
Merge pull request #688 from cjones051073/use-nsgetenviron-on-apple
Use _NSGetEnviron() on Apple
2021-04-29 12:00:35 -05:00
Chris Jones 29797b9eb0
Use _NSGetEnviron() on Apple 2021-04-27 11:54:24 +01:00
Calvin Rose e181ee586b Prepare for 1.15.5 release. 2021-04-25 14:00:16 -05:00
Calvin Rose 7b7d742bec Add declare-headers to jpm. 2021-04-25 13:38:24 -05:00
Calvin Rose 612eaff9ff Fix #682 - Don't hardcode size of sun_path. 2021-04-15 14:57:40 -05:00
Calvin Rose d76ef187e8
Merge pull request #681 from pyrmont/patch-2
Fix link to Introduction
2021-04-09 20:04:42 -05:00
Michael Camilleri e01ab86a89
Fix link to Introduction 2021-04-08 16:10:24 +09:00
Calvin Rose 89b59b4ffc Merge branch 'master' of github.com:janet-lang/janet 2021-04-06 23:36:11 -05:00
Calvin Rose e367ecf806 Update cannonical link. 2021-04-06 23:35:57 -05:00
Calvin Rose effc9e0f33
Merge pull request #677 from uvtc/patch-1
Add note about sponsorship to README
2021-04-02 15:00:21 -05:00
John Gabriele da06e6c6e3
Update README.md
Co-authored-by: Michael Camilleri <mike@inqk.net>
2021-03-31 21:40:30 -04:00
John Gabriele c258bee54f
Add note about sponsorship to README 2021-03-31 21:27:03 -04:00
Calvin Rose cde4a505cf Fix #673 - check typed array index bounds as well as buffer count. 2021-03-30 21:14:42 -05:00
Calvin Rose 2802e66259 Merge branch 'master' of github.com:janet-lang/janet 2021-03-26 15:45:14 -05:00
Calvin Rose 3a3003029a Merge branch 'master' of github.com:janet-lang/janet 2021-03-26 15:44:43 -05:00
Calvin Rose 08bca8fb63 Merge branch 'master' of github.com:janet-lang/janet 2021-03-26 15:36:50 -05:00
Calvin Rose 7c7ff802fa Add net/shutdown to allow better networking with streams. 2021-03-26 15:36:25 -05:00
Calvin Rose 0945acc780
Merge pull request #672 from Luewd/cc-file-ext
Allow .cc file extension in jpm declare-native
2021-03-26 15:13:12 -05:00
Lue 64ec9f9cb6
Allow .cc file extension in jpm declare-native 2021-03-25 13:19:05 -04:00
Calvin Rose 83f7de33c0
Merge pull request #671 from pyrmont/feature.metadata
Support adding arbitrary metadata to bindings
2021-03-24 16:56:25 -05:00
Michael Camilleri ec2d7bf349
Support adding arbitrary metadata to bindings 2021-03-24 09:38:12 +09:00
Andrew Chambers f4c9064b79 Add config support for custom allocators. 2021-03-23 23:00:48 +13:00
Calvin Rose 8ede16dc26
Merge pull request #669 from dbready/dist_layout
Create Folder Hierarchy for Linux Release
2021-03-22 11:51:21 -05:00
Damien Ready 27e400fba3 Prepare the .tar distribution with folder layout 2021-03-20 10:53:51 -05:00
Calvin Rose 37d6cb469b
Merge pull request #668 from ffontaine/master
meson.build: fix build without threads
2021-03-19 15:44:25 -05:00
Calvin Rose 100a82feb2 Version bump (development version). 2021-03-19 15:41:34 -05:00
Calvin Rose 90e5828d5d Update printing when entering debugger. 2021-03-19 15:38:46 -05:00
Calvin Rose b3e80308d4 Change inheritance rule. 2021-03-19 15:18:19 -05:00
Fabrice Fontaine a7abe11105 meson.build: fix build without threads
Fix the following build failure with -Dsingle_threaded=true on embedded
toolchains without pthread:

FAILED: janet.p/meson-generated_.._janet.c.o
/home/buildroot/autobuild/run/instance-3/output-1/host/bin/arm-linux-gcc -Ijanet.p -I. -I.. -I../src/include -fdiagnostics-color=always -pipe -Wall -Winvalid-pch -std=c99 -O3 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -pthread -fvisibility=hidden -MD -MQ janet.p/meson-generated_.._janet.c.o -MF janet.p/meson-generated_.._janet.c.o.d -o janet.p/meson-generated_.._janet.c.o -c janet.c
In file included from /home/buildroot/autobuild/run/instance-3/output-1/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/usr/include/stdlib.h:24,
                 from ../src/include/janet.h:300,
                 from src/core/features.h:57:
/home/buildroot/autobuild/run/instance-3/output-1/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/usr/include/features.h:218:5: warning: #warning requested reentrant code, but thread support was disabled [-Wcpp]
  218 | #   warning requested reentrant code, but thread support was disabled
      |     ^~~~~~~
src/core/ev.c:39:10: fatal error: pthread.h: No such file or directory

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2021-03-18 09:13:22 +01:00
Calvin Rose 3c63a48df4 (#667) Add constant inlining for tuples and structs.
Structs and tuples composed entirely out of constant values
will themselves be considered constant values during compilation.
This reduces the amount of generated code.
2021-03-16 20:52:55 -05:00
Calvin Rose fcb88e5a98 Merge branch 'master' of github.com:janet-lang/janet 2021-03-16 20:12:47 -05:00
Calvin Rose a467b34de4 Prepare for 1.15.4 release. 2021-03-16 20:12:33 -05:00
Calvin Rose a24cc77ff8
Merge pull request #666 from pyrmont/patch-1
Remove instructions to add tags
2021-03-14 16:16:42 -05:00
Michael Camilleri d6675d9909
Remove instructions to add tags 2021-03-14 15:07:33 +09:00
Calvin Rose fa163093d2 Update CHANGELOG.md 2021-03-13 19:22:47 -06:00
Calvin Rose e70f64e23d Sort keys initial. 2021-03-13 19:17:07 -06:00
Calvin Rose 6f605f8141 Update pretty printing default depth. 2021-03-13 17:43:19 -06:00
Calvin Rose d9419ef994
Merge pull request #660 from ffontaine/master
meson.build: fix static build
2021-03-12 19:06:33 -06:00
Calvin Rose 7e8639a682
Merge pull request #664 from leahneukirchen/meson-pkgconfig2
Fix include path when using meson
2021-03-12 17:11:54 -06:00
Leah Neukirchen 452b303b4c Fix include path when using meson
Closes #661.
2021-03-12 18:49:50 +01:00
Fabrice Fontaine b0f1a4967d meson.build: fix static build
Don't enforce -rdynamic when building statically to avoid the following
build failure:

/home/giuliobenetti/autobuild/run/instance-2/output-1/host/bin/arm-linux-gcc  -o janet janet.p/meson-generated_.._janet.c.o janet.p/src_mainclient_shell.c.o -Wl,--as-needed -Wl,--allow-shlib-undefined -Wl,-O1 -rdynamic -Wl,-elf2flt -static -Wl,--start-group -lm -ldl -Wl,--end-group -pthread
arm-linux-gcc.br_real: error: unrecognized command line option '-rdynamic'

Fixes:
 - http://autobuild.buildroot.org/results/a4f927f73a7b80e65408c992d7b6023609a1eacc

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2021-03-12 08:46:05 +01:00
Calvin Rose 9eb4c59c04 Require opt-in behavior per script.
This means a binscript needs to indicate that it is a Janet script, and
then the user who is installing the script can choose whether or not to
do the magic shebang replacement.
2021-03-11 18:47:53 -06:00
Calvin Rose 0d42506cde Merge branch 'master' of github.com:janet-lang/janet 2021-03-11 18:37:54 -06:00
Calvin Rose c8a13ce475 Add --auto-shebang option to jpm. 2021-03-11 18:37:45 -06:00
Calvin Rose 05e3467d09
Merge pull request #655 from uvtc/patch-1
Update os.c
2021-03-11 18:12:54 -06:00
Calvin Rose 90639e5068
Merge pull request #658 from pyrmont/bugfix.jpm-realpath
Fix argument passing to os/realpath in jpm
2021-03-11 18:12:38 -06:00
Calvin Rose 73c7711c78
Merge pull request #657 from ffontaine/master
meson.build: defaults to c99 for "build.c_std"
2021-03-11 18:12:25 -06:00
Calvin Rose 78f6b6a507 Add auto-shebang functionality. 2021-03-11 18:10:33 -06:00
Michael Camilleri 84f0ab5356
Fix argument passing to os/realpath in jpm 2021-03-10 17:11:12 +09:00
Fabrice Fontaine 546437d799 meson.build: defaults to c99 for "build.c_std"
Since Meson 0.51, there are special build options for "native:true"
builds, prefixed with "build.".  This change breaks cross builds
because `janet-boot/src_core_asm.c` is no longer built with `-std=c99`:

FAILED: janet-boot.p/src_core_asm.c.o
/usr/bin/gcc -Ijanet-boot.p -I. -I.. -I../src/include -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -O3 -pthread -DJANET_BOOTSTRAP -MD -MQ janet-boot.p/src_core_asm.c.o -MF janet-boot.p/src_core_asm.c.o.d -o janet-boot.p/src_core_asm.c.o -c ../src/core/asm.c
../src/core/asm.c: In function 'janet_disasm_bytecode':
../src/core/asm.c:866:5: error: 'for' loop initial declarations are only allowed in C99 mode
     for (int32_t i = 0; i < def->bytecode_length; i++) {
     ^

Fixes:
 - http://autobuild.buildroot.net/results/355e0992338a8d132050517f83a3884606b00529

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2021-03-10 07:57:53 +01:00
John Gabriele 0f05aec563
Update os.c
Doc typo
2021-03-09 14:39:09 -05:00
Calvin Rose c9097623d6 Add group-by and partition-by to the core.
Semantics are mostly emulated from Clojure.
2021-03-04 19:34:36 -06:00
Calvin Rose 6392b37c47 Merge branch 'master' of github.com:janet-lang/janet 2021-02-28 13:05:05 -06:00
Calvin Rose 4fcc8075d4 Release 1.15.3 2021-02-28 13:04:24 -06:00
Calvin Rose b2d6a55335
Merge pull request #646 from pyrmont/bugfix.run-context-match
Fix call to match in run-context
2021-02-28 10:48:43 -06:00
Michael Camilleri 1fea5f8fe7
Fix call to match in run-context 2021-02-28 14:23:17 +09:00
Calvin Rose d3e52a2afb Fix makefile to attach build identifier. 2021-02-27 19:50:31 -06:00
Calvin Rose d6ea1989cc Merge branch 'master' of github.com:janet-lang/janet 2021-02-26 17:29:25 -06:00
Calvin Rose 96513665d6 Address #641 - add undef combinator.
The (undef rule :tag) combinator lets a user "scope" tagged captures.
After the rule has matched, all captures with tag :tag can no longer be
refered to by their tag. However, such captures from outside
rule are kept as is. If no tag is given, all tagged captures from rule
are unreferenced. Note that this doesn't `drop` the captures, merely
removes their association with the tag. This means subsequent calls to
`backref` and `backmatch` will no longer "see" these tagged captures.
2021-02-26 17:25:09 -06:00
Calvin Rose b795d13f61
Merge pull request #642 from pyrmont/feature.run-context-location
Allow source location in run-context to be updated
2021-02-26 16:36:03 -06:00
Calvin Rose 970f9b3981
Merge pull request #643 from uvtc/patch-1
`sort` doc
2021-02-26 16:28:27 -06:00
John Gabriele be7dab4d17
Update boot.janet 2021-02-23 22:30:42 -05:00
John Gabriele 0e44ce5cba
Update boot.janet 2021-02-23 22:26:53 -05:00
John Gabriele 1f8c2781dd
`sort` doc
Clarify doc for `sort` and `sorted`. Also in `sort`, changed arg name.
2021-02-23 22:24:59 -05:00
Michael Camilleri f381a9c773
Check that new source location is a string 2021-02-22 12:50:44 +09:00
Michael Camilleri 855a9a01fc
Allow source location in run-context to be updated 2021-02-22 12:38:56 +09:00
Calvin Rose a5f237993d Don't fail testing when ev disabled. 2021-02-20 10:56:54 -06:00
Calvin Rose c68264802a Fix #638 - update fiber status in certain cases.
This fixes a regression from changes to janet_try. In some cases, we
would not update the status of a fiber when signaling, which left the
fiber's status as whatever it had previously. This could lead to strange
control flow issues.
2021-02-20 10:55:16 -06:00
Calvin Rose 742469a8bc Address #640.
Allow for a zero length match at the end of a string when using the
to or thru combinators.
2021-02-19 16:10:03 -06:00
Calvin Rose 92928d5c4f Update definition of `or`. 2021-02-16 17:00:27 -06:00
Calvin Rose 8320e25d64
Merge pull request #639 from leahneukirchen/or
Fix or with zero arguments
2021-02-16 16:57:21 -06:00
Leah Neukirchen c16a9d8463 Fix or with zero arguments.
The value is nil to be consistent for and/or and all/some.
Also add some tests for and/or.
2021-02-16 19:59:03 +01:00
Calvin Rose f1819c916a Fix build error for 1.15.2 2021-02-15 10:27:19 -06:00
Calvin Rose dd14b24d2a 1.15.1 release. 2021-02-15 10:21:22 -06:00
Calvin Rose 050d7c12a3 Prepare for 1.15.1 release. 2021-02-15 10:19:24 -06:00
Calvin Rose 7e2c433abc Fix #636 2021-02-14 14:34:52 -06:00
Calvin Rose 6713b23a65 Change behavior of empty env table passed to os/execute on windows. 2021-02-14 11:22:20 -06:00
Calvin Rose 60078e7950 Change os/execute implementation for windows. 2021-02-14 11:04:59 -06:00
Calvin Rose 69095fbb48
Merge pull request #633 from Alligator/master
Add missing argument to errorf in jpm
2021-02-10 17:51:47 -06:00
alligator c88a3c64e3 Add missing argument to errorf 2021-02-10 22:45:43 +00:00
Calvin Rose 771b0d0ab1 Version bump. 2021-02-09 20:32:09 -06:00
Calvin Rose c85310578b
Merge pull request #632 from sogaiu/tweak-spec-readint
Tweak spec_readint
2021-02-09 17:47:25 -06:00
sogaiu 60e2992158 Tweak spec_readint 2021-02-10 08:33:46 +09:00
Calvin Rose 2795e8a8b7 Update some sr.ht configs. 2021-02-08 18:26:04 -06:00
Calvin Rose bdf14170a4 Get ready for 1.15.0 release. 2021-02-08 18:10:46 -06:00
Calvin Rose 10dcbc639a Immediate instuctions will now call :compare method. 2021-02-08 11:53:25 -06:00
Calvin Rose 6a9bb0f4e4 Define immediate comparison instructions for non-integers.
Previous, the instructions were defined only for values that
fit into 32 bit integers for legacy reasons.
2021-02-08 11:41:48 -06:00
Calvin Rose c941e5a8f4
Merge pull request #628 from yumaikas/master
Switch out `by` to `before?` in sort functions.
2021-02-05 18:17:52 -06:00
Calvin Rose be91414c7a Improve error message from janet_call.
List expected arity in error messages.
2021-02-05 18:01:52 -06:00
Calvin Rose 6839b603c8 x86 32 bit on windows. 2021-02-04 23:31:04 -06:00
Andrew Owen 926b68d62e Switch out `by` to `before?` in sort functions.
Makes docstrings easier to read, and reduces confusion with sorted-by
and sort-by.
2021-02-04 22:28:46 -07:00
Calvin Rose d374e90033 Update sort documentation. 2021-02-04 20:11:24 -06:00
Calvin Rose b168b0758a Fix #625 - no fancy mixing in number hasing
Just hash upper 32 bits with lower 32 bits. Trying to get too fancy
was causing slowdowns in very trivial cases. Assuming that all
combinations of 64 bits in a double are equally likely (suspect but
probably not that incorrect), the obvious method of xoring the top
32 bits with the lower 32 bits gives a uniform distribution.
2021-02-04 19:37:11 -06:00
Calvin Rose 54c66ecfc0
Merge pull request #622 from sogaiu/tweak-add-paths-docstring
Tweak module/add-paths docstring
2021-02-04 19:05:34 -06:00
sogaiu 1c158bd4ff Tweak module/add-paths docstring 2021-02-03 21:11:16 +09:00
Calvin Rose ff24143f54
Merge pull request #620 from sogaiu/marshal-doc
Tweak marshal docstring
2021-02-02 21:29:54 -06:00
Calvin Rose dd117e81c2 Fix parser/insert.
We need to add the tuple wrapping code there as well.
2021-02-02 18:55:24 -06:00
sogaiu f4744a18c6 Tweak marshal docstring 2021-02-02 15:00:57 +09:00
Calvin Rose 259d5fabd9 Update Makefile and build_win for better builds.
Use build/c/janet.c in both to prevent accidental inclusion
of build/janet.h (which may be stale) instead of the source headers.
2021-01-31 09:59:53 -06:00
Calvin Rose d122a75efd Cleanup boot.janet to be more like normal source code.
Don't use `undef`, just use private defines.
2021-01-31 09:08:39 -06:00
Calvin Rose c9ea3ac304 Address #618 - clarify file/open docs. 2021-01-31 08:39:57 -06:00
Calvin Rose c63fe6ef8a Make flycheck follow GNU standards for errors. 2021-01-30 12:51:38 -06:00
Calvin Rose 72ec89dfe9 Change output format for line+col. 2021-01-30 11:33:15 -06:00
Calvin Rose 04805d106e Simpler overflow check. 2021-01-29 20:11:38 -06:00
Calvin Rose 9aed578466 Address #616 Buffer extra overflow bug.
We should have a normal error instead of undefined behavior, wrap
around, or wait for realloc to fail.
2021-01-29 18:32:54 -06:00
Calvin Rose 77c5279296
Merge pull request #611 from subsetpark/doc-example-readme
Use a slightly clearer example of the `doc` fun in README
2021-01-24 17:25:37 -06:00
Calvin Rose af75bf3b64 Update for sending streams to new threads. 2021-01-24 16:48:46 -06:00
Zach Smith a5157e868b Use a slightly clearer example of the `doc` fun in README 2021-01-24 15:44:34 -05:00
Calvin Rose 01a3d8f932 Address #478 - Disable core in static binaries/
Add --no-core option to quickbin, as well as :no-core option
to declare executable. This doesn't use the autodetection when
making binaries, instead opting for manual intervention.
2021-01-23 17:47:41 -06:00
Calvin Rose f22472a644 Begin work on allowing small binaries. 2021-01-23 17:08:11 -06:00
Calvin Rose 5cac8bcf9f Prepare for patch release. 2021-01-23 14:48:36 -06:00
Calvin Rose a2801fbef9 Fix #610 - POLLHUP should cause us to continue reading. 2021-01-23 14:26:24 -06:00
Calvin Rose 0b14e913da Merge branch 'master' of github.com:janet-lang/janet 2021-01-23 13:54:36 -06:00
Calvin Rose 85155bb2b4 Reference #478 Update peg/compile to use dyn for default grammar. 2021-01-23 13:54:02 -06:00
Calvin Rose dd8de1e9ac
Merge pull request #609 from yumaikas/master
Change tracev to upscope instead of using let
2021-01-22 19:02:27 -06:00
Calvin Rose c909835b0a Update CHANGELOG. 2021-01-22 12:55:38 -06:00
Calvin Rose a18aafedfd Merge branch 'master' of github.com:janet-lang/janet 2021-01-22 12:53:28 -06:00
Calvin Rose 317ab6df6b Add ev/thread and ev/do-thread.
- Also fix setting supervisor with net/accept-loop.
2021-01-22 12:52:45 -06:00
Andrew Owen 1fcaffe6b0 Change tracev to upscope, add test 2021-01-21 23:40:28 -07:00
Calvin Rose 3ae5c410dc
Merge pull request #606 from snimmagadda/master
Replace malloc + memset with calloc.
2021-01-21 12:59:21 -06:00
Sunil Nimmagadda 381128364e Replace malloc + memset with calloc.
Fixes an overflow warning from gcc with '-Wstringop-overflow' on
NetBSD-current.
2021-01-21 19:35:57 +05:30
Calvin Rose 0acf167e84
Merge pull request #602 from pyrmont/feature.module-docstrings
Display module-level docstrings with (doc)
2021-01-20 22:11:38 -06:00
Calvin Rose f7ca6deeb0
Merge pull request #603 from pepe/evcal-doc
Fix ev/call doc
2021-01-20 20:52:23 -06:00
Josef Pospíšil 251486e4aa Fix ev/call doc 2021-01-20 20:31:41 +01:00
Michael Camilleri c6467be60d
Conform display of path with existing display of source map info 2021-01-20 10:47:55 +09:00
Michael Camilleri 4dd512ad28
Use print-module-entry function to display docstring 2021-01-20 10:16:59 +09:00
Michael Camilleri 28076b9385
Display module-level docstrings with (doc) 2021-01-20 10:01:31 +09:00
Calvin Rose 49dcc816ae Update os/shell to be non-blocking as well. 2021-01-18 16:44:22 -06:00
Calvin Rose fa61c70103 Release 1.14.1 2021-01-18 11:51:42 -06:00
Calvin Rose 5ee6dbcdf4 Prepare for 1.14.1 release. 2021-01-18 11:43:53 -06:00
Calvin Rose 634219da2c Fix windows swallowing IOCP events in many cases.
This fixes windows hanging on "failed" IO operations.
2021-01-17 20:41:59 -06:00
Calvin Rose fbe3849b4b Revert change to propagate op code. 2021-01-17 15:33:42 -06:00
Calvin Rose bd2e335063 Allow 1 argument call of debug/stacktrace
Since fibers now track the last value signaled.
2021-01-17 13:55:40 -06:00
Calvin Rose 96262e7d87 Fix integer limit docs. 2021-01-17 13:44:53 -06:00
Calvin Rose c5da87b860 Fix broken doc format.
Many assumptions in the parsing code that could cause infinite
loops, as well as assuming things were non-nil.
2021-01-17 11:36:48 -06:00
Calvin Rose 848d4a1498 Update man page. 2021-01-16 19:40:29 -06:00
Calvin Rose 70e23df6f8 Merge branch 'master' of github.com:janet-lang/janet 2021-01-16 18:29:41 -06:00
Calvin Rose 95af205681
Merge pull request #589 from yumaikas/master
Add support for a profile.janet
2021-01-16 18:29:00 -06:00
Calvin Rose 6dfb689d1f Update versions to indicate 14.1 2021-01-16 15:54:27 -06:00
Calvin Rose 462e74ef87 Add os/proc-close to close all pipes associated with a subprocess.
This will not leak handles until the GC runs in most use cases.
2021-01-16 15:11:07 -06:00
Andrew Owen c6aa536590 Clean up env dance 2021-01-16 12:47:50 -07:00
Calvin Rose c79480342b Remove unused defines. 2021-01-16 07:19:28 -06:00
Calvin Rose a1cc5ca045 Fix #593.
Also add ev/give-supervisor to the core.
2021-01-16 07:18:07 -06:00
Andrew Owen 7f74ff3dd7 Restore :source property to keep import* working at REPL 2021-01-15 02:59:17 -07:00
Andrew Owen c4a95e9a1e Update error handling, kill a bikeshed argument 2021-01-15 01:53:14 -07:00
Andrew Owen 71f9e2b1d7 Add support for a profile.janet
Add support for a profile.janet, along with a flag for disabling it's use.
2021-01-15 01:31:23 -07:00
Calvin Rose 16fe32215b
Merge pull request #584 from sogaiu/tweak-file-docs
Tweak file docs
2021-01-13 21:41:33 -06:00
Calvin Rose dd7342a6cf
Merge pull request #583 from sogaiu/tweak-debug-docs
Tweak debug/stack docs
2021-01-13 21:41:26 -06:00
Calvin Rose 35c88d10cd
Merge pull request #582 from sogaiu/tweak-parser-docs
Tweak parser docs
2021-01-13 21:41:09 -06:00
Calvin Rose 42532de0eb
Merge pull request #585 from sogaiu/tweak-os-docs
Tweak os docs
2021-01-13 21:41:01 -06:00
sogaiu 122e2a9378 Tweak os docs 2021-01-14 08:44:56 +09:00
sogaiu 33c9395d79 Tweak file docs 2021-01-14 08:33:04 +09:00
sogaiu fc49aa359c Tweak debug/stack docs 2021-01-14 07:47:50 +09:00
sogaiu fcf37942a7 Tweak parser docs 2021-01-14 07:31:20 +09:00
Calvin Rose 9b42d5a5e9
Merge pull request #579 from sogaiu/tweak-type-docs
Tweak type docs
2021-01-13 12:26:30 -06:00
Calvin Rose ba92dfcbe9
Merge pull request #580 from sogaiu/tweak-update-docs
Tweak update docs
2021-01-13 12:26:10 -06:00
Calvin Rose fd03603adb
Merge pull request #577 from sogaiu/tweak-expand-path-docs
Tweak module/expand-path docs
2021-01-13 12:25:55 -06:00
Calvin Rose 2008ddf8a8
Merge pull request #578 from sogaiu/tweak-disasm-docs
Tweak disasm docs
2021-01-13 12:25:30 -06:00
sogaiu c56b876bfe Tweak update docs 2021-01-13 23:04:06 +09:00
sogaiu c4957d5dfb Tweak type docs 2021-01-13 22:59:43 +09:00
sogaiu 068bd33afb Tweak disasm docs 2021-01-13 22:27:03 +09:00
sogaiu e9bd108be9 Tweak module/expand-path docs 2021-01-13 22:16:54 +09:00
Calvin Rose 4f2d1cdc00 Go back to a single supervisor channel per fiber.
We now also use the fiber mask to figure out which flags to wait for.
2021-01-12 21:35:28 -06:00
Calvin Rose 61cca10cf6 Allow iterating through the properties of core abstract types. 2021-01-11 23:14:07 -06:00
Calvin Rose dfbdd17dce Add `doc-of` function to core for reverse documentation lookup. 2021-01-11 20:32:26 -06:00
Calvin Rose 9078d3bd37 Update CHANGELOG.md 2021-01-11 18:54:50 -06:00
Calvin Rose 5e1a8c86f9 Add more network and subprocess testing with redirection. 2021-01-11 18:32:56 -06:00
Calvin Rose bf01bf631d More work on windows networking code.
Remove use of WSARecv and WSASend since for whatever reason
they seem suspect. We may want to revisit this later.
2021-01-11 18:00:31 -06:00
Calvin Rose 80c5ba32b5 Remove wait from CI testing for networking tests.
We want to expose any existing race conditions.
2021-01-11 15:55:12 -06:00
Calvin Rose 874cc79443 Fix #571 - fiber/status and fiber/new docstrings. 2021-01-11 15:44:46 -06:00
Calvin Rose 3883460202 Remove length checks to a number of core functions.
This lets them be more generic and implemented over a wider range of
data types, such as fibers.
2021-01-11 15:01:41 -06:00
Calvin Rose f0dbc2e404 Fix subprocess spawning on windows.
Also fix (:read stream :all)
2021-01-11 11:10:23 -06:00
Calvin Rose 4df1ac5b23 Fix some issues in os.c to diagnose improve windows subprocess code. 2021-01-11 09:06:39 -06:00
Calvin Rose 1f6d0d342b Fix #566 - bad docstring and bad arity for net/flush. 2021-01-10 12:02:28 -06:00
Calvin Rose 4625c28e6a Merge branch 'master' of github.com:janet-lang/janet 2021-01-10 11:59:41 -06:00
Calvin Rose 5536ba20a8 Move socket setup code from ev.c to net.c 2021-01-10 11:58:47 -06:00
Calvin Rose ef398e9036
Merge pull request #567 from Nananas/patch-1
Minor typo in ev/rselect docstring
2021-01-10 11:47:37 -06:00
Thomas Dendale 0c73c3f1cd
Minor typo in ev/rselect docstring
`ev/choice` is actually called `ev/select`
2021-01-10 16:42:52 +01:00
Calvin Rose 7ae7984f3c Allow yielding from root fiber to ev loop. 2021-01-09 23:35:34 -06:00
Calvin Rose 8286b33c52 Add event-chan argument to ev/go.
The event-chan is the final piece of the puzzle for fibers, and
will be pushed to when a fiber yields to the event loop.
2021-01-09 23:33:23 -06:00
Calvin Rose 475775cc9d Add a "new_channel" for root fibers.
When new fibers are scheduled on the event loop, this new_channel
receives the newly created fibers. This lets a fiber track which fibers
have been added and let's a user implement a supervisor.

Fix formatting.
2021-01-09 18:33:40 -06:00
Calvin Rose 11067d7a56 Update module and rem operator for int types. 2021-01-09 14:47:43 -06:00
Calvin Rose 5b05da65f0 Allow wrap around on u64.
This lets some math work as expected.
2021-01-09 12:43:33 -06:00
Calvin Rose 444e630783 Fix formatting. 2021-01-09 10:14:20 -06:00
Calvin Rose 8951b8de7a Inherit the supervisor channel from the root fiber if not given. 2021-01-08 16:32:23 -06:00
Calvin Rose 2abb87eb63 Add space in docstring. 2021-01-07 18:57:13 -06:00
Calvin Rose 32e8ac912d Merge branch 'master' of github.com:janet-lang/janet 2021-01-07 18:08:08 -06:00
Calvin Rose e403fb4652 Do not try and preload imports that are relative. 2021-01-07 18:07:47 -06:00
Calvin Rose daa37c22f5
Merge pull request #551 from pepe/remove-redundant-do
Remove redundant do
2021-01-07 10:38:21 -06:00
Josef Pospíšil 5a2a134c95 Remove redundant do 2021-01-07 14:38:58 +01:00
Calvin Rose b9acb6dfa5 Update CHANGELOG.md 2021-01-06 23:25:00 -06:00
Calvin Rose 4e7ad3c7ce Add initial implementation for supervisor channels.
Supervisor channels are a simple concept to more efficiently
enable dynamic, structure concurrency. When a top-level fiber
completes (or errors), it will push itself to it's supervisor
channel if it has one (instead of printing a stacktrace). This
let's another fiber poll a channel and "supervise" a set of fibers.
2021-01-06 23:19:22 -06:00
Calvin Rose ee0e1a2342 Remove jpm.bat from windows dist.
It is still present in the MSI.
2021-01-06 19:36:37 -06:00
Calvin Rose f206b476d1 Fix #550 - add varfn to safe forms for flycheck. 2021-01-06 17:31:08 -06:00
Calvin Rose dd2595c53f Merge branch 'master' of github.com:janet-lang/janet 2021-01-06 17:27:50 -06:00
Calvin Rose 545df28d71 Add flycheck function to core.
Also make flychecking work with stdin out of the box.
2021-01-06 17:27:17 -06:00
Calvin Rose 16f80b78cf
Merge pull request #546 from pepe/doc-thread-new-loop
Update doc for thread/new and remove ws in loop's
2021-01-05 20:31:46 -06:00
Calvin Rose 147bcce01b
Merge pull request #549 from pyrmont/docs.string-find-all-typo
Fix typos in string/find-all documentation
2021-01-05 20:31:12 -06:00
Calvin Rose f5877ac6d1 Revert makefile. 2021-01-05 20:29:50 -06:00
Calvin Rose adc41e31f4 Address #547 - don't drop references.
Keep a separate stack for tagged references. May cause pegs to
use more memory but makes the backref and backmatch features much more
powerful.

Also disables the second stack if backref and backmatch are not used in the peg.
2021-01-05 20:27:15 -06:00
Michael Camilleri 2e555a930f
Fix typos in string/find-all documentation 2021-01-06 10:14:49 +09:00
Calvin Rose bcba0c0279 Fix #548 - string/split bug.
Also update docstrings for string/find. The 'skipping'
behavior that was documented only applies to to string/replace-all.
2021-01-05 18:54:51 -06:00
Josef Pospíšil c7f382add6 Update doc for thread/new and remove ws in loop's 2021-01-04 18:29:00 +01:00
Calvin Rose 665b1e68d5 Pluralize arity compile warning. 2021-01-03 20:15:51 -06:00
Calvin Rose 2ca9300bf7 Add sort tests. 2021-01-03 16:45:37 -06:00
Calvin Rose 81f62b246c
Merge pull request #545 from felixr/master
Revert my buggy hybrid sort
2021-01-03 16:39:23 -06:00
Calvin Rose 87badc71d2 Remove :generate verb from loop.
Instead, one case use `:in` as with otehr data structures.
2021-01-03 16:38:38 -06:00
Calvin Rose e5242c67ff Update changelog and documentation. 2021-01-03 16:30:43 -06:00
Calvin Rose 4355420994 Remove function `eachy`.
Instead use `each`.
2021-01-03 16:19:23 -06:00
Calvin Rose c357af02c2 Allow iterating over fibers with each and similar. 2021-01-03 16:17:36 -06:00
Felix Riedel 19576effbe Revert "Tweak sort: use insertion sort for small arrays"
This reverts commit 0ea77cabfb.
2021-01-03 20:09:50 +00:00
Calvin Rose ecc6eb7497 Don't fail jpm if os/realpath fails. 2021-01-03 13:09:41 -06:00
Calvin Rose d0ac318980 Don't print to stderr in Makefile to detect version. Fix #544 2021-01-03 12:59:16 -06:00
Calvin Rose 7b030fe70d Fix some return issues. 2021-01-03 11:54:31 -06:00
Calvin Rose 115556fcf2 Merge branch 'ev_execute' 2021-01-03 11:48:00 -06:00
Calvin Rose 9760cf1f4e Fix MSVC warning. 2021-01-03 11:47:29 -06:00
Calvin Rose 47bb7fd21b Begin implementing async subproccesses for windows. 2021-01-03 11:21:44 -06:00
Calvin Rose 1c7ed8ca48 Use PostQueuedCompletionStatus for threaded calls on windows.
Ore efficient than using a self pipe.
2021-01-03 11:08:12 -06:00
Calvin Rose 6b268c5df4 `find-index` now takes optional default. 2021-01-03 09:33:52 -06:00
Calvin Rose 62f783f1dc Merge branch 'master' of github.com:janet-lang/janet 2021-01-03 09:26:31 -06:00
Calvin Rose 61c65f3df1 Fix valgrind warning. 2020-12-31 16:30:54 -06:00
Calvin Rose 05166b3673 Fix proc getter bug. 2020-12-31 16:23:20 -06:00
Calvin Rose 0a1c93b869 Add ev api for making threaded calls.
Easy way to make arbitrary functions in C async.
2020-12-31 16:12:42 -06:00
Calvin Rose 788f91a36f Remove unneeded book keeping for sub processes.
Since we are not using signals we no longer need some bookkeeping.
2020-12-31 11:52:12 -06:00
Calvin Rose c831ecf5d2 Working implementation of process waiting with threads.
Does not require all sorts of signal handling code
that is not thread-safe and can "steal processes".

However, there is a much simpler way to add this functionality
by creating a new stream and thread for each subprocess when it is
waited on. This is perhaps _slightly_ less efficient but oh so much
simpler, since we can reuse all of our concepts from streams and there
is no need to implement a whole system around the selfpipe.
2020-12-31 11:22:18 -06:00
Calvin Rose 9e42ee153c Merge branch 'master' into HEAD 2020-12-30 12:19:13 -06:00
Calvin Rose d457aa5951 Deprecate file/popen.
os/spawn is the prefered way of creating a subprocess and
communicating with it.
2020-12-30 10:22:45 -06:00
Calvin Rose ab37ee6ebb Add :all option to ev/read.
Brings ev/read more in line with file/read.
2020-12-29 20:37:59 -06:00
Calvin Rose 8655530b19 Rename predicates in module/paths 2020-12-29 19:52:26 -06:00
Calvin Rose 27b1f59aa9 Change Ctrl-C and move old behavior to Ctrl-Q
This lets Janet be a better unix citizen and lets Ctrl-C
raise an interrupt. Trying to make Janet behave superficially
like a shell by overriding Ctrl-C is not helpful.
2020-12-29 16:20:37 -06:00
Calvin Rose cc2cc4db43
Merge pull request #541 from sogaiu/match-doc-formatting
Tweak match docstring
2020-12-29 13:10:35 -06:00
Calvin Rose 20bcd95279 Merge commit '0ea77cabfb30afc15433581f5888171c1f65aafd' 2020-12-28 12:20:21 -06:00
Calvin Rose d7954be5e5 Update docstring for os/open. 2020-12-28 11:00:15 -06:00
Felix Riedel 0ea77cabfb Tweak sort: use insertion sort for small arrays 2020-12-28 16:06:48 +00:00
Felix Riedel 0d46352ff4 Revert to better performing number hash. 2020-12-27 14:05:40 +00:00
sogaiu ffa0d5fe45 Tweak match docstring 2020-12-27 13:42:22 +09:00
Calvin Rose a2c837a99c Merge remote-tracking branch 'felixr/master' into master 2020-12-26 20:06:34 -06:00
Calvin Rose 13d8d11011 Try new number hashing with frexp.
This may be a bit slower in some cases but generally should
have much better hashing for numbers.
2020-12-26 16:54:14 -06:00
Calvin Rose 2357b6162f Update test-install target. 2020-12-26 15:42:13 -06:00
Calvin Rose b4f242193d Improve hash function for numbers. 2020-12-26 15:38:04 -06:00
Calvin Rose 7242ee0186
Merge pull request #540 from felixr/better-quicksort
Improve quicksort to avoid worst case performance on sorted input
2020-12-26 15:23:01 -06:00
Felix Riedel 3e742ffc4c Improve quicksort to avoid worst case performance.
The current implementation will have quadratic behaviour for already
sorted arrays because it picks the last element as pivot. In an sorted
array this splits the array repeatedly into the biggest value and all
other values.

The implementation in this commit uses the *median of three* as pivot.

`janet -e "(sort (range 10000))"` to reproduce quadratic behaviour.
2020-12-26 19:18:17 +00:00
Felix Riedel 2ec12fe06f Improve hashing of numbers
Using an integer hash (https://stackoverflow.com/a/12996028/60617) on
the number casted to int32 combined with lower bits of the number.
2020-12-26 13:09:11 +00:00
Felix Riedel c76e0ae685 Use boost's way of combining hash values for arrays and kv pairs.
`seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);`
from https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html

The current way of combining hashes peforms poorly on hash values of
numbers. Changing the way hashes are combined canlead to a significant speed up:

```
time janet_new -e '(def tbl @{}) (loop [x :in (range 1000) y :in (range 1000)] (put tbl {0 x 1 y} true))'
3.77s user 0.08s system 99% cpu 3.843 total

time janet_orig -e '(def tbl @{}) (loop [x :in (range 1000) y :in (range 1000)] (put tbl {0 x 1 y} true))'
48.98s user 0.15s system 99% cpu 49.136 total
```
2020-12-26 13:05:03 +00:00
Calvin Rose 25ded775ad Add array/clear.
Also improve map, find-index, and find to work on data structures
which do not defined length.
2020-12-18 12:37:58 -06:00
Calvin Rose cae4f19629
Merge pull request #532 from pyrmont/feature.parser-line-col-setting
Update (parser/where) to support optional line and column
2020-12-15 19:03:25 -06:00
Michael Camilleri 04f6c7b156
Clarify docstring of parser/where 2020-12-15 16:41:45 +09:00
Michael Camilleri 77b79e9899
Update (parser/where) to support optional line and column 2020-12-15 14:12:33 +09:00
Calvin Rose a55354357c Make dofile error if source file errors.
This should make dofile a bit easier to use.
It also means that import properly raises errors when
things go bad.
2020-12-14 08:23:06 -06:00
Calvin Rose 392d5d51df Fix build info for 1.13.1 2020-12-13 11:59:52 -06:00
Calvin Rose 9bc996a630 Prepare for 1.13.0 initial release. 2020-12-13 11:17:10 -06:00
Calvin Rose 7b709d4c68 Prevent buffer/trim from shrinking buffer to 0 bytes as well. 2020-12-13 09:38:35 -06:00
Calvin Rose eab5f67c5c Fix buffer with NULL data pointer issue.
Simply prevent buffers from ever having a NULL data pointer.
2020-12-13 09:33:57 -06:00
Calvin Rose 6020106000 Address #529 2020-12-11 19:21:54 -06:00
Calvin Rose 12f470ed10 Use :_name instead of :name for printing tagged tables. 2020-12-11 18:28:09 -06:00
Calvin Rose 945cbcfad6 Tail recursive match implementation.
This implementation uses multiple passes on patterns
to remove the need for a sentinel value to check if there was a match.
This also re-uses extracted subpatterns for complicated patterns.
2020-12-10 08:35:34 -06:00
Calvin Rose d53007739e Invert read/write bits on pipe in os/execute.
It was backwards, breaking this functionality.
2020-12-09 19:04:05 -06:00
Calvin Rose 6eaf8272e1
Merge pull request #525 from uvtc/patch-1
light markup in some docs in corelib
2020-12-07 15:57:09 -06:00
Calvin Rose 6fb83dce06
Merge pull request #526 from sogaiu/tweak-comment
Tweak comment for janet_fiber_popframe
2020-12-07 15:56:25 -06:00
John Gabriele 52addc877d
Use `xs` 2020-12-07 14:07:13 -05:00
sogaiu 53a5f3d2dc Tweak comment for janet_fiber_popframe 2020-12-07 12:23:27 +09:00
Calvin Rose 711ee5a36d Merge branch 'preload' 2020-12-06 21:06:59 -06:00
Calvin Rose cd09b696b5 Add :preload loader. 2020-12-06 21:06:17 -06:00
John Gabriele df1ca255a9
parts/xs --> pieces 2020-12-06 21:29:30 -05:00
Calvin Rose 811a5d93f4 Prevent some potential bad characters in test out. 2020-12-06 17:10:18 -06:00
John Gabriele adbe361b9b
light markup in some docs in corelib 2020-12-06 17:51:48 -05:00
Calvin Rose 0f16f21677 Make builds deterministic again.
Also prevent marshal from creating multiple copies of
a function - (marshal function pointer before function def pointer).
2020-12-06 16:32:23 -06:00
Calvin Rose aa0de01e5f Fix some formatting and undefined behavior. 2020-12-06 14:33:08 -06:00
Calvin Rose 785757f2f6 Remove pthreads from shell.c and update bsd build. 2020-12-06 13:51:06 -06:00
Calvin Rose 01120dfc46 Try and fix openbsd st.ht build.
Oneline meson configs, remove extra `cd janet`.
2020-12-06 11:57:40 -06:00
Calvin Rose a119eb4ef0 Merge branch 'master' of github.com:janet-lang/janet 2020-12-06 11:47:46 -06:00
Calvin Rose 0aa4c3d217 Consolidate sr.ht builds to 1-per-platform.
This generally makes more sense from an infrastructure
point of view and works around 4 builds per push limit of sr.ht.
2020-12-06 11:46:45 -06:00
Calvin Rose 3c0cc59d77 Rename some srht build files. 2020-12-06 11:22:35 -06:00
Calvin Rose 7e1d095996
Merge pull request #522 from pyrmont/docs.keep-docstring
Clarify description of keep
2020-12-05 14:31:58 -06:00
Calvin Rose cfa9fb6ee4 Update changelog. 2020-12-05 10:36:27 -06:00
Calvin Rose 9d23192614 Add ev/deadline and ev/with-deadline.
This should be more useful than timeouts in real-world
use cases. The deadline system is based on fibers and is target
to much more coarse-grained (and therfor reliable) timeouts than things
like ev/sleep and timeout arguments.
2020-12-05 10:32:34 -06:00
Michael Camilleri 7c1a52ae65
Use 'different from' in preference to 'different to' 2020-12-05 16:43:44 +09:00
Michael Camilleri 9aa1b9c740
Clarify description of keep 2020-12-05 16:02:36 +09:00
Calvin Rose c4a4916055 Address #500 - update docs and add buffer/push
This updates the documentation and adds a function buffer/push, which
is a more useful function than buffer/push-string or buffer/push-byte by
combining both.
2020-12-04 17:56:47 -06:00
Calvin Rose b402e0671a
Merge pull request #514 from uvtc/patch-2
boot.janet, fix possible typo
2020-12-04 17:40:46 -06:00
Calvin Rose 8144f83b66
Merge pull request #516 from uvtc/patch-4
doc for identity
2020-12-04 17:40:31 -06:00
Calvin Rose cd2a55e268
Merge pull request #513 from uvtc/patch-1
boot.janet, cond doc
2020-12-04 17:38:02 -06:00
Calvin Rose f92b5d69c8
Merge pull request #515 from uvtc/patch-3
C-style (hyphenate)
2020-12-04 17:37:24 -06:00
Calvin Rose a8c21459c3
Merge pull request #517 from uvtc/patch-5
boot.janet, compare*, light formatting
2020-12-04 17:37:06 -06:00
Calvin Rose 4789b4c9f3
Merge pull request #520 from uvtc/patch-6
corelib.c, describe, add hyphen
2020-12-04 17:31:15 -06:00
Calvin Rose ee1cd6f151
Merge pull request #521 from sogaiu/parser-with-a-colon
Minor tweak in changelog
2020-12-04 17:30:59 -06:00
sogaiu dfcda296a3 Minor tweak in changelog 2020-12-02 17:52:29 +09:00
John Gabriele 4d38fcb289
corelib.c, describe, add hyphen 2020-12-01 11:56:53 -05:00
Calvin Rose cbdea8f331 Make os/execute cooperate with ev module.
os/execute, os/proc-wait do not block (currently posix only).
This uses the self-pipe trick to turn signals into a pollable entity.
2020-11-29 15:36:21 -06:00
John Gabriele 51d6a13510
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:31:01 -05:00
John Gabriele 7b4eeecd9f
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:30:48 -05:00
John Gabriele 82eff7e082
Update src/boot/boot.janet
Agreed. That's more clear.

Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:30:26 -05:00
John Gabriele b922e36071
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:18:19 -05:00
John Gabriele 7c75aeaad2
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:17:38 -05:00
John Gabriele 2db9323671
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:17:23 -05:00
John Gabriele 31ae93de19
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:17:12 -05:00
John Gabriele a81e9f23f0
Update src/boot/boot.janet
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:16:55 -05:00
John Gabriele 59f09a4386
Update src/boot/boot.janet
omit needless word

Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-11-29 14:15:55 -05:00
John Gabriele 53400ecac1
boot.janet, compare*, light formatting
Since those represent code, they should get backticks.
2020-11-28 14:41:42 -05:00
John Gabriele 1b8928a8ec
doc for identity
This function only takes one argument anyway, and errors if you try to pass more.
2020-11-28 14:35:17 -05:00
John Gabriele e706494893
C-style 2020-11-28 14:29:13 -05:00
John Gabriele 894aea7ce7
boot.janet, fix possible typo
Possible typo?
2020-11-28 14:25:10 -05:00
John Gabriele 87167a21c9
boot.janet, cond doc
Arranged this way seems to make more sense.
2020-11-28 14:18:35 -05:00
Calvin Rose 7c8f5ef811 Merge branch 'master' of github.com:janet-lang/janet 2020-11-28 12:18:51 -06:00
Calvin Rose 7aa4241662 Add testing for the new reindent behavior.
This also provides a reference function to reimplement
the behavior in Janet.
2020-11-28 12:18:36 -06:00
Calvin Rose 56a915b5b1 Long strings now autoindent contents - doc-format is simpler.
No need to try and auto detect the base indentation - it is 0.
This will be taken care of by the parser.
2020-11-28 10:04:25 -06:00
Calvin Rose 90a0dfa35f
Merge pull request #512 from timgates42/bugfix_typo_source
docs: fix simple typo, soucre -> source
2020-11-27 16:54:34 -06:00
Tim Gates 128d72785f
docs: fix simple typo, soucre -> source
There is a small typo in src/core/features.h.

Should read `source` rather than `soucre`.
2020-11-28 09:45:46 +11:00
Calvin Rose 21a6017547 typo 2020-11-27 12:27:44 -06:00
Calvin Rose a0964d44d5 Fix some valgrind errors.
A null pointer dereference and a memory leak with the line/col mapping.
2020-11-27 12:21:23 -06:00
Calvin Rose fb0859dfe6 Merge remote-tracking branch 'pyrmont/feature.markdown-docstrings' into longstring-autoindent 2020-11-27 12:13:45 -06:00
Calvin Rose dadd6037bb Merge branch 'master' into longstring-autoindent 2020-11-27 10:40:10 -06:00
Michael Camilleri 6f3eff3258
Add example docstring 2020-11-27 18:29:41 +09:00
Michael Camilleri 02224d5aa9
Fix bugs in parsing logic 2020-11-27 18:28:58 +09:00
Calvin Rose bfd2845077 Add merge-module to core.
This is a little utility used for manually importing modules.
It is responsible for taking the output of dofile, run-context, or
require and merging into another environment as if import was called.
2020-11-27 00:16:54 -06:00
Michael Camilleri ba2e0489e6
Add initial implementation of docstring formatter 2020-11-27 15:07:38 +09:00
Calvin Rose ca7c5b8b10 ev/call uses current env as prototype of environment. 2020-11-26 21:13:41 -06:00
Calvin Rose 6c43489fb2 Fix #508 - nil fiber environment.
run-context did not handle a nil environment well, so that was fixed
and ev/call inherits the environment when creating the fiber.
2020-11-26 19:04:45 -06:00
Calvin Rose d76f671d37 Update changelog and make arg to peg's error optional. 2020-11-26 18:57:24 -06:00
Calvin Rose 776ce586bc Add line and column combinators to peg.
These capture the line and column number of the current position
in the matched text. This is useful for error reporting as well
as indentation checking.

This works by lazily creating an index on first use that stores all
newline character indices in order. We can then do a binary search on
this to get both line number and column number in log(n) time.
This is good enough for most use cases and doesn't slow down the common case at all
- these will not be commonly used patterns in a hot loop so it is not worth to try and
optimize this at all. Constant time look up should be possible but at
the cost of complicating code and slowing down all matching to check for
new lines.
2020-11-26 18:32:56 -06:00
Calvin Rose adc3066dc8 Update doc-format and boot.janet docstrings.
Make doc-format respect leading indents, increase the default format
width to better accommodate markdown formatted documentation. We still
need to support single line style doc strings, such as those used
for most c functions which can be a single line of much longer than
80 or 120 characters.

Consecutive whitespace internal to lines is not preserved, though.
2020-11-26 14:58:36 -06:00
Calvin Rose 7fd2da1096 Add code in parser to automatically indent long strings.
Leading spaces are stripped based on the column index of the first
backtick character in the first delimiter. If there are
characters that are not newline or space before that column in the
string, then the behavior is the same as the old behvaior - no
re-indentation is performed.
2020-11-26 13:20:58 -06:00
Calvin Rose 451340e4c0 Update docstrings in boot.janet (#506)
Elaborate on usage of reduce and accumulate.
2020-11-26 10:34:51 -06:00
Calvin Rose a3e812b86d Fix #505 - bat int64 parsing.
Fixes an off-by-1 error.

Also makes windows testing hopefully a bit less flaky.
2020-11-25 09:45:46 -06:00
Calvin Rose a3f98091c4 Fix #509
janet_fiber returns NULL if there is a bad arity, check that before
continuing.
2020-11-23 15:28:28 -06:00
Calvin Rose 6720b34868 Don't use peg for patch tool. 2020-11-18 19:37:18 -06:00
Calvin Rose 781ed0dc67 Merge branch 'master' of github.com:janet-lang/janet 2020-11-18 19:36:12 -06:00
Calvin Rose 8f00848c7b Fix build issues on windows by using a size_t instead of int. 2020-11-18 19:31:20 -06:00
Calvin Rose 53aa19a916 Several changes to move pipe creation back into ev.c 2020-11-18 10:53:36 -06:00
Calvin Rose 2dc04d2957 On install, merge janetconf.h into janet.h
This results in a cleaner amalgmated build
2020-11-17 09:53:12 -06:00
Calvin Rose 306bdee673 Merge branch 'master' of github.com:janet-lang/janet 2020-11-16 18:47:28 -06:00
Calvin Rose cff52ded58 Add JANET_ASYNC_EVENT_CANCEL
also fix bug that could cause event loop to hang.
2020-11-16 18:46:59 -06:00
Calvin Rose fbe658a724
Merge pull request #503 from sogaiu/boot-janet-docstring-tweaks
Tweak docstrings in boot.janet
2020-11-16 17:03:54 -06:00
Calvin Rose f9d0eb47b7 Merge branch 'master' of github.com:janet-lang/janet 2020-11-16 16:51:29 -06:00
Calvin Rose 078f50d45a When reading from a stream, EPIPE is considered EOS.
Before, EPIPE caused an error, but in most cases it is better
to consider it an end of stream. In the future, we may want to allow
cusomtization of this behavior with flags on the stream but for now
let's keep it simpler.
2020-11-16 16:49:27 -06:00
Calvin Rose 974a45c804 When reading from a stream, EPIPE is considered EOS.
Before, EPIPE caused an error, but in most cases it is better
to consider it an end of stream. In the future, we may want to allow
cusomtization of this behavior with flags on the stream but for now
let's keep it simpler.
2020-11-16 16:42:09 -06:00
Calvin Rose 760e4e3d68 Add upscope special form.
Upscope is similar to do, but does not introduce a new lexical scope.
2020-11-16 16:41:27 -06:00
Calvin Rose 9ec5689d6b Don't use gcroot/unroot for tracking IO operations.
This could have bad effects in higher load situations, and
duplicates code. It is better to keep a dedicated list of
scheduled IO operations which can be efficiently added and
removed from. It also provides and easy way to enumerate
scheduled IO operations.
2020-11-16 09:30:04 -06:00
sogaiu c8b72431a3 Some more 2020-11-16 16:13:28 +09:00
sogaiu 0eb913fb9a A couple more tweaks 2020-11-16 14:14:51 +09:00
sogaiu fce27cb2e8 Tweak docstrings in boot.janet 2020-11-16 14:03:26 +09:00
Calvin Rose 1b6272db2e Fix windows ifdef. 2020-11-15 19:55:58 -06:00
Calvin Rose b1c0ad5e42 CD into source directory in build recipe. 2020-11-15 19:50:33 -06:00
Calvin Rose 3f7cdcb6a7 Add meson test build for epoll. 2020-11-15 19:47:11 -06:00
Calvin Rose a25b030e36 Fix EPOLL implementation. 2020-11-15 19:40:47 -06:00
Calvin Rose 717fac02d1 Update janet.h for janet_thread_current 2020-11-15 16:12:02 -06:00
Calvin Rose dcf8ba0edb Update CHANGELOG.md 2020-11-15 15:35:50 -06:00
Calvin Rose 3ab2ae130b Address #495 Add :read and :parser to run-context. 2020-11-15 15:26:16 -06:00
Calvin Rose 6e6900fa3a os/execute and os/spawn can take streams. 2020-11-15 12:17:29 -06:00
Calvin Rose d7af4596e1 Move math.h include out of windows ifdef 2020-11-15 10:21:37 -06:00
Calvin Rose 1759151875 Change suite 9 test a bit. 2020-11-15 10:12:10 -06:00
Calvin Rose a7ed3dea4b Remove some flags in os/open. 2020-11-15 10:06:20 -06:00
Calvin Rose cdcb774dc8 Add os/pipe and os/open.
ev/pipe -> os/pipe, and os/open is a wrapper
around the open system call.
2020-11-15 09:57:29 -06:00
Calvin Rose d199c817dc Broken Pipe error on windows should just be end of stream. 2020-11-14 16:03:51 -06:00
Calvin Rose dc51bd09f7 Make sure all test logs go to the same stream. 2020-11-14 15:56:48 -06:00
Calvin Rose 139e3fab25 Invert status check for (Read/Write)File 2020-11-14 15:52:01 -06:00
Calvin Rose 7a98f9aa02 Improve windows error messages on write failures. 2020-11-14 15:48:21 -06:00
Calvin Rose b53dd67e74 Use custom pipe implementation for overlapped io. 2020-11-14 15:44:19 -06:00
Calvin Rose e546731093 ev_lasterr -> janet_ev_lasterr 2020-11-14 15:24:13 -06:00
Calvin Rose d50c4ef6da Try again for windows build. 2020-11-14 15:01:52 -06:00
Calvin Rose 7d0b1955a2 typo 2020-11-14 14:55:26 -06:00
Calvin Rose 16cf7681f0 Fix some windows issues. 2020-11-14 14:40:39 -06:00
Calvin Rose 12f09ad2d7 Add ev/pipe and move stream code into ev.c
Also adds a lot to the C API and changes things up.
2020-11-14 14:29:11 -06:00
Calvin Rose b3e88a8d80 Move read/write functions into ev.c from net.c
This code can also be used for non-network streams.
2020-11-14 11:48:23 -06:00
Calvin Rose 761273bcc4 Add janet_thread_current() to C api. 2020-11-12 18:42:41 -06:00
Calvin Rose 1a75f68cb2 Fix windows build. 2020-11-12 14:52:02 -06:00
Calvin Rose 1b0edf54f1 Fix gc leak.
Rather than trying to be clever with pinning/unpinning, always
mark the root fiber and that should serve as thei singular common root in almost
all cases.
2020-11-12 14:29:38 -06:00
Calvin Rose caa6576719 Fix formatting. 2020-11-11 15:35:44 -06:00
Calvin Rose 93bd2c11fa
Merge pull request #502 from pepe/fix-net-server-fiber
Fix net server fiber
2020-11-11 15:33:42 -06:00
Josef Pospíšil 2be09790a9 Change fix with ev/call 2020-11-10 10:39:33 +01:00
Josef Pospíšil bf6eae711a Fix adding handler to loop with fiber 2020-11-10 10:32:47 +01:00
Calvin Rose 69b68c0091 Update changelog. 2020-11-09 11:24:28 -06:00
Calvin Rose 6f1d5d3b73 Add net/listen and net/accept-loop.
These are the elements that make up net/server, which has been moved
into pure Janet instead.
2020-11-09 11:18:09 -06:00
Calvin Rose 099a912992 Fix posix regression. 2020-11-08 19:48:44 -06:00
Calvin Rose 56b1ea3726 Include math.h to fix some bugs on 32 bit windows. 2020-11-08 19:06:35 -06:00
Calvin Rose d6391f2d70 Get windows IOCP working for accept.
This also changes the api of servers slightly -
in light of having support for ev tasks, it is probably better
to remove the "simple" server code and replace it with some Janet
or remove it all together. While convenient, it has issues with error
handling and rigidity.
2020-11-08 18:56:13 -06:00
Calvin Rose 07910272e2 Get socket reads and writes working with IOCP. 2020-11-08 10:38:28 -06:00
Calvin Rose 1092013c2b Merge branch 'master' into ev 2020-11-07 14:36:25 -06:00
Calvin Rose 0db83bd787
Merge pull request #498 from pepe/fix-asm-example
Fix asm example
2020-11-07 14:35:39 -06:00
Calvin Rose f55316eabc
Merge pull request #494 from harryvederci/patch-1
Fix typo
2020-11-07 14:34:43 -06:00
Calvin Rose 840f59934e
Merge pull request #497 from ahungry/bugfix/Adjust-popen-doc
Fix function doc to match that of C POPEN
2020-11-07 14:34:11 -06:00
Calvin Rose 75a9c59ad8
Merge pull request #499 from sogaiu/disasm-doc-typo
Tweak disasm doc
2020-11-07 14:33:53 -06:00
sogaiu adfccd33ae Tweak disasm doc 2020-11-05 13:56:42 +09:00
Josef Pospíšil 9d41243c15 Fix comments formating 2020-11-04 10:18:31 +01:00
Josef Pospíšil e33e182eb0 Fix assembly example 2020-11-04 10:16:02 +01:00
Matthew Carter 4dffd662f0 Fix function doc to match that of C POPEN
It may be misleading to some user to believe it is taking a path to a
file, when it is executing an arbitrary shell command for the first argument.
2020-11-03 20:52:02 -05:00
Calvin Rose 5064d579d4 Add net header instead of ifdef check. 2020-11-03 17:49:09 -06:00
Calvin Rose 540425a41b Make docstring less confusing - Fix #493. 2020-11-02 09:09:22 -06:00
Calvin Rose 4d21b582c7 Improve reading and writing from streams.
Handle errors earlier, and allow 0 length packets from UDP
but not from TCP. This should more closely follow the exact specs
of send and recv calls.
2020-11-02 09:06:31 -06:00
Calvin Rose f288bc1790
Merge pull request #492 from drkameleon/master
Copy editing & fixing typos
2020-11-02 08:29:49 -06:00
Calvin Rose 8942e348bd Small change to windows ev. 2020-11-02 08:27:45 -06:00
Calvin Rose 9f27336827 Update windows ev code. 2020-11-02 08:19:53 -06:00
Calvin Rose f517cccf7b Fix unix domain sockets.
Also allow abstract unix domain sockets on Linux
(prefixed with '@' as is customary).
2020-11-02 08:16:28 -06:00
Harry Prins 3a937ace51
Fix typo 2020-10-29 08:45:04 +00:00
Yanis Zafirópulos b8661f8bff
Update README.md
Co-authored-by: Michael Camilleri <mike@inqk.net>
2020-10-26 16:21:06 +01:00
Yanis Zafirópulos 51828ab5f8
Copy editing :) 2020-10-26 14:46:31 +01:00
Yanis Zafirópulos 84fe5d7f34
Copy editing :) 2020-10-26 14:44:17 +01:00
Calvin Rose 2891d2b260 Address #489
Add gc pressure when resizing fiber stack.
2020-10-18 18:41:18 -05:00
Calvin Rose edfb861a5f Disable epoll by default for evloop. 2020-10-11 15:05:27 -05:00
Calvin Rose 88c1cf3ee7 Reformat files. 2020-10-11 09:33:07 -05:00
Calvin Rose 813e3fdcfd Merge branch 'windows-ev' into ev 2020-10-11 09:32:17 -05:00
Calvin Rose bbe10e4938 Add another select example. 2020-10-11 09:14:31 -05:00
Calvin Rose cb4903fa86 Overhaul of poll loop, redo ev/select. 2020-10-11 09:14:14 -05:00
Calvin Rose ea45165db8 Merge branch 'master' into ev 2020-10-10 09:04:05 -05:00
Calvin Rose 1fba699ed4 Merge branch 'master' of github.com:janet-lang/janet into master 2020-10-08 12:35:16 -05:00
Calvin Rose ce3d574c41 Update docstring. 2020-10-08 12:34:08 -05:00
Calvin Rose 7a601a7eb2
Merge pull request #481 from sogaiu/remove-namespace-reference
Use "module" instead of "namespace" in docstring
2020-10-07 17:43:56 -05:00
sogaiu 9ec66ab826 Use "module" instead of "namespace" in docstring 2020-10-07 18:18:28 +09:00
Calvin Rose ebfa07f8ce Registering an abstract type is idemptotent. 2020-10-06 19:11:29 -05:00
Calvin Rose 964a800d51 More work on windows event loop code. 2020-10-06 19:07:29 -05:00
Calvin Rose 5c05dec65a
Merge pull request #479 from andrewchambers/mf
Add missing Makefile dependencies for install.
2020-10-06 18:26:16 -05:00
Andrew Chambers bf6ebc4a68 Add missing Makefile dependencies for install. 2020-10-07 10:19:49 +13:00
Calvin Rose 2e944931b3 Update timestamp function to work on windows. 2020-10-04 15:18:31 -05:00
Calvin Rose db67538311 Work on getting ev support on windows. 2020-10-04 12:46:15 -05:00
Calvin Rose 307c7e00e2 Merge branch 'master' into ev 2020-10-03 11:09:21 -05:00
Calvin Rose 45feb55483 Add integer parsing to pegs. 2020-09-27 12:19:00 -05:00
Calvin Rose 0a1d902f46 Fix #477
Make the walk function preserve bracket type, which should fix
threading macro behavior when threading into bracketed expressions.
2020-09-26 13:28:29 -05:00
Calvin Rose 959a577b5f Merge branch 'master' into ev 2020-09-26 11:50:13 -05:00
Calvin Rose 95f4bd8e23 Merge branch 'master' into ev 2020-09-13 11:24:27 -05:00
Calvin Rose d3182dce51 Merge branch 'master' into ev 2020-09-12 10:02:01 -05:00
Calvin Rose 191d0001f4 Add header on BSDs. 2020-09-07 15:22:18 -05:00
Calvin Rose 1a04ce33f1 Conditionally include epoll headers. 2020-09-07 13:13:28 -05:00
Calvin Rose babfe50550 Merge branch 'master' into ev
Also add poll implementation for ev.
2020-09-07 12:52:50 -05:00
Calvin Rose 17d0b7a985 Improve import's handling of non constant args.
Be much more conservative about which arguments are cast to strings.
2020-08-27 07:40:51 -05:00
Calvin Rose 86e00e865e Merge branch 'master' into ev 2020-08-23 11:25:04 -05:00
Calvin Rose 30522bbf7d Merge branch 'master' into ev 2020-08-16 17:52:36 -05:00
Calvin Rose fb26c9b2c4 Add ev/select and ev/rselect initial implementation.
Getting closer to a CSP implmententation. Probably
useful to move scheduling fields outside of fibers
and into an external table.
2020-08-09 00:20:27 -05:00
Calvin Rose 78ffb63429 Disallow mutlitple state machines waiting for a single fiber.
A 'select' operator will be channel based, not state machine based.
2020-08-08 07:51:46 -05:00
Calvin Rose 1213990b7d Merge branch 'master' into ev 2020-08-07 19:51:37 -05:00
Calvin Rose cb898fabf4 Set default channel size to 0. 2020-08-03 07:57:02 -05:00
Calvin Rose 5899671d96 Merge branch 'master' into ev 2020-08-03 07:54:53 -05:00
Calvin Rose 742c5bb639 Use a common queue implementation.
Queues occur in three places, so we use a single
implementation rather than three separate ones. This also
has the result that janet_vm_spawn will not overflow in the case
of channel-heavy, IO-light operation.
2020-08-01 14:20:58 -05:00
Calvin Rose 297de01d95 Add preliminary channel implementation. 2020-08-01 13:13:58 -05:00
Calvin Rose 2eb2dddb59 Begin work on channels. 2020-07-26 23:45:25 -05:00
Calvin Rose 0403e306ed Silence warnings from some compilers. 2020-07-26 08:48:22 -05:00
Calvin Rose d393fbf360 Merge branch 'master' into ev 2020-07-25 14:07:47 -05:00
Calvin Rose 3960d0f6de Merge branch 'master' into ev 2020-07-25 13:17:05 -05:00
Calvin Rose 553b4d9428 Add timeouts to net functions.
Further debugging of the general timeout system, as well
as having a single fiber wait on multiple state machines (select).
2020-07-19 19:41:12 -05:00
Calvin Rose df145f4bc9 Merge branch 'master' into ev 2020-07-19 17:20:43 -05:00
Calvin Rose cd197e8be3 Add ev/call.
This is a common operation, and making fibers manually can be tedious.
2020-07-06 19:13:32 -05:00
Calvin Rose 51cf6465ff Merge branch 'master' into ev 2020-07-06 17:22:38 -05:00
Calvin Rose bd95f742c0 Merge branch 'master' into ev 2020-07-05 23:14:49 -05:00
Calvin Rose 9ba94d2c6b More work on timeouts and racing listeners.
When two listeners are racing to resume the same fiber, the
first should cancel out the other.
2020-07-05 17:26:17 -05:00
Calvin Rose a4de83b3a3 Merge branch 'master' into ev 2020-07-05 10:11:23 -05:00
Calvin Rose 37a430c97c Move declarations around. 2020-07-03 13:47:48 -05:00
Calvin Rose f264cb0b18 Merge branch 'master' into ev 2020-07-03 12:26:01 -05:00
Calvin Rose a0abf307b4 Merge branch 'master' into ev 2020-07-03 12:14:48 -05:00
Calvin Rose 328ee94412 Merge branch 'master' into ev 2020-06-22 22:25:44 -05:00
Calvin Rose b1a4f05b5a Explicitly disallow handler for datagram server. 2020-06-13 08:29:48 -05:00
Calvin Rose ce2079104a Merge branch 'master' into ev 2020-06-11 19:20:51 -05:00
Calvin Rose d64e9b6263 Remove snapcraft. 2020-06-06 10:31:16 -05:00
Calvin Rose 123710078d Add unix domain socket support to net.
Code is a bit messy, as getaddrinfo does not support
unix domain sockets directly. We require a keyword :unix
instead of the usual hostname string, and the port is the
path to unix domain socket. The UDS should support both stream
and datagram sockets.
2020-06-03 00:53:17 -05:00
Calvin Rose ec0d0ba368 Initial UDP implementation. 2020-06-02 19:47:50 -05:00
Calvin Rose 3f434f2a44 Add backpressure capability to net. 2020-05-31 15:46:01 -05:00
Calvin Rose 71d8e6b4cd Merge branch 'master' into ev 2020-05-30 11:35:19 -05:00
Calvin Rose a78af0a7fb Do not explicitly free state machines, instead return a status.
This makes it harder to have some kind of use after free issue.
2020-05-30 11:31:05 -05:00
Calvin Rose 117ae196fd Add net/flush.
Useful for simple TCP protocols (netrepl), which benefit from being able
to immediately send a message.
2020-05-28 19:22:38 -05:00
Calvin Rose 4c211c8dce More updates to the ev library. 2020-05-28 16:51:11 -05:00
Calvin Rose c10d9b9d9d Merge branch 'master' into asyncio 2020-05-28 10:57:10 -05:00
Calvin Rose b68b0a256e Start with ev module. 2020-05-28 10:39:40 -05:00
174 changed files with 25110 additions and 12052 deletions

View File

@ -1,4 +1,4 @@
image: freebsd/12.x
image: freebsd/14.x
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
@ -9,4 +9,4 @@ tasks:
gmake
gmake test
sudo gmake install
gmake test-install
sudo gmake uninstall

21
.builds/linux.yml Normal file
View File

@ -0,0 +1,21 @@
image: archlinux
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- meson
tasks:
- with-epoll: |
cd janet
meson setup with-epoll --buildtype=release
cd with-epoll
meson configure -Depoll=true
ninja
ninja test
- no-epoll: |
cd janet
meson setup no-epoll --buildtype=release
cd no-epoll
meson configure -Depoll=false
ninja
ninja test
sudo ninja install

View File

@ -1,14 +0,0 @@
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

View File

@ -1,15 +0,0 @@
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

View File

@ -1,22 +0,0 @@
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

View File

@ -1,12 +1,32 @@
image: openbsd/latest
image: openbsd/7.4
sources:
- https://git.sr.ht/~bakpakin/janet
packages:
- gmake
- meson
tasks:
- build: |
- gmake: |
cd janet
gmake
gmake test
doas gmake install
gmake test-install
doas gmake uninstall
- meson_min: |
cd janet
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
cd build_meson_min
ninja
- meson_prf: |
cd janet
meson setup build_meson_prf --buildtype=release -Dprf=true
cd build_meson_prf
ninja
ninja test
- meson_default: |
cd janet
meson setup build_meson_default --buildtype=release
cd build_meson_default
ninja
ninja test
doas ninja install

3
.gitattributes vendored
View File

@ -1,5 +1,4 @@
*.janet linguist-language=Clojure
*.janet linguist-language=Janet
*.janet text eol=lf
*.c text eol=lf
*.h text eol=lf

38
.github/cosmo/build vendored Normal file
View File

@ -0,0 +1,38 @@
#!/bin/sh
set -eux
COSMO_DIR="/sc/cosmocc"
# build x86_64
X86_64_CC="/sc/cosmocc/bin/x86_64-unknown-cosmo-cc"
X86_64_AR="/sc/cosmocc/bin/x86_64-unknown-cosmo-ar"
mkdir -p /sc/cosmocc/x86_64
make -j CC="$X86_64_CC" AR="$X86_64_AR" HAS_SHARED=0 JANET_NO_AMALG=1
cp build/janet /sc/cosmocc/x86_64/janet
make clean
# build aarch64
AARCH64_CC="/sc/cosmocc/bin/aarch64-unknown-cosmo-cc"
AARCH64_AR="/sc/cosmocc/bin/aarch64-unknown-cosmo-ar"
mkdir -p /sc/cosmocc/aarch64
make -j CC="$AARCH64_CC" AR="$AARCH64_AR" HAS_SHARED=0 JANET_NO_AMALG=1
cp build/janet /sc/cosmocc/aarch64/janet
make clean
# fat binary
apefat () {
OUTPUT="$1"
OLDNAME_X86_64="$(basename -- "$2")"
OLDNAME_AARCH64="$(basename -- "$3")"
TARG_FOLD="$(dirname "$OUTPUT")"
"$COSMO_DIR/bin/apelink" -l "$COSMO_DIR/bin/ape-x86_64.elf" \
-l "$COSMO_DIR/bin/ape-aarch64.elf" \
-M "$COSMO_DIR/bin/ape-m1.c" \
-o "$OUTPUT" \
"$2" \
"$3"
cp "$2" "$TARG_FOLD/$OLDNAME_X86_64.x86_64"
cp "$3" "$TARG_FOLD/$OLDNAME_AARCH64.aarch64"
}
apefat /sc/cosmocc/janet.com /sc/cosmocc/x86_64/janet /sc/cosmocc/aarch64/janet

21
.github/cosmo/setup vendored Normal file
View File

@ -0,0 +1,21 @@
#!/bin/sh
set -e
sudo apt update
sudo apt-get install -y ca-certificates libssl-dev\
qemu qemu-utils qemu-user-static\
texinfo groff\
cmake ninja-build bison zip\
pkg-config build-essential autoconf re2c
# download cosmocc
cd /sc
wget https://github.com/jart/cosmopolitan/releases/download/3.3.3/cosmocc-3.3.3.zip
mkdir -p cosmocc
cd cosmocc
unzip ../cosmocc-3.3.3.zip
# register
cd /sc/cosmocc
sudo cp ./bin/ape-x86_64.elf /usr/bin/ape
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"

41
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "2 7 * * 4"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ cpp ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

89
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,89 @@
name: Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: read
jobs:
release:
permissions:
contents: write # for softprops/action-gh-release to create GitHub release
name: Build release binaries
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest ]
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Set the version
run: echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
- name: Set the platform
run: echo "platform=$(tr '[A-Z]' '[a-z]' <<< $RUNNER_OS)" >> $GITHUB_ENV
- name: Compile the project
run: make clean && make
- name: Build the artifact
run: JANET_DIST_DIR=janet-${{ env.version }}-${{ env.platform }} make build/janet-${{ env.version }}-${{ env.platform }}-x64.tar.gz
- name: Draft the release
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
build/*.gz
build/janet.h
build/c/janet.c
build/c/shell.c
release-windows:
permissions:
contents: write # for softprops/action-gh-release to create GitHub release
name: Build release binaries for windows
runs-on: windows-latest
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Build the project
shell: cmd
run: build_win all
- name: Draft the release
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
./dist/*.zip
./*.zip
./*.msi
release-cosmo:
permissions:
contents: write # for softprops/action-gh-release to create GitHub release
name: Build release binaries for Cosmo
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: create build folder
run: |
sudo mkdir -p /sc
sudo chmod -R 0777 /sc
- name: setup Cosmopolitan Libc
run: bash ./.github/cosmo/setup
- name: Set the version
run: echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
- name: Set the platform
run: echo "platform=cosmo" >> $GITHUB_ENV
- name: build Janet APE binary
run: bash ./.github/cosmo/build
- name: push binary to github
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
/sc/cosmocc/janet.com

91
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,91 @@
name: Test
on: [push, pull_request]
permissions:
contents: read
jobs:
test-posix:
name: Build and test on POSIX systems
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest ]
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Compile the project
run: make clean && make
- name: Test the project
run: make test
test-windows:
name: Build and test on Windows
runs-on: windows-latest
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Build the project
shell: cmd
run: build_win
- name: Test the project
shell: cmd
run: build_win test
test-mingw:
name: Build on Windows with Mingw (no test yet)
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup Mingw
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
base-devel
git
gcc
- name: Build the project
shell: cmd
run: make -j4 CC=gcc JANET_NO_AMALG=1
test-mingw-linux:
name: Build and test with Mingw on Linux + Wine
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup Mingw and wine
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libstdc++6:i386 libgcc-s1:i386
sudo apt-get install gcc-mingw-w64-x86-64-win32 wine wine32 wine64
- name: Compile the project
run: make clean && make CC=x86_64-w64-mingw32-gcc LD=x86_64-w64-mingw32-gcc UNAME=MINGW RUN=wine
- name: Test the project
run: make test UNAME=MINGW RUN=wine VERBOSE=1
test-arm-linux:
name: Build and test ARM32 cross compilation
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup qemu and cross compiler
run: |
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabi qemu-user
- name: Compile the project
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-gcc
- name: Test the project
run: make RUN="qemu-arm -L /usr/arm-linux-gnueabi/" SUBRUN="qemu-arm -L /usr/arm-linux-gnueabi/" test VERBOSE=1

26
.gitignore vendored
View File

@ -32,6 +32,14 @@ lockfile.janet
# Local directory for testing
local
# Common test files I use.
temp.janet
temp.c
temp*janet
temp*.c
scratch.janet
scratch.c
# Emscripten
*.bc
janet.js
@ -40,9 +48,11 @@ janet.wasm
# Generated files
*.gen.h
*.gen.c
*.tmp
# Generate test files
*.out
.orig
# Tools
xxd
@ -50,6 +60,8 @@ xxd.exe
# VSCode
.vs
.clangd
.cache
# Swap files
*.swp
@ -61,10 +73,13 @@ tags
vgcore.*
*.out.*
# Wix artifacts
# WiX artifacts
*.msi
*.wixpdb
# Makefile config
/config.mk
# Created by https://www.gitignore.io/api/c
### C ###
@ -112,6 +127,9 @@ vgcore.*
*.idb
*.pdb
# GGov
*.gcov
# Kernel Module Compile Results
*.mod*
*.cmd
@ -120,6 +138,9 @@ Module.symvers
Mkfile.old
dkms.conf
# Coverage files
*.cov
# End of https://www.gitignore.io/api/c
# Created by https://www.gitignore.io/api/cmake
@ -135,3 +156,6 @@ compile_commands.json
CTestTestfile.cmake
# End of https://www.gitignore.io/api/cmake
# Astyle
*.orig

View File

@ -1,25 +0,0 @@
language: c
script:
- make
- make test
- sudo make install
- make test-install
- make build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
compiler:
- clang
- gcc
os:
- linux
- osx
before_deploy:
deploy:
provider: releases
api_key:
secure: JSqAOTH1jmfVlbOuPO3BbY1BhPq+ddiBNPCxuAyKHoVwfO4eNAmq9COI+UwCMWY3dg+YlspufRwkHj//B7QQ6hPbSsKu+Mapu6gr/CAE/jxbfO/E98LkIkUwbGjplwtzw2kiBkHN/Bu6J5X76cwo4D8nwQ1JIcV3nWtoG87t7H4W0R4AYQkbLGAPylgUFr11YMPx2cRBBqCdLAGIrny7kQ/0cRBfkN81R/gUJv/q3OjmUvY7sALXp7mFdZb75QPSilKIDuVUU5hLvPYTeRl6cWI/M+m5SmGZx1rjv5S9Qaw070XoNyt9JAADtbOUnADKvDguDZIP1FCuT1Gb+cnJPzrvk6+OBU9s8UjCTFtgV+LKlhmRZcwV5YQBE94PKRMJNC6VvIWM7UeQ8Zhm1jmQS6ONNWbuoUAlkZP57NtDQa2x0GT2wkubNSQKlaY+6/gwTD9KAJIzaZG7HYXH7b+4g7VbccCyhDAtDZtXgrOIS4WAkNc8rWezRO4H0qHMyON9aCEb0eTE8hWIufbx6ymG4gUxnYO+AkrEYMCwQvU6lS8BsevkaMTVtSShqlQtJ9FRlmJA3MA2ONyqzQXJENqRydyVbpFrKSv+0HbMyhEc5BoKbt0QcTh/slouNV4eASNar/GKN7aP8XKGUeMwIoCcRpP+3ehmwX9SUw7Ah5S42pA=
file: build/janet-${TRAVIS_TAG}-${TRAVIS_OS_NAME}.tar.gz
draft: true
skip_cleanup: true
on:
tags: true
repo: janet-lang/janet
condition: "$CC = clang"

View File

@ -1,6 +1,428 @@
# Changelog
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Add extra optional `env` argument to `eval` and `eval-string`.
- Allow naming function literals with a keyword. This allows better stacktraces for macros without
accidentally adding new bindings.
- Add macros `ev/with-lock`, `ev/with-rlock`, and `ev/with-wlock` for using mutexes and rwlocks.
- Add `with-env`
- Add *module-make-env* dynamic binding
- Add buffer/format-at
- Add long form command line options for readable CLI usage
- Fix bug with `net/accept-loop` that would sometimes miss connections.
## 1.34.0 - 2024-03-22
- Add a new (split) PEG special by @ianthehenry
- Add buffer/push-* sized int and float by @pnelson
- Documentation improvements: @amano-kenji, @llmII, @MaxGyver83, @pepe, @sogaiu.
- Expose _exit to skip certain cleanup with os/exit.
- Swap set / body order for each by @sogaiu.
- Abort on assert failure instead of exit.
- Fix: os/proc-wait by @llmII.
- Fix macex1 to keep syntax location for all tuples.
- Restore if-let tail calls.
- Don't try and resume fibers that can't be resumed.
- Register stream on unmarshal.
- Fix asm roundtrip issue.
## 1.33.0 - 2024-01-07
- Add more + and * keywords to default-peg-grammar by @sogaiu.
- Use libc strlen in janet_buffer_push_cstring by @williewillus.
- Be a bit safer with reference counting.
- Add support for atomic loads in Janet's atomic abstraction.
- Fix poll event loop CPU usage issue.
- Add ipv6, shared, and cryptorand options to meson.
- Add more ipv6 feature detection.
- Fix loop for forever loop.
- Cleaned up unused NetStateConnect, fixed janet_async_end() ev refcount by @zevv.
- Fix warnings w/ MSVC and format.
- Fix marshal_one_env w/ JANET_MARSHAL_UNSAFE.
- Fix `(default)`.
- Fix cannot marshal fiber with c stackframe, in a dynamic way that is fairly conservative.
- Fix typo for SIGALARM in os/proc-kill.
- Prevent bytecode optimization from remove mk* instructions.
- Fix arity typo in peg.c by @pepe.
- Update Makefile for MinGW.
- Fix canceling waiting fiber.
- Add a new (sub) PEG special by @ianthehenry.
- Fix if net/server's handler has incorrect arity.
- Fix macex raising on ().
## 1.32.1 - 2023-10-15
- Fix return value from C function `janet_dobytes` when called on Janet functions that yield to event loop.
- Change C API for event loop interaction - get rid of JanetListener and instead use `janet_async_start` and `janet_async_end`.
- Rework event loop to make fewer system calls on kqueue and epoll.
- Expose atomic refcount abstraction in janet.h
- Add `array/weak` for weak references in arrays
- Add support for weak tables via `table/weak`, `table/weak-keys`, and `table/weak-values`.
- Fix compiler bug with using the result of `(break x)` expression in some contexts.
- Rework internal event loop code to be better behaved on Windows
- Update meson build to work better on windows
## 1.31.0 - 2023-09-17
- Report line and column when using `janet_dobytes`
- Add `:unless` loop modifier
- Allow calling `reverse` on generators.
- Improve performance of a number of core functions including `partition`, `mean`, `keys`, `values`, `pairs`, `interleave`.
- Add `lengthable?`
- Add `os/sigaction`
- Change `every?` and `any?` to behave like the functional versions of the `and` and `or` macros.
- Fix bug with garbage collecting threaded abstract types.
- Add `:signal` to the `sandbox` function to allow intercepting signals.
## 1.30.0 - 2023-08-05
- Change indexing of `array/remove` to start from -1 at the end instead of -2.
- Add new string escape sequences `\\a`, `\\b`, `\\?`, and `\\'`.
- Fix bug with marshalling channels
- Add `div` for floored division
- Make `div` and `mod` variadic
- Support `bnot` for integer types.
- Define `(mod x 0)` as `x`
- Add `ffi/pointer-cfunction` to convert pointers to cfunctions
## 1.29.1 - 2023-06-19
- Add support for passing booleans to PEGs for "always" and "never" matching.
- Allow dictionary types for `take` and `drop`
- Fix bug with closing channels while other fibers were waiting on them - `ev/take`, `ev/give`, and `ev/select` will now return the correct (documented) value when another fiber closes the channel.
- Add `ffi/calling-conventions` to show all available calling conventions for FFI.
- Add `net/setsockopt`
- Add `signal` argument to `os/proc-kill` to send signals besides `SIGKILL` on Posix.
- Add `source` argument to `os/clock` to get different time sources.
- Various combinator functions now are variadic like `map`
- Add `file/lines` to iterate over lines in a file lazily.
- Reorganize test suite to be sorted by module rather than pseudo-randomly.
- Add `*task-id*`
- Add `env` argument to `fiber/new`.
- Add `JANET_NO_AMALG` flag to Makefile to properly incremental builds
- Optimize bytecode compiler to generate fewer instructions and improve loops.
- Fix bug with `ev/gather` and hung fibers.
- Add `os/isatty`
- Add `has-key?` and `has-value?`
- Make imperative arithmetic macros variadic
- `ev/connect` now yields to the event loop instead of blocking while waiting for an ACK.
## 1.28.0 - 2023-05-13
- Various bug fixes
- Make nested short-fn's behave a bit more predictably (it is still not recommended to nest short-fns).
- Add `os/strftime` for date formatting.
- Fix `ev/select` on threaded channels sometimes live-locking.
- Support the `NO_COLOR` environment variable to turn off VT100 color codes in repl (and in scripts).
See http://no-color.org/
- Disallow using `(splice x)` in contexts where it doesn't make sense rather than silently coercing to `x`.
Instead, raise a compiler error.
- Change the names of `:user8` and `:user9` sigals to `:interrupt` and `:await`
- Change the names of `:user8` and `:user9` fiber statuses to `:interrupted` and `:suspended`.
- Add `ev/all-tasks` to see all currently suspended fibers.
- Add `keep-syntax` and `keep-syntax!` functions to make writing macros easier.
## 1.27.0 - 2023-03-05
- Change semantics around bracket tuples to no longer be equal to regular tuples.
- Add `index` argument to `ffi/write` for symmetry with `ffi/read`.
- Add `buffer/push-at`
- Add `ffi/pointer-buffer` to convert pointers to buffers the cannot be reallocated. This
allows easier manipulation of FFI memory, memory mapped files, and buffer memory shared between threads.
- Calling `ev/cancel` on a fiber waiting on `ev/gather` will correctly
cancel the child fibers.
- Add `(sandbox ...)` function to core for permission based security. Also add `janet_sandbox` to C API.
The sandbox allows limiting access to the file system, network, ffi, and OS resources at runtime.
- Add `(.locals)` function to debugger to see currently bound local symbols.
- Track symbol -> slot mapping so debugger can get symbolic information. This exposes local bindings
in `debug/stack` and `disasm`.
- Add `os/compiler` to detect what host compiler was used to compile the interpreter
- Add support for mingw and cygwin builds (mingw support also added in jpm).
## 1.26.0 - 2023-01-07
- Add `ffi/malloc` and `ffi/free`. Useful as tools of last resort.
- Add `ffi/jitfn` to allow calling function pointers generated at runtime from machine code.
Bring your own assembler, though.
- Channels can now be marshalled. Pending state is not saved, only items in the channel.
- Use the new `.length` function pointer on abstract types for lengths. Adding
a `length` method will still work as well.
- Support byte views on abstract types with the `.bytes` function pointer.
- Add the `u` format specifier to printf family functions.
- Allow printing 64 integer types in `printf` and `string/format` family functions.
- Allow importing modules from custom directories more easily with the `@` prefix
to module paths. For example, if there is a dynamic binding :custom-modules that
is a file system path to a directory of modules, import from that directory with
`(import @custom-modules/mymod)`.
- Fix error message bug in FFI library.
## 1.25.1 - 2022-10-29
- Add `memcmp` function to core library.
- Fix bug in `os/open` with `:rw` permissions not correct on Linux.
- Support config.mk for more easily configuring the Makefile.
## 1.25.0 - 2022-10-10
- Windows FFI fixes.
- Fix PEG `if-not` combinator with captures in the condition
- Fix bug with `os/date` with nil first argument
- Fix bug with `net/accept` on Linux that could leak file descriptors to subprocesses
- Reduce number of hash collisions from pointer hashing
- Add optional parameter to `marshal` to skip cycle checking code
## 1.24.1 - 2022-08-24
- Fix FFI bug on Linux/Posix
- Improve parse error messages for bad delimiters.
- Add optional `name` parameter to the `short-fn` macro.
## 1.24.0 - 2022-08-14
- Add FFI support to 64-bit windows compiled with MSVC
- Don't process shared object names passed to dlopen.
- Add better support for windows console in the default shell.c for auto-completion and
other shell-like input features.
- Improve default error message from `assert`.
- Add the `tabseq` macro for simpler table comprehensions.
- Allow setting `(dyn :task-id)` in fibers to improve context in supervisor messages. Prior to
this change, supervisor messages over threaded channels would be from ambiguous threads/fibers.
## 1.23.0 - 2022-06-20
- Add experimental `ffi/` module for interfacing with dynamic libraries and raw function pointers. Only available
on 64 bit linux, mac, and bsd systems.
- Allow using `&named` in function prototypes for named arguments. This is a more ergonomic
variant of `&keys` that isn't as redundant, more self documenting, and allows extension to
things like default arguments.
- Add `delay` macro for lazy evaluate-and-save thunks.
- Remove pthread.h from janet.h for easier includes.
- Add `debugger` - an easy to use debugger function that just takes a fiber.
- `dofile` will now start a debugger on errors if the environment it is passed has `:debug` set.
- Add `debugger-on-status` function, which can be passed to `run-context` to start a debugger on
abnormal fiber signals.
- Allow running scripts with the `-d` flag to use the built-in debugger on errors and breakpoints.
- Add mutexes (locks) and reader-writer locks to ev module for thread coordination.
- Add `parse-all` as a generalization of the `parse` function.
- Add `os/cpu-count` to get the number of available processors on a machine
## 1.22.0 - 2022-05-09
- Prohibit negative size argument to `table/new`.
- Add `module/value`.
- Remove `file/popen`. Use `os/spawn` with the `:pipe` options instead.
- Fix bug in peg `thru` and `to` combinators.
- Fix printing issue in `doc` macro.
- Numerous updates to function docstrings
- Add `defdyn` aliases for various dynamic bindings used in core.
- Install `janet.h` symlink to make Janet native libraries and applications
easier to build without `jpm`.
## 1.21.2 - 2022-04-01
- C functions `janet_dobytes` and `janet_dostring` will now enter the event loop if it is enabled.
- Fix hashing regression - hash of negative 0 must be the same as positive 0 since they are equal.
- The `flycheck` function no longer pollutes the module/cache
- Fix quasiquote bug in compiler
- Disallow use of `cancel` and `resume` on fibers scheduled or created with `ev/go`, as well as the root
fiber.
## 1.20.0 - 2022-1-27
- Add `:missing-symbol` hook to `compile` that will act as a catch-all macro for undefined symbols.
- Add `:redef` dynamic binding that will allow users to redefine top-level bindings with late binding. This
is intended for development use.
- Fix a bug with reading from a stream returned by `os/open` on Windows and Linux.
- Add `:ppc64` as a detectable OS type.
- Add `& more` support for destructuring in the match macro.
- Add `& more` support for destructuring in all binding forms (`def`).
## 1.19.2 - 2021-12-06
- Fix bug with missing status lines in some stack traces.
- Update hash function to have better statistical properties.
## 1.19.1 - 2021-12-04
- Add an optional `prefix` parameter to `debug/stacktrace` to allow printing prettier error messages.
- Remove appveyor for CI pipeline
- Fixed a bug that prevented sending threaded abstracts over threaded channels.
- Fix bug in the `map` function with arity at least 3.
## 1.19.0 - 2021-11-27
- Add `math/log-gamma` to replace `math/gamma`, and change `math/gamma` to be the expected gamma function.
- Fix leaking file-descriptors in os/spawn and os/execute.
- Ctrl-C will now raise SIGINT.
- Allow quoted literals in the `match` macro to behave as expected in patterns.
- Fix windows net related bug for TCP servers.
- Allow evaluating ev streams with dofile.
- Fix `ev` related bug with operations on already closed file descriptors.
- Add struct and table agnostic `getproto` function.
- Add a number of functions related to structs.
- Add prototypes to structs. Structs can now inherit from other structs, just like tables.
- Create a struct with a prototype with `struct/with-proto`.
- Deadlocked channels will no longer exit early - instead they will hang, which is more intuitive.
## 1.18.1 - 2021-10-16
- Fix some documentation typos
- Fix - Set pipes passed to subprocess to blocking mode.
- Fix `-r` switch in repl.
## 1.18.0 - 2021-10-10
- Allow `ev/cancel` to work on already scheduled fibers.
- Fix bugs with ev/ module.
- Add optional `base` argument to scan-number
- Add `-i` flag to janet binary to make it easier to run image files from the command line
- Remove `thread/` module.
- Add `(number ...)` pattern to peg for more efficient number parsing using Janet's
scan-number function without immediate string creation.
## 1.17.2 - 2021-09-18
- Remove include of windows.h from janet.h. This caused issues on certain projects.
- Fix formatting in doc-format to better handle special characters in signatures.
- Fix some marshalling bugs.
- Add optional Makefile target to install jpm as well.
- Supervisor channels in threads will no longer include a wasteful copy of the fiber in every
message across a thread.
- Allow passing a closure to `ev/thread` as well as a whole fiber.
- Allow passing a closure directly to `ev/go` to spawn fibers on the event loop.
## 1.17.1 - 2021-08-29
- Fix docstring typos
- Add `make install-jpm-git` to make jpm co-install simpler if using the Makefile.
- Fix bugs with starting ev/threads and fiber marshaling.
## 1.17.0 - 2021-08-21
- Add the `-E` flag for one-liners with the `short-fn` syntax for argument passing.
- Add support for threaded abstract types. Threaded abstract types can easily be shared between threads.
- Deprecate the `thread` library. Use threaded channels and ev instead.
- Channels can now be marshalled.
- Add the ability to close channels with `ev/chan-close` (or `:close`).
- Add threaded channels with `ev/thread-chan`.
- Add `JANET_FN` and `JANET_REG` macros to more easily define C functions that export their source mapping information.
- Add `janet_interpreter_interupt` and `janet_loop1_interrupt` to interrupt the interpreter while running.
- Add `table/clear`
- Add build option to disable the threading library without disabling all threads.
- Remove JPM from the main Janet distribution. Instead, JPM must be installed
separately like any other package.
- Fix issue with `ev/go` when called with an initial value and supervisor.
- Add the C API functions `janet_vm_save` and `janet_vm_load` to allow
saving and restoring the entire VM state.
## 1.16.1 - 2021-06-09
- Add `maclintf` - a utility for adding linting messages when inside macros.
- Print source code of offending line on compiler warnings and errors.
- Fix some issues with linting and re-add missing `make docs`.
- Allow controlling linting with dynamic bindings `:lint-warn`, `:lint-error`, and `:lint-levels`.
- Add `-w` and `-x` command line flags to the `janet` binary to set linting thresholds.
linting thresholds are as follows:
- :none - will never be trigger.
- :relaxed - will only trigger on `:relaxed` lints.
- :normal - will trigger on `:relaxed` and `:normal` lints.
- :strict - will trigger on `:strict`, `:normal`, and `:relaxed` lints. This will catch the most issues
but can be distracting.
## 1.16.0 - 2021-05-30
- Add color documentation to the `doc` macro - enable/disable with `(dyn :doc-color)`.
- Remove simpler HTML docs from distribution - use website or built-in documentation instead.
- Add compiler warnings and deprecation levels.
- Add `as-macro` to make using macros within quasiquote easier to do hygienically.
- Expose `JANET_OUT_OF_MEMORY` as part of the Janet API.
- Add `native-deps` option to `declare-native` in `jpm`. This lets native libraries link to other
native libraries when building with jpm.
- Remove the `tarray` module. The functionality of typed arrays will be moved to an external module
that can be installed via `jpm`.
- Add `from-pairs` to core.
- Add `JPM_OS_WHICH` environment variable to jpm to allow changing auto-detection behavior.
- The flychecker will consider any top-level calls of functions that start with `define-` to
be safe to execute and execute them. This allows certain patterns (like spork/path) to be
better processed by the flychecker.
## 1.15.5 - 2021-04-25
- Add `declare-headers` to jpm.
- Fix error using unix pipes on BSDs.
- Support .cc and .cxx extensions in `jpm` for C++ code.
- Change networking code to not create as many HUP errors.
- Add `net/shutdown` to close sockets in one direction without hang ups.
- Update code for printing the debug repl
## 1.15.4 - 2021-03-16
- Increase default nesting depth of pretty printing to `JANET_RECURSION_GUARD`
- Update meson.build
- Add option to automatically add shebang line in installed scripts with `jpm`.
- Add `partition-by` and `group-by` to the core.
- Sort keys in pretty printing output.
## 1.15.3 - 2021-02-28
- Fix a fiber bug that occured in deeply nested fibers
- Add `unref` combinator to pegs.
- Small docstring changes.
## 1.15.2 - 2021-02-15
- Fix bug in windows version of `os/spawn` and `os/execute` with setting environment variables.
- Fix documentation typos.
- Fix peg integer reading combinators when used with capture tags.
## 1.15.0 - 2021-02-08
- Fix `gtim` and `ltim` bytecode instructions on non-integer values.
- Clean up output of flychecking to be the same as the repl.
- Change behavior of `debug/stacktrace` with a nil error value.
- Add optional argument to `parser/produce`.
- Add `no-core` option to creating standalone binaries to make execution faster.
- Fix bug where a buffer overflow could be confused with an out of memory error.
- Change error output to `file:line:column: message`. Column is in bytes - tabs
are considered to have width 1 (instead of 8).
## 1.14.2 - 2021-01-23
- Allow `JANET_PROFILE` env variable to load a profile before loading the repl.
- Update `tracev` macro to allow `def` and `var` inside to work as expected.
- Use `(dyn :peg-grammar)` for passing a default grammar to `peg/compile` instead of loading
`default-peg-grammar` directly from the root environment.
- Add `ev/thread` for combining threading with the event loop.
- Add `ev/do-thread` to make `ev/thread` easier to use.
- Automatically set supervisor channel in `net/accept-loop` and `net/server` correctly.
## 1.14.1 - 2021-01-18
- Add `doc-of` for reverse documentation lookup.
- Add `ev/give-supervsior` to send a message to the supervising channel.
- Add `ev/gather` and `chan` argument to `ev/go`. This new argument allows "supervisor channels"
for fibers to enable structured concurrency.
- Make `-k` flag work on stdin if no files are given.
- Add `flycheck` function to core.
- Make `backmatch` and `backref` more expressive in pegs.
- Fix buggy `string/split`.
- Add `fiber/last-value` to get the value that was last yielded, errored, or signaled
by a fiber.
- Remove `:generate` verb from `loop` macros. Instead, use the `:in` verb
which will now work on fibers as well as other data structures.
- Define `next`, `get`, and `in` for fibers. This lets
`each`, `map`, and similar iteration macros can now iterate over fibers.
- Remove macro `eachy`, which can be replaced by `each`.
- Add `dflt` argument to find-index.
- Deprecate `file/popen` in favor of `os/spawn`.
- Add `:all` keyword to `ev/read` and `net/read` to make them more like `file/read`. However, we
do not provide any `:line` option as that requires buffering.
- Change repl behavior to make Ctrl-C raise SIGINT on posix. The old behavior for Ctrl-C,
to clear the current line buffer, has been moved to Ctrl-Q.
- Importing modules that start with `/` is now the only way to import from project root.
Before, this would import from / on disk. Previous imports that did not start with `.` or `/`
are now unambiguously importing from the syspath, instead of checking both the syspath and
the project root. This is backwards incompatible and dependencies should be updated for this.
- Change hash function for numbers.
- Improve error handling of `dofile`.
- Bug fixes in networking and subprocess code.
- Use markdown formatting in more places for docstrings.
## 1.13.1 - 2020-12-13
- Pretty printing a table with a prototype will look for `:_name` instead of `:name`
in the prototype table to tag the output.
- `match` macro implementation changed to be tail recursive.
- Adds a :preload loader which allows one to manually put things into `module/cache`.
- Add `buffer/push` function.
- Backtick delimited strings and buffers are now reindented based on the column of the
opening delimiter. Whitespace in columns to the left of the starting column is ignored unless
there are non-space/non-newline characters in that region, in which case the old behavior is preserved.
- Argument to `(error)` combinator in PEGs is now optional.
- Add `(line)` and `(column)` combinators to PEGs to capture source line and column.
This should make error reporting a bit easier.
- Add `merge-module` to core.
- During installation and release, merge janetconf.h into janet.h for easier install.
- Add `upscope` special form.
- `os/execute` and `os/spawn` can take streams for redirecting IO.
- Add `:parser` and `:read` parameters to `run-context`.
- Add `os/open` if ev is enabled.
- Add `os/pipe` if ev is enabled.
- Add `janet_thread_current(void)` to C API
- Add integer parsing forms to pegs. This makes parsing many binary protocols easier.
- Lots of updates to networking code - now can use epoll (or poll) on linux and IOCP on windows.
- Add `ev/` module. This exposes a fiber scheduler, queues, timeouts, and other functionality to users
for single threaded cooperative scheduling and asynchronous IO.
- Add `net/accept-loop` and `net/listen`. These functions break down `net/server` into it's essential parts
and are more flexible. They also allow further improvements to these utility functions.
- Various small bug fixes.
## 1.12.2 - 2020-09-20
- Add janet\_try and janet\_restore to C API.
- Fix `os/execute` regression on windows.

View File

@ -14,7 +14,6 @@ Please read this document before making contributions.
on how to reproduce it. If it is a compiler or language bug, please try to include a minimal
example. This means don't post all 200 lines of code from your project, but spend some time
distilling the problem to just the relevant code.
* Add the `bug` tag to the issue.
## Contributing Changes
@ -30,8 +29,7 @@ may require changes before being merged.
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.) Use `make format` to
automatically format your C code with
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.
@ -45,7 +43,7 @@ For changes to the VM and Core code, you will probably need to know C. Janet is
a subset of C99 that works with Microsoft Visual C++. This means most of C99 but with the following
omissions.
* No `restrict`
* 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.
@ -66,6 +64,23 @@ ensure a consistent code style for C.
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.
## Typo Fixing and One-Line changes
Typo fixes are welcome, as are simple one line fixes. Do not open many separate pull requests for each
individual typo fix. This is incredibly annoying to deal with as someone needs to review each PR, run
CI, and merge. Instead, accumulate batches of typo fixes into a single PR. If there are objections to
specific changes, these can be addressed in the review process before the final merge, if the changes
are accepted.
Similarly, low effort and bad faith changes are annoying to developers and such issues may be closed
immediately without response.
## Contributions from Automated Tools
People making changes found or generated by automated tools MUST note this when opening an issue
or creating a pull request. This can help give context to developers if the change/issue is
confusing or nonsensical.
## Suggesting Changes
To suggest changes, open an issue on GitHub. Check GitHub for other issues
@ -75,4 +90,3 @@ timely manner. In short, if you want extra functionality now, then build it.
* Include a good description of the problem that is being solved
* Include descriptions of potential solutions if you have some in mind.
* Add the appropriate tags to the issue. For new features, add the `enhancement` tag.

View File

@ -1,4 +1,4 @@
Copyright (c) 2020 Calvin Rose and contributors
Copyright (c) 2023 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

216
Makefile
View File

@ -1,4 +1,4 @@
# Copyright (c) 2020 Calvin Rose
# Copyright (c) 2023 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,59 +21,98 @@
################################
##### Set global variables #####
################################
sinclude config.mk
PREFIX?=/usr/local
JANETCONF_HEADER?=src/conf/janetconf.h
INCLUDEDIR?=$(PREFIX)/include
BINDIR?=$(PREFIX)/bin
LIBDIR?=$(PREFIX)/lib
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1 || echo local)\""
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1 2> /dev/null || echo local)\""
CLIBS=-lm -lpthread
JANET_TARGET=build/janet
JANET_BOOT=build/janet_boot
JANET_IMPORT_LIB=build/janet.lib
JANET_LIBRARY_IMPORT_LIB=build/libjanet.lib
JANET_LIBRARY=build/libjanet.so
JANET_STATIC_LIBRARY=build/libjanet.a
JANET_PATH?=$(LIBDIR)/janet
JANET_MANPATH?=$(PREFIX)/share/man/man1/
JANET_PKG_CONFIG_PATH?=$(LIBDIR)/pkgconfig
JANET_DIST_DIR?=janet-dist
JANET_BOOT_FLAGS:=. JANET_PATH '$(JANET_PATH)'
JANET_TARGET_OBJECTS=build/janet.o build/shell.o
JPM_TAG?=master
HAS_SHARED?=1
DEBUGGER=gdb
SONAME_SETTER=-Wl,-soname,
# For cross compilation
HOSTCC?=$(CC)
HOSTAR?=$(AR)
CFLAGS?=-O2
# Symbols are (optionally) removed later, keep -g as default!
CFLAGS?=-O2 -g
LDFLAGS?=-rdynamic
LIBJANET_LDFLAGS?=$(LD_FLAGS)
RUN:=$(RUN)
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)
BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) -O0 $(COMMON_CFLAGS) -g
BUILD_CFLAGS:=$(CFLAGS) $(COMMON_CFLAGS)
# Disable amalgamated build
ifeq ($(JANET_NO_AMALG), 1)
JANET_TARGET_OBJECTS+=$(patsubst src/%.c,build/%.bin.o,$(JANET_CORE_SOURCES))
JANET_BOOT_FLAGS+=image-only
endif
# For installation
LDCONFIG:=ldconfig "$(LIBDIR)"
# Check OS
UNAME:=$(shell uname -s)
UNAME?=$(shell uname -s)
ifeq ($(UNAME), Darwin)
CLIBS:=$(CLIBS) -ldl
SONAME_SETTER:=-Wl,-install_name,
JANET_LIBRARY=build/libjanet.dylib
LDCONFIG:=true
else ifeq ($(UNAME), Linux)
CLIBS:=$(CLIBS) -lrt -ldl
endif
# For other unix likes, add flags here!
ifeq ($(UNAME), Haiku)
LDCONFIG:=true
LDFLAGS=-Wl,--export-dynamic
endif
# For Android (termux)
ifeq ($(UNAME), Linux) # uname on Darwin doesn't recognise -o
ifeq ($(shell uname -o), Android)
CLIBS:=$(CLIBS) -landroid-spawn
endif
endif
$(shell mkdir -p build/core build/mainclient build/webclient build/boot)
all: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY)
# Mingw
ifeq ($(findstring MINGW,$(UNAME)), MINGW)
CLIBS:=-lws2_32 -lpsapi -lwsock32
LDFLAGS:=-Wl,--out-implib,$(JANET_IMPORT_LIB)
LIBJANET_LDFLAGS:=-Wl,--out-implib,$(JANET_LIBRARY_IMPORT_LIB)
JANET_TARGET:=$(JANET_TARGET).exe
JANET_BOOT:=$(JANET_BOOT).exe
endif
$(shell mkdir -p build/core build/c build/boot build/mainclient)
all: $(JANET_TARGET) $(JANET_STATIC_LIBRARY) build/janet.h
ifeq ($(HAS_SHARED), 1)
all: $(JANET_LIBRARY)
endif
######################
##### Name Files #####
######################
JANET_HEADERS=src/include/janet.h src/conf/janetconf.h
JANET_HEADERS=src/include/janet.h $(JANETCONF_HEADER)
JANET_LOCAL_HEADERS=src/core/features.h \
src/core/util.h \
@ -97,6 +136,8 @@ JANET_CORE_SOURCES=src/core/abstract.c \
src/core/corelib.c \
src/core/debug.c \
src/core/emit.c \
src/core/ev.c \
src/core/ffi.c \
src/core/fiber.c \
src/core/gc.c \
src/core/inttypes.c \
@ -111,14 +152,13 @@ JANET_CORE_SOURCES=src/core/abstract.c \
src/core/regalloc.c \
src/core/run.c \
src/core/specials.c \
src/core/state.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 \
@ -141,45 +181,56 @@ JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) $(JAN
$(JANET_BOOT_OBJECTS): $(JANET_BOOT_HEADERS)
build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS)
build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
$(CC) $(BOOT_CFLAGS) -o $@ -c $<
build/janet_boot: $(JANET_BOOT_OBJECTS)
$(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)' > $@
build/c/janet.c: $(JANET_BOOT) src/boot/boot.janet
$(RUN) $(JANET_BOOT) $(JANET_BOOT_FLAGS) > $@
cksum $@
##################
##### Quicky #####
##################
build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
$(HOSTCC) $(BUILD_CFLAGS) -o $@ -c $<
########################
##### Amalgamation #####
########################
SONAME=libjanet.so.1.12
ifeq ($(UNAME), Darwin)
SONAME=libjanet.1.34.dylib
else
SONAME=libjanet.so.1.34
endif
build/shell.c: src/mainclient/shell.c
build/c/shell.c: src/mainclient/shell.c
cp $< $@
build/janet.h: src/include/janet.h
build/janet.h: $(JANET_TARGET) src/include/janet.h $(JANETCONF_HEADER)
$(RUN) ./$(JANET_TARGET) tools/patch-header.janet src/include/janet.h $(JANETCONF_HEADER) $@
build/janetconf.h: $(JANETCONF_HEADER)
cp $< $@
build/janetconf.h: src/conf/janetconf.h
cp $< $@
build/janet.o: build/c/janet.c $(JANETCONF_HEADER) src/include/janet.h
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
build/janet.o: build/janet.c build/janet.h build/janetconf.h
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@ -I build
build/shell.o: build/c/shell.c $(JANETCONF_HEADER) src/include/janet.h
$(HOSTCC) $(BUILD_CFLAGS) -c $< -o $@
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
$(JANET_TARGET): $(JANET_TARGET_OBJECTS)
$(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_LIBRARY): $(JANET_TARGET_OBJECTS)
$(HOSTCC) $(LIBJANET_LDFLAGS) $(BUILD_CFLAGS) $(SONAME_SETTER)$(SONAME) -shared -o $@ $^ $(CLIBS)
$(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
$(JANET_STATIC_LIBRARY): $(JANET_TARGET_OBJECTS)
$(HOSTAR) rcs $@ $^
###################
@ -191,25 +242,23 @@ $(JANET_STATIC_LIBRARY): build/janet.o build/shell.o
TEST_SCRIPTS=$(wildcard test/suite*.janet)
repl: $(JANET_TARGET)
./$(JANET_TARGET)
$(RUN) ./$(JANET_TARGET)
debug: $(JANET_TARGET)
$(DEBUGGER) ./$(JANET_TARGET)
VALGRIND_COMMAND=valgrind --leak-check=full
VALGRIND_COMMAND=valgrind --leak-check=full --quiet
valgrind: $(JANET_TARGET)
$(VALGRIND_COMMAND) ./$(JANET_TARGET)
test: $(JANET_TARGET) $(TEST_PROGRAMS)
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
for f in test/suite*.janet; do $(RUN) ./$(JANET_TARGET) "$$f" || exit; done
for f in examples/*.janet; do $(RUN) ./$(JANET_TARGET) -k "$$f"; done
valtest: $(JANET_TARGET) $(TEST_PROGRAMS)
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
@ -221,13 +270,26 @@ callgrind: $(JANET_TARGET)
dist: build/janet-dist.tar.gz
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)
build/janet.h \
janet.1 LICENSE CONTRIBUTING.md $(JANET_STATIC_LIBRARY) \
README.md build/c/janet.c build/c/shell.c
mkdir -p build/$(JANET_DIST_DIR)/bin
cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
strip -x -S 'build/$(JANET_DIST_DIR)/bin/janet'
mkdir -p build/$(JANET_DIST_DIR)/include
cp build/janet.h build/$(JANET_DIST_DIR)/include/
mkdir -p build/$(JANET_DIST_DIR)/lib/
cp $(JANET_STATIC_LIBRARY) build/$(JANET_DIST_DIR)/lib/
cp $(JANET_LIBRARY) build/$(JANET_DIST_DIR)/lib/ || true
mkdir -p build/$(JANET_DIST_DIR)/man/man1/
cp janet.1 build/$(JANET_DIST_DIR)/man/man1/janet.1
mkdir -p build/$(JANET_DIST_DIR)/src/
cp build/c/janet.c build/c/shell.c build/$(JANET_DIST_DIR)/src/
cp CONTRIBUTING.md LICENSE README.md build/$(JANET_DIST_DIR)/
cd build && tar -czvf ../$@ ./$(JANET_DIST_DIR)
ifeq ($(HAS_SHARED), 1)
build/janet-%.tar.gz: $(JANET_LIBRARY)
endif
#########################
##### Documentation #####
@ -236,16 +298,12 @@ build/janet-%.tar.gz: $(JANET_TARGET) \
docs: build/doc.html
build/doc.html: $(JANET_TARGET) tools/gendoc.janet
$(JANET_TARGET) tools/gendoc.janet > build/doc.html
$(RUN) $(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)' > $@
@ -256,38 +314,57 @@ build/janet.pc: $(JANET_TARGET)
echo "Name: janet" >> $@
echo "Url: https://janet-lang.org" >> $@
echo "Description: Library for the Janet programming language." >> $@
$(JANET_TARGET) -e '(print "Version: " janet/version)' >> $@
$(RUN) $(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
install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h
mkdir -p '$(DESTDIR)$(BINDIR)'
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
strip -x -S '$(DESTDIR)$(BINDIR)/janet'
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
cp -rf $(JANET_HEADERS) '$(DESTDIR)$(INCLUDEDIR)/janet'
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
ln -sf ./janet/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet.h'
mkdir -p '$(DESTDIR)$(JANET_PATH)'
mkdir -p '$(DESTDIR)$(LIBDIR)'
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')'
if test $(UNAME) = Darwin ; then \
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib' ; \
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.dylib' ; \
ln -sf libjanet.$(shell $(JANET_TARGET) -e '(print janet/version)').dylib $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
else \
cp $(JANET_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)')' ; \
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so' ; \
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME) ; \
fi
cp $(JANET_STATIC_LIBRARY) '$(DESTDIR)$(LIBDIR)/libjanet.a'
ln -sf $(SONAME) '$(DESTDIR)$(LIBDIR)/libjanet.so'
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(DESTDIR)$(LIBDIR)/$(SONAME)
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
cp '$(JANET_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
cp '$(JANET_LIBRARY_IMPORT_LIB)' '$(DESTDIR)$(LIBDIR)' || echo 'no import lib to install (mingw only)'
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || echo "You can ignore this error for non-Linux systems or local installs"
install-jpm-git: $(JANET_TARGET)
mkdir -p build
rm -rf build/jpm
git clone --depth=1 --branch='$(JPM_TAG)' https://github.com/janet-lang/jpm.git build/jpm
cd build/jpm && PREFIX='$(PREFIX)' \
DESTDIR=$(DESTDIR) \
JANET_MANPATH='$(JANET_MANPATH)' \
JANET_HEADERPATH='$(INCLUDEDIR)/janet' \
JANET_BINPATH='$(BINDIR)' \
JANET_LIBPATH='$(LIBDIR)' \
$(RUN) ../../$(JANET_TARGET) ./bootstrap.janet
uninstall:
-rm '$(DESTDIR)$(BINDIR)/janet'
-rm '$(DESTDIR)$(BINDIR)/jpm'
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet'
-rm -rf '$(DESTDIR)$(INCLUDEDIR)/janet.h'
-rm -rf '$(DESTDIR)$(LIBDIR)'/libjanet.*
-rm '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
-rm '$(DESTDIR)$(JANET_MANPATH)/janet.1'
-rm '$(DESTDIR)$(JANET_MANPATH)/jpm.1'
# -rm -rf '$(DESTDIR)$(JANET_PATH)'/* - err on the side of correctness here
#################
@ -295,29 +372,22 @@ uninstall:
#################
format:
tools/format.sh
sh tools/format.sh
grammar: build/janet.tmLanguage
build/janet.tmLanguage: tools/tm_lang_gen.janet $(JANET_TARGET)
$(JANET_TARGET) $< > $@
$(RUN) $(JANET_TARGET) $< > $@
compile-commands:
# Requires pip install compiledb
compiledb make
clean:
-rm -rf build vgcore.* callgrind.*
-rm -rf test/install/build test/install/modpath
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
echo "JPM has been removed from default install."
help:
@echo
@ -342,4 +412,4 @@ help:
@echo
.PHONY: clean install repl debug valgrind test \
valtest dist uninstall docs grammar format help
valtest dist uninstall docs grammar format help compile-commands

316
README.md
View File

@ -1,72 +1,148 @@
[![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?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/master/freebsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/master/freebsd.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~bakpakin/janet/commits/master/openbsd.yml.svg)](https://builds.sr.ht/~bakpakin/janet/commits/master/openbsd.yml?)
[![Actions Status](https://github.com/janet-lang/janet/actions/workflows/test.yml/badge.svg)](https://github.com/janet-lang/janet/actions/workflows/test.yml)
<img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left">
**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 (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.
**Janet** is a programming language for system scripting, expressive automation, and
extending programs written in C or C++ with user scripting capabilities.
There is a repl for trying out the language, as well as the ability
Janet makes a good system scripting language, or a language to embed in other programs.
It's like Lua and GNU Guile in that regard. It has more built-in functionality and a richer core language than
Lua, but smaller than GNU Guile or Python. However, it is much easier to embed and port than Python or Guile.
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 can be embedded into other programs. Try Janet in your browser at
[https://janet-lang.org](https://janet-lang.org).
Janet can be embedded in other programs. Try Janet in your browser at
<https://janet-lang.org>.
If you'd like to financially support the ongoing development of Janet, consider
[sponsoring its primary author](https://github.com/sponsors/bakpakin) through GitHub.
<br>
## Use Cases
## Examples
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.
See the examples directory for all provided example programs.
## Features
### Game of Life
* Minimal setup - one binary and you are good to go!
* First class closures
```janet
# John Conway's Game of Life
(def- window
(seq [x :range [-1 2]
y :range [-1 2]
:when (not (and (zero? x) (zero? y)))]
[x y]))
(defn- neighbors
[[x y]]
(map (fn [[x1 y1]] [(+ x x1) (+ y y1)]) window))
(defn tick
"Get the next state in the Game Of Life."
[state]
(def cell-set (frequencies state))
(def neighbor-set (frequencies (mapcat neighbors state)))
(seq [coord :keys neighbor-set
:let [count (get neighbor-set coord)]
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
coord))
(defn draw
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
[state x1 y1 x2 y2]
(def cellset @{})
(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 [x y]) "X " ". ")))
(print))
# Print the first 20 generations of a glider
(var *state* '[(0 0) (-1 0) (1 0) (1 1) (0 2)])
(for i 0 20
(print "generation " i)
(draw *state* -7 -7 7 7)
(set *state* (tick *state*)))
```
### TCP Echo Server
```janet
# A simple TCP echo server using the built-in socket networking and event loop.
(defn handler
"Simple handler for connections."
[stream]
(defer (:close stream)
(def id (gensym))
(def b @"")
(print "Connection " id "!")
(while (:read stream 1024 b)
(printf " %v -> %v" id b)
(:write stream b)
(buffer/clear b))
(printf "Done %v!" id)
(ev/sleep 0.5)))
(net/server "127.0.0.1" "8000" handler)
```
### Windows FFI Hello, World!
```janet
# Use the FFI to popup a Windows message box - no C required
(ffi/context "user32.dll")
(ffi/defbind MessageBoxA :int
[w :ptr text :string cap :string typ :int])
(MessageBoxA nil "Hello, World!" "Test" 0)
```
## Language Features
* 600+ functions and macros in the core library
* Built-in socket networking, threading, subprocesses, and file system functions.
* Parsing Expression Grammars (PEG) engine as a more robust Regex alternative
* Macros and compile-time computation
* Per-thread event loop for efficient IO (epoll/IOCP/kqueue)
* First-class green threads (continuations) as well as OS threads
* Erlang-style supervision trees that integrate with the event loop
* First-class closures
* Garbage collection
* First class green threads (continuations)
* Python style generators (implemented as a plain macro)
* Distributed as janet.c and janet.h for embedding into a larger program.
* Python-style generators (implemented as a plain macro)
* Mutable and immutable arrays (array/tuple)
* Mutable and immutable hashtables (table/struct)
* Mutable and immutable strings (buffer/string)
* 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
* Dynamically load C libraries
* Functional and imperative standard library
* Lexical scoping
* Imperative programming as well as functional
* REPL
* 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
* Tail recursion
* Interface with C functions and dynamically load plugins ("natives").
* Built-in C FFI for when the native bindings are too much work
* REPL development with debugger and inspectable runtime
## Documentation
* 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)
* For the full API for all functions in the core library, see [the core API doc](https://janet-lang.org/api/index.html).
Documentation is also available locally in the repl.
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)
(doc apply)
```
Shows documentation for the doc macro.
shows documentation for the `apply` function.
To get a list of all bindings in the default
environment, use the `(all-bindings)` function. You
can also use the `(doc)` macro with no arguments if you are in the repl
can also use the `(doc)` macro with no arguments if you are in the REPL
to show bound symbols.
## Source
@ -81,66 +157,71 @@ the SourceHut mirror is actively maintained.
The Makefile is non-portable and requires GNU-flavored make.
```
```sh
cd somewhere/my/projects/janet
make
make test
make repl
make install
make install-jpm-git
```
Find out more about the available make targets by running `make help`.
### 32-bit Haiku
32-bit Haiku build instructions are the same as the unix-like build instructions,
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`.
```
```sh
cd somewhere/my/projects/janet
make CC=gcc-x86
make test
make repl
make install
make install-jpm-git
```
### 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`.
FreeBSD build instructions are the same as the UNIX-like build instructions,
but you need `gmake` to compile. Alternatively, install the package directly with `pkg install lang/janet`.
```
```sh
cd somewhere/my/projects/janet
gmake
gmake test
gmake repl
gmake install
gmake install-jpm-git
```
### NetBSD
NetBSD build instructions are the same as the FreeBSD build instuctions.
Alternatively, install directly from packages, using `pkgin install janet`.
NetBSD build instructions are the same as the FreeBSD build instructions.
Alternatively, install the package directly with `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.
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 your 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`
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
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 cross-compilation.
For the impatient, building with Meson is as follows. The options provided to
`meson setup` below emulate Janet's Makefile.
@ -166,22 +247,22 @@ ninja -C build install
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
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.
Emacs, and Atom each have syntax packages for the Janet language, though.
## Installation
See [the Introduction](https://janet-lang.org/introduction.html) for more details. If you just want
See the [Introduction](https://janet-lang.org/docs/index.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
A repl is launched when the binary is invoked with no arguments. Pass the -h flag
to display the usage information. Individual scripts can be run with `./janet myscript.janet`
A REPL is launched when the binary is invoked with no arguments. Pass the `-h` flag
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-bindings)` into the repl.
by entering the command `(all-bindings)` into the REPL.
```
$ janet
@ -193,32 +274,38 @@ Hello, World!
nil
janet:3:> (os/exit)
$ janet -h
usage: build/janet [options] script args...
usage: 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 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)
-E code arguments... : Evaluate an expression as a short-fn with arguments
-d : Set the debug flag in the REPL
-r : Enter the REPL after running all scripts
-R : Disables loading profile.janet when JANET_PROFILE is present
-p : Keep on executing if there is a top-level error (persistent)
-q : Hide logo (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
-i : Load the script argument as an image file instead of source code
-n : Disable ANSI color output in the REPL
-l lib : Use a module before processing more arguments
-w level : Set the lint warning level - default is "normal"
-x level : Set the lint error level - default is "none"
-- : Stop handling options
```
If installed, you can also run `man janet` and `man jpm` to get usage information.
If installed, you can also run `man janet` to get usage information.
## Embedding
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`
`src/include/janet.h` and `src/conf/janetconf.h`, can be dragged into any C
project and compiled into it. 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
@ -226,27 +313,88 @@ there is no need for dynamic modules, add the define
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/)
Feel free to ask questions and join the discussion on the [Janet Zulip Instance](https://janet.zulipchat.com/)
## FAQ
### Why is my terminal spitting out junk when I run the repl?
### How fast is it?
It is about the same speed as most interpreted languages without a JIT compiler. Tight, critical
loops should probably be written in C or C++ . Programs tend to be a bit faster than
they would be in a language like Python due to the discouragement of slow Object-Oriented abstraction
with lots of hash-table lookups, and making late-binding explicit. All values are boxed in an 8-byte
representation by default and allocated on the heap, with the exception of numbers, nils and booleans. The
PEG engine is a specialized interpreter that can efficiently process string and buffer data.
The GC is simple and stop-the-world, but GC knobs are exposed in the core library and separate threads
have isolated heaps and garbage collectors. Data that is shared between threads is reference counted.
YMMV.
### Where is (favorite feature from other language)?
It may exist, it may not. If you want to propose a major language feature, go ahead and open an issue, but
it will likely be closed as "will not implement". Often, such features make one usecase simpler at the expense
of 5 others by making the language more complicated.
### Is there a language spec?
There is not currently a spec besides the documentation at <https://janet-lang.org>.
### Is this Scheme/Common Lisp? Where are the cons cells?
Nope. There are no cons cells here.
### Is this a Clojure port?
No. It's similar to Clojure superficially because I like Lisps and I like the aesthetics.
Internally, Janet is not at all like Clojure, Scheme, or Common Lisp.
### Are the immutable data structures (tuples and structs) implemented as hash tries?
No. They are immutable arrays and hash tables. Don't try and use them like Clojure's vectors
and maps, instead they work well as table keys or other identifiers.
### Can I do object-oriented programming with Janet?
To some extent, yes. However, it is not the recommended method of abstraction, and performance may suffer.
That said, tables can be used to make mutable objects with inheritance and polymorphism, where object
methods are implemented with keywords.
```clj
(def Car @{:honk (fn [self msg] (print "car " self " goes " msg)) })
(def my-car (table/setproto @{} Car))
(:honk my-car "Beep!")
```
### Why can't we add (feature from Clojure) into the core?
Usually, one of a few reasons:
- Often, it already exists in a different form and the Clojure port would be redundant.
- Clojure programs often generate a lot of garbage and rely on the JVM to clean it up.
Janet does not run on the JVM and has a more primitive garbage collector.
- We want to keep the Janet core small. With Lisps, a feature can usually be added as a library
without feeling "bolted on", especially when compared to ALGOL-like languages. Adding features
to the core also makes it a bit more difficult to keep Janet maximally portable.
### Can I bind to Rust/Zig/Go/Java/Nim/C++/D/Pascal/Fortran/Odin/Jai/(Some new "Systems" Programming Language)?
Probably, if that language has a good interface with C. But the programmer may need to do
some extra work to map Janet's internal memory model to that of the bound language. Janet
also uses `setjmp`/`longjmp` for non-local returns internally. This
approach is out of favor with many programmers now and doesn't always play well with other languages
that have exceptions or stack-unwinding.
### 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
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` flag if further issues
ensue.
## Why Janet
## Why is it called "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,58 +0,0 @@
version: build-{build}
clone_folder: c:\projects\janet
image:
- Visual Studio 2019
configuration:
- Release
platform:
- x64
- x86
environment:
matrix:
- arch: Win64
matrix:
fast_finish: true
# skip unsupported combinations
init:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %platform%
install:
- set JANET_BUILD=%appveyor_repo_commit:~0,7%
- build_win all
- 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
artifacts:
- 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|shell).*/
draft: true
on:
APPVEYOR_REPO_TAG: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

View File

@ -14,13 +14,18 @@
@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
@rem Example use asan
@rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi
@rem set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib
@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
@ -28,40 +33,40 @@ if not "%JANET_BUILD%" == "" (
@set JANET_COMPILE=%JANET_COMPILE% /DJANET_BUILD="\"%JANET_BUILD%\""
)
mkdir build
mkdir build\core
mkdir build\mainclient
mkdir build\boot
if not exist build mkdir build
if not exist build\core mkdir build\core
if not exist build\c mkdir build\c
if not exist build\boot mkdir build\boot
@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
@if not errorlevel 0 goto :BUILDFAIL
)
for %%f in (src\boot\*.c) do (
%JANET_COMPILE% /DJANET_BOOTSTRAP /Fobuild\boot\%%~nf.obj %%f
@if errorlevel 1 goto :BUILDFAIL
@if not errorlevel 0 goto :BUILDFAIL
)
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
@if errorlevel 1 goto :BUILDFAIL
build\janet_boot . > build\janet.c
@if not errorlevel 0 goto :BUILDFAIL
build\janet_boot . > build\c\janet.c
@rem Build the sources
%JANET_COMPILE% /Fobuild\janet.obj build\janet.c
@if errorlevel 1 goto :BUILDFAIL
%JANET_COMPILE% /Fobuild\janet.obj build\c\janet.c
@if not errorlevel 0 goto :BUILDFAIL
%JANET_COMPILE% /Fobuild\shell.obj src\mainclient\shell.c
@if errorlevel 1 goto :BUILDFAIL
@if not errorlevel 0 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\janet.obj build\shell.obj build\janet_win.res
@if errorlevel 1 goto :BUILDFAIL
@if not errorlevel 0 goto :BUILDFAIL
@rem Build static library (libjanet.a)
@rem Build static library (libjanet.lib)
%JANET_LINK_STATIC% /out:build\libjanet.lib build\janet.obj
@if errorlevel 1 goto :BUILDFAIL
@if not errorlevel 0 goto :BUILDFAIL
echo === Successfully built janet.exe for Windows ===
echo === Run 'build_win test' to run tests. ==
@ -82,18 +87,20 @@ exit /b 1
@echo command prompt.
exit /b 0
@rem Clean build artifacts
@rem Clean build artifacts
:CLEAN
del *.exe *.lib *.exp
rd /s /q build
rd /s /q dist
if exist dist (
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 not errorlevel 0 goto TESTFAIL
)
exit /b 0
@ -102,9 +109,9 @@ exit /b 0
mkdir dist
janet.exe tools\gendoc.janet > dist\doc.html
janet.exe tools\removecr.janet dist\doc.html
janet.exe tools\removecr.janet build\janet.c
janet.exe tools\removecr.janet build\c\janet.c
copy build\janet.c dist\janet.c
copy build\c\janet.c dist\janet.c
copy src\mainclient\shell.c dist\shell.c
copy janet.exe dist\janet.exe
copy LICENSE dist\LICENSE
@ -112,14 +119,12 @@ copy README.md dist\README.md
copy janet.lib dist\janet.lib
copy janet.exp dist\janet.exp
copy janet.def dist\janet.def
copy src\include\janet.h dist\janet.h
copy src\conf\janetconf.h dist\janetconf.h
janet.exe tools\patch-header.janet src\include\janet.h src\conf\janetconf.h build\janet.h
copy build\janet.h dist\janet.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
@ -148,34 +153,6 @@ FOR %%a in (janet-*-windows-*-installer.msi) DO (
)
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

View File

@ -1,23 +1,22 @@
# Example of dst bytecode assembly
# Fibonacci sequence, implemented with naive recursion.
(def fibasm (asm '{
arity 1
bytecode [
(ltim 1 0 0x2) # $1 = $0 < 2
(jmpif 1 :done) # if ($1) goto :done
(lds 1) # $1 = self
(addim 0 0 -0x1) # $0 = $0 - 1
(push 0) # push($0), push argument for next function call
(call 2 1) # $2 = call($1)
(addim 0 0 -0x1) # $0 = $0 - 1
(push 0) # push($0)
(call 0 1) # $0 = call($1)
(add 0 0 2) # $0 = $0 + $2 (integers)
:done
(ret 0) # return $0
]
}))
(def fibasm
(asm
'{:arity 1
:bytecode @[(ltim 1 0 0x2) # $1 = $0 < 2
(jmpif 1 :done) # if ($1) goto :done
(lds 1) # $1 = self
(addim 0 0 -0x1) # $0 = $0 - 1
(push 0) # push($0), push argument for next function call
(call 2 1) # $2 = call($1)
(addim 0 0 -0x1) # $0 = $0 - 1
(push 0) # push($0)
(call 0 1) # $0 = call($1)
(add 0 0 2) # $0 = $0 + $2 (integers)
:done
(ret 0) # return $0
]}))
# Test it

View File

@ -0,0 +1,22 @@
(defn dowork [name n]
(print name " starting work...")
(os/execute [(dyn :executable) "-e" (string "(os/sleep " n ")")] :p)
(print name " finished work!"))
# Will be done in parallel
(print "starting group A")
(ev/call dowork "A 2" 2)
(ev/call dowork "A 1" 1)
(ev/call dowork "A 3" 3)
(ev/sleep 4)
# Will also be done in parallel
(print "starting group B")
(ev/call dowork "B 2" 2)
(ev/call dowork "B 1" 1)
(ev/call dowork "B 3" 3)
(ev/sleep 4)
(print "all work done")

15
examples/channel.janet Normal file
View File

@ -0,0 +1,15 @@
(def c (ev/chan 4))
(defn writer []
(for i 0 10
(ev/sleep 0.1)
(print "writer giving item " i "...")
(ev/give c (string "item " i))))
(defn reader [name]
(forever
(print "reader " name " got " (ev/take c))))
(ev/call writer)
(each letter [:a :b :c :d :e :f :g]
(ev/call reader letter))

View File

@ -0,0 +1,5 @@
(with [conn (net/connect "127.0.0.1" 8000)]
(print "writing abcdefg...")
(:write conn "abcdefg")
(print "reading...")
(printf "got: %v" (:read conn 1024)))

15
examples/echoserve.janet Normal file
View File

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

45
examples/evlocks.janet Normal file
View File

@ -0,0 +1,45 @@
(defn sleep
"Sleep the entire thread, not just a single fiber."
[n]
(os/sleep (* 0.1 n)))
(defn work [lock n]
(ev/acquire-lock lock)
(print "working " n "...")
(sleep n)
(print "done working...")
(ev/release-lock lock))
(defn reader
[rwlock n]
(ev/acquire-rlock rwlock)
(print "reading " n "...")
(sleep n)
(print "done reading " n "...")
(ev/release-rlock rwlock))
(defn writer
[rwlock n]
(ev/acquire-wlock rwlock)
(print "writing " n "...")
(sleep n)
(print "done writing...")
(ev/release-wlock rwlock))
(defn test-lock
[]
(def lock (ev/lock))
(for i 3 7
(ev/spawn-thread
(work lock i))))
(defn test-rwlock
[]
(def rwlock (ev/rwlock))
(for i 0 20
(if (> 0.1 (math/random))
(ev/spawn-thread (writer rwlock i))
(ev/spawn-thread (reader rwlock i)))))
(test-rwlock)
(test-lock)

22
examples/evsleep.janet Normal file
View File

@ -0,0 +1,22 @@
(defn worker
"Run for a number of iterations."
[name iterations]
(for i 0 iterations
(ev/sleep 1)
(print "worker " name " iteration " i)))
(ev/call worker :a 10)
(ev/sleep 0.2)
(ev/call worker :b 5)
(ev/sleep 0.3)
(ev/call worker :c 12)
(defn worker2
[name]
(repeat 10
(ev/sleep 0.2)
(print name " working")))
(ev/go worker2 :bob)
(ev/go worker2 :joe)
(ev/go worker2 :sally)

71
examples/ffi/gtk.janet Normal file
View File

@ -0,0 +1,71 @@
# :lazy true needed for jpm quickbin
# lazily loads library on first function use
# so the `main` function
# can be marshalled.
(ffi/context "/usr/lib/libgtk-3.so" :lazy true)
(ffi/defbind
gtk-application-new :ptr
"Add docstrings as needed."
[title :string flags :uint])
(ffi/defbind
g-signal-connect-data :ulong
[a :ptr b :ptr c :ptr d :ptr e :ptr f :int])
(ffi/defbind
g-application-run :int
[app :ptr argc :int argv :ptr])
(ffi/defbind
gtk-application-window-new :ptr
[a :ptr])
(ffi/defbind
gtk-button-new-with-label :ptr
[a :ptr])
(ffi/defbind
gtk-container-add :void
[a :ptr b :ptr])
(ffi/defbind
gtk-widget-show-all :void
[a :ptr])
(ffi/defbind
gtk-button-set-label :void
[a :ptr b :ptr])
(def cb (delay (ffi/trampoline :default)))
(defn ffi/array
``Convert a janet array to a buffer that can be passed to FFI functions.
For example, to create an array of type `char *` (array of c strings), one
could use `(ffi/array ["hello" "world"] :ptr)`. One needs to be careful that
array elements are not garbage collected though - the GC can't follow references
inside an arbitrary byte buffer.``
[arr ctype &opt buf]
(default buf @"")
(each el arr
(ffi/write ctype el buf))
buf)
(defn on-active
[app]
(def window (gtk-application-window-new app))
(def btn (gtk-button-new-with-label "Click Me!"))
(g-signal-connect-data btn "clicked" (cb)
(fn [btn] (gtk-button-set-label btn "Hello World"))
nil 1)
(gtk-container-add window btn)
(gtk-widget-show-all window))
(defn main
[&]
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
(g-signal-connect-data app "activate" (cb) on-active nil 1)
# manually build an array with ffi/write
# - we are responsible for preventing gc when the arg array is used
(def argv (ffi/array (dyn *args*) :string))
(g-application-run app (length (dyn *args*)) argv))

205
examples/ffi/so.c Normal file
View File

@ -0,0 +1,205 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#ifdef _WIN32
#define EXPORTER __declspec(dllexport)
#else
#define EXPORTER
#endif
/* Structs */
typedef struct {
int a, b;
float c, d;
} Split;
typedef struct {
float c, d;
int a, b;
} SplitFlip;
typedef struct {
int u, v, w, x, y, z;
} SixInts;
typedef struct {
int a;
int b;
} intint;
typedef struct {
int a;
int b;
int c;
} intintint;
typedef struct {
int64_t a;
int64_t b;
int64_t c;
} big;
/* Functions */
EXPORTER
int int_fn(int a, int b) {
return (a << 2) + b;
}
EXPORTER
double my_fn(int64_t a, int64_t b, const char *x) {
return (double)(a + b) + 0.5 + strlen(x);
}
EXPORTER
double double_fn(double x, double y, double z) {
return (x + y) * z * 3;
}
EXPORTER
double double_many(double x, double y, double z, double w, double a, double b) {
return x + y + z + w + a + b;
}
EXPORTER
double double_lots(
double a,
double b,
double c,
double d,
double e,
double f,
double g,
double h,
double i,
double j) {
return i + j;
}
EXPORTER
double double_lots_2(
double a,
double b,
double c,
double d,
double e,
double f,
double g,
double h,
double i,
double j) {
return a +
10.0 * b +
100.0 * c +
1000.0 * d +
10000.0 * e +
100000.0 * f +
1000000.0 * g +
10000000.0 * h +
100000000.0 * i +
1000000000.0 * j;
}
EXPORTER
double float_fn(float x, float y, float z) {
return (x + y) * z;
}
EXPORTER
int intint_fn(double x, intint ii) {
printf("double: %g\n", x);
return ii.a + ii.b;
}
EXPORTER
int intintint_fn(double x, intintint iii) {
printf("double: %g\n", x);
return iii.a + iii.b + iii.c;
}
EXPORTER
intint return_struct(int i) {
intint ret;
ret.a = i;
ret.b = i * i;
return ret;
}
EXPORTER
big struct_big(int i, double d) {
big ret;
ret.a = i;
ret.b = (int64_t) d;
ret.c = ret.a + ret.b + 1000;
return ret;
}
EXPORTER
void void_fn(void) {
printf("void fn ran\n");
}
EXPORTER
void void_fn_2(double y) {
printf("y = %f\n", y);
}
EXPORTER
void void_ret_fn(int x) {
printf("void fn ran: %d\n", x);
}
EXPORTER
int intintint_fn_2(intintint iii, int i) {
fprintf(stderr, "iii.a = %d, iii.b = %d, iii.c = %d, i = %d\n", iii.a, iii.b, iii.c, i);
return i * (iii.a + iii.b + iii.c);
}
EXPORTER
float split_fn(Split s) {
return s.a * s.c + s.b * s.d;
}
EXPORTER
float split_flip_fn(SplitFlip s) {
return s.a * s.c + s.b * s.d;
}
EXPORTER
Split split_ret_fn(int x, float y) {
Split ret;
ret.a = x;
ret.b = x;
ret.c = y;
ret.d = y;
return ret;
}
EXPORTER
SplitFlip split_flip_ret_fn(int x, float y) {
SplitFlip ret;
ret.a = x;
ret.b = x;
ret.c = y;
ret.d = y;
return ret;
}
EXPORTER
SixInts sixints_fn(void) {
return (SixInts) {
6666, 1111, 2222, 3333, 4444, 5555
};
}
EXPORTER
int sixints_fn_2(int x, SixInts s) {
return x + s.u + s.v + s.w + s.x + s.y + s.z;
}
EXPORTER
int sixints_fn_3(SixInts s, int x) {
return x + s.u + s.v + s.w + s.x + s.y + s.z;
}

136
examples/ffi/test.janet Normal file
View File

@ -0,0 +1,136 @@
#
# Simple FFI test script that tests against a simple shared object
#
(def is-windows (= :windows (os/which)))
(def ffi/loc (string "examples/ffi/so." (if is-windows "dll" "so")))
(def ffi/source-loc "examples/ffi/so.c")
(if is-windows
(os/execute ["cl.exe" "/nologo" "/LD" ffi/source-loc "/link" "/DLL" (string "/OUT:" ffi/loc)] :px)
(os/execute ["cc" ffi/source-loc "-shared" "-o" ffi/loc] :px))
(ffi/context ffi/loc)
(def intintint (ffi/struct :int :int :int))
(def big (ffi/struct :s64 :s64 :s64))
(def split (ffi/struct :int :int :float :float))
(def split-flip (ffi/struct :float :float :int :int))
(def six-ints (ffi/struct :int :int :int :int :int :int))
(ffi/defbind int-fn :int [a :int b :int])
(ffi/defbind double-fn :double [a :double b :double c :double])
(ffi/defbind double-many :double
[x :double y :double z :double w :double a :double b :double])
(ffi/defbind double-lots :double
[a :double b :double c :double d :double e :double f :double g :double h :double i :double j :double])
(ffi/defbind float-fn :double
[x :float y :float z :float])
(ffi/defbind intint-fn :int
[x :double ii [:int :int]])
(ffi/defbind return-struct [:int :int]
[i :int])
(ffi/defbind intintint-fn :int
[x :double iii intintint])
(ffi/defbind struct-big big
[i :int d :double])
(ffi/defbind void-fn :void [])
(ffi/defbind double-lots-2 :double
[a :double
b :double
c :double
d :double
e :double
f :double
g :double
h :double
i :double
j :double])
(ffi/defbind void-fn-2 :void [y :double])
(ffi/defbind intintint-fn-2 :int [iii intintint i :int])
(ffi/defbind split-fn :float [s split])
(ffi/defbind split-flip-fn :float [s split-flip])
(ffi/defbind split-ret-fn split [x :int y :float])
(ffi/defbind split-flip-ret-fn split-flip [x :int y :float])
(ffi/defbind sixints-fn six-ints [])
(ffi/defbind sixints-fn-2 :int [x :int s six-ints])
(ffi/defbind sixints-fn-3 :int [s six-ints x :int])
(ffi/defbind-alias int-fn int-fn-aliased :int [a :int b :int])
#
# Struct reading and writing
#
(defn check-round-trip
[t value]
(def buf (ffi/write t value))
(def same-value (ffi/read t buf))
(assert (deep= value same-value)
(string/format "round trip %j (got %j)" value same-value)))
(check-round-trip :bool true)
(check-round-trip :bool false)
(check-round-trip :void nil)
(check-round-trip :void nil)
(check-round-trip :s8 10)
(check-round-trip :s8 0)
(check-round-trip :s8 -10)
(check-round-trip :u8 10)
(check-round-trip :u8 0)
(check-round-trip :s16 10)
(check-round-trip :s16 0)
(check-round-trip :s16 -12312)
(check-round-trip :u16 10)
(check-round-trip :u16 0)
(check-round-trip :u32 0)
(check-round-trip :u32 10)
(check-round-trip :u32 0xFFFF7777)
(check-round-trip :s32 0x7FFF7777)
(check-round-trip :s32 0)
(check-round-trip :s32 -1234567)
(def s (ffi/struct :s8 :s8 :s8 :float))
(check-round-trip s [1 3 5 123.5])
(check-round-trip s [-1 -3 -5 -123.5])
#
# Call functions
#
(tracev (sixints-fn))
(tracev (sixints-fn-2 100 [1 2 3 4 5 6]))
(tracev (sixints-fn-3 [1 2 3 4 5 6] 200))
(tracev (split-ret-fn 10 12))
(tracev (split-flip-ret-fn 10 12))
(tracev (split-flip-ret-fn 12 10))
(tracev (intintint-fn-2 [10 20 30] 3))
(tracev (split-fn [5 6 1.2 3.4]))
(tracev (void-fn-2 10.3))
(tracev (double-many 1 2 3 4 5 6))
(tracev (string/format "%.17g" (double-many 1 2 3 4 5 6)))
(tracev (type (double-many 1 2 3 4 5 6)))
(tracev (double-lots-2 0 1 2 3 4 5 6 7 8 9))
(tracev (void-fn))
(tracev (int-fn 10 20))
(tracev (double-fn 1.5 2.5 3.5))
(tracev (double-lots 1 2 3 4 5 6 7 8 9 10))
(tracev (float-fn 8 4 17))
(tracev (intint-fn 123.456 [10 20]))
(tracev (intintint-fn 123.456 [10 20 30]))
(tracev (return-struct 42))
(tracev (double-lots 1 2 3 4 5 6 700 800 9 10))
(tracev (struct-big 11 99.5))
(tracev (int-fn-aliased 10 20))
(assert (= [10 10 12 12] (split-ret-fn 10 12)))
(assert (= [12 12 10 10] (split-flip-ret-fn 10 12)))
(assert (= 183 (intintint-fn-2 [10 20 31] 3)))
(assert (= 264 (math/round (* 10 (split-fn [5 6 1.2 3.4])))))
(assert (= 9876543210 (double-lots-2 0 1 2 3 4 5 6 7 8 9)))
(assert (= 60 (int-fn 10 20)))
(assert (= 42 (double-fn 1.5 2.5 3.5)))
(assert (= 21 (math/round (double-many 1 2 3 4 5 6.01))))
(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10)))
(assert (= 204 (float-fn 8 4 17)))
(print "Done.")

7
examples/ffi/win32.janet Normal file
View File

@ -0,0 +1,7 @@
(ffi/context "user32.dll")
(ffi/defbind MessageBoxA :int
[w :ptr text :string cap :string typ :int])
(MessageBoxA nil "Hello, World!" "Test" 0)

View File

@ -0,0 +1,19 @@
(def f
(coro
(for i 0 10
(yield (string "yield " i))
(os/sleep 0))))
(print "simple yielding")
(each item f (print "got: " item ", now " (fiber/status f)))
(def f
(coro
(for i 0 10
(yield (string "yield " i))
(ev/sleep 0))))
(print "complex yielding")
(each item f (print "got: " item ", now " (fiber/status f)))
(print (fiber/status f))

BIN
examples/jitfn/hello.bin Normal file

Binary file not shown.

17
examples/jitfn/hello.nasm Normal file
View File

@ -0,0 +1,17 @@
BITS 64
;;;
;;; Code
;;;
mov rax, 1 ; write(
mov rdi, 1 ; STDOUT_FILENO,
lea rsi, [rel msg] ; msg,
mov rdx, msglen ; sizeof(msg)
syscall ; );
ret ; return;
;;;
;;; Constants
;;;
msg: db "Hello, world!", 10
msglen: equ $ - msg

View File

@ -0,0 +1,13 @@
###
### Relies on NASM being installed to assemble code.
### Only works on x86-64 Linux.
###
### Before running, compile hello.nasm to hello.bin with
### $ nasm hello.nasm -o hello.bin
(def bin (slurp "hello.bin"))
(def f (ffi/jitfn bin))
(def signature (ffi/signature :default :void))
(ffi/call f signature)
(print "called a jitted function with FFI!")
(print "machine code: " (describe (string/slice f)))

2
examples/lineloop.janet Normal file
View File

@ -0,0 +1,2 @@
(while (not (empty? (def line (getline))))
(prin "line: " line))

View File

@ -0,0 +1,30 @@
(defn init-db [c]
(def res @{:clients @{}})
(var i 0)
(repeat c
(def n (string "client" i))
(put-in res [:clients n] @{:name n :projects @{}})
(++ i)
(repeat c
(def pn (string "project" i))
(put-in res [:clients n :projects pn] @{:name pn})
(++ i)
(repeat c
(def tn (string "task" i))
(put-in res [:clients n :projects pn :tasks tn] @{:name pn})
(++ i))))
res)
(loop [c :range [30 80 1]]
(var s (os/clock))
(print "Marshal DB with " c " clients, "
(* c c) " projects and "
(* c c c) " tasks. "
"Total " (+ (* c c c) (* c c) c) " tables")
(def buf (marshal (init-db c) @{} @""))
(print "Buffer is " (length buf) " bytes")
(print "Duration " (- (os/clock) s))
(set s (os/clock))
(gccollect)
(print "Collected garbage in " (- (os/clock) s)))

View File

@ -7,13 +7,13 @@ typedef struct {
} num_array;
static num_array *num_array_init(num_array *array, size_t size) {
array->data = (double *)calloc(size, sizeof(double));
array->data = (double *)janet_calloc(size, sizeof(double));
array->size = size;
return array;
}
static void num_array_deinit(num_array *array) {
free(array->data);
janet_free(array->data);
}
static int num_array_gc(void *p, size_t s) {
@ -76,9 +76,16 @@ void num_array_put(void *p, Janet key, Janet value) {
}
}
static Janet num_array_length(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
num_array *array = (num_array *)janet_getabstract(argv, 0, &num_array_type);
return janet_wrap_number(array->size);
}
static const JanetMethod methods[] = {
{"scale", num_array_scale},
{"sum", num_array_sum},
{"length", num_array_length},
{NULL, NULL}
};
@ -109,6 +116,11 @@ static const JanetReg cfuns[] = {
"(numarray/scale numarray factor)\n\n"
"scale numarray by factor"
},
{
"sum", num_array_sum,
"(numarray/sum numarray)\n\n"
"sums numarray"
},
{NULL, NULL, NULL}
};

View File

@ -1,4 +1,4 @@
(import build/numarray)
(import /build/numarray)
(def a (numarray/new 30))
(print (get a 20))

View File

@ -0,0 +1,5 @@
# Switch to python
(print "running in Janet")
(os/posix-exec ["python"] :p)
(print "will not print")

23
examples/select.janet Normal file
View File

@ -0,0 +1,23 @@
(def channels
(seq [:repeat 5] (ev/chan 4)))
(defn writer [c]
(for i 0 3
(def item (string i ":" (mod (hash c) 999)))
(ev/sleep 0.1)
(print "writer giving item " item " to " c "...")
(ev/give c item))
(print "Done!"))
(defn reader [name]
(forever
(def [_ c x] (ev/rselect ;channels))
(print "reader " name " got " x " from " c)))
# Readers
(each letter [:a :b :c :d :e :f :g]
(ev/call reader letter))
# Writers
(each c channels
(ev/call writer c))

37
examples/select2.janet Normal file
View File

@ -0,0 +1,37 @@
###
### examples/select2.janet
###
### Mix reads and writes in select.
###
(def c1 (ev/chan 40))
(def c2 (ev/chan 40))
(def c3 (ev/chan 40))
(def c4 (ev/chan 40))
(def c5 (ev/chan 4))
(defn worker
[c n x]
(forever
(ev/sleep n)
(ev/give c x)))
(defn writer-worker
[c]
(forever
(ev/sleep 0.2)
(print "writing " (ev/take c))))
(ev/call worker c1 1 :item1)
(ev/sleep 0.2)
(ev/call worker c2 1 :item2)
(ev/sleep 0.1)
(ev/call worker c3 1 :item3)
(ev/sleep 0.2)
(ev/call worker c4 1 :item4)
(ev/sleep 0.1)
(ev/call worker c4 1 :item5)
(ev/call writer-worker c5)
(forever (pp (ev/rselect c1 c2 c3 c4 [c5 :thing])))

41
examples/sigaction.janet Normal file
View File

@ -0,0 +1,41 @@
###
### Usage: janet examples/sigaction.janet 1|2|3|4 &
###
### Then at shell: kill -s SIGTERM $!
###
(defn action
[]
(print "Handled SIGTERM!")
(flush)
(os/exit 1))
(defn main1
[]
(os/sigaction :term action true)
(forever))
(defn main2
[]
(os/sigaction :term action)
(forever))
(defn main3
[]
(os/sigaction :term action true)
(forever (ev/sleep math/inf)))
(defn main4
[]
(os/sigaction :term action)
(forever (ev/sleep math/inf)))
(defn main
[& args]
(def which (scan-number (get args 1 "1")))
(case which
1 (main1) # should work
2 (main2) # will not work
3 (main3) # should work
4 (main4) # should work
(error "bad main")))

View File

@ -1,73 +0,0 @@
# 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))))

View File

@ -6,8 +6,15 @@
(def b @"")
(print "Connection " id "!")
(while (:read stream 1024 b)
(repeat 10 (print "work for " id " ...") (ev/sleep 0.1))
(:write stream b)
(buffer/clear b))
(printf "Done %v!" id)))
(net/server "127.0.0.1" "8000" handler)
# Run server.
(let [server (net/server "127.0.0.1" "8000")]
(print "Starting echo server on 127.0.0.1:8000")
(forever
(if-let [conn (:accept server)]
(ev/call handler conn)
(print "no new connections"))))

View File

@ -0,0 +1,22 @@
(def chan (ev/thread-chan 10))
(ev/spawn
(ev/sleep 0)
(print "started fiber!")
(ev/give chan (math/random))
(ev/give chan (math/random))
(ev/give chan (math/random))
(ev/sleep 0.5)
(for i 0 10
(print "giving to channel...")
(ev/give chan (math/random))
(ev/sleep 1))
(print "finished fiber!")
(:close chan))
(ev/do-thread
(print "started thread!")
(ev/sleep 1)
(while (def x (do (print "taking from channel...") (ev/take chan)))
(print "got " x " from thread!"))
(print "finished thread!"))

View File

@ -1,68 +0,0 @@
(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")))

5
examples/udpclient.janet Normal file
View File

@ -0,0 +1,5 @@
(def conn (net/connect "127.0.0.1" "8009" :datagram))
(:write conn (string/format "%q" (os/cryptorand 16)))
(def x (:read conn 1024))
(pp x)

6
examples/udpserver.janet Normal file
View File

@ -0,0 +1,6 @@
(def server (net/listen "127.0.0.1" "8009" :datagram))
(while true
(def buf @"")
(def who (:recv-from server 1024 buf))
(printf "got %q from %v, echoing!" buf who)
(:send-to server who buf))

View File

@ -1,10 +1,10 @@
# 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:
# 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 command
# line, and then at the REPL type:
#
# (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
# This will import a file using curl. You can then try:
#
# (print (c/color :green "Hello!"))
#
@ -13,9 +13,9 @@
(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))
(def p (os/spawn ["curl" url "-s"] :p {:out :pipe}))
(def res (dofile (p :out) :source url ;args))
(:wait p)
res)
(defn- check-http-url

View File

@ -0,0 +1,20 @@
(def weak-k (table/weak-keys 10))
(def weak-v (table/weak-values 10))
(def weak-kv (table/weak 10))
(put weak-kv (gensym) 10)
(put weak-kv :hello :world)
(put weak-k :abc123zz77asda :stuff)
(put weak-k true :abc123zz77asda)
(put weak-k :zyzzyz false)
(put weak-v (gensym) 10)
(put weak-v 20 (gensym))
(print "before gc")
(tracev weak-k)
(tracev weak-v)
(tracev weak-kv)
(gccollect)
(print "after gc")
(tracev weak-k)
(tracev weak-v)
(tracev weak-kv)

61
janet.1
View File

@ -3,11 +3,14 @@
janet \- run the Janet language abstract machine
.SH SYNOPSIS
.B janet
[\fB\-hvsrpnqk\fR]
[\fB\-hvsrpnqik\fR]
[\fB\-e\fR \fISOURCE\fR]
[\fB\-E\fR \fISOURCE ...ARGUMENTS\fR]
[\fB\-l\fR \fIMODULE\fR]
[\fB\-m\fR \fIPATH\fR]
[\fB\-c\fR \fIMODULE JIMAGE\fR]
[\fB\-w\fR \fILEVEL\fR]
[\fB\-x\fR \fILEVEL\fR]
[\fB\-\-\fR]
.BR script
.BR args ...
@ -64,6 +67,10 @@ Move cursor to the beginning of input line.
.BR Ctrl\-B
Move cursor one character to the left.
.TP 16
.BR Ctrl\-D
If on a newline, indicate end of stream and exit the repl.
.TP 16
.BR Ctrl\-E
Move cursor to the end of input line.
@ -100,6 +107,10 @@ Delete one word before the cursor.
.BR Ctrl\-G
Show documentation for the current symbol under the cursor.
.TP 16
.BR Ctrl\-Q
Clear the current command, including already typed lines.
.TP 16
.BR Alt\-B/Alt\-F
Move cursor backwards and forwards one word.
@ -152,6 +163,16 @@ Read raw input from stdin and forgo prompt history and other readline-like featu
Execute a string of Janet source. Source code is executed in the order it is encountered, so earlier
arguments are executed before later ones.
.TP
.BR \-E\ code\ arguments...
Execute a single Janet expression as a Janet short-fn, passing the remaining command line arguments to the expression. This allows
more concise one-liners with command line arguments.
Example: janet -E '(print $0)' 12 is equivalent to '((short-fn (print $0)) 12)', which is in turn equivalent to
`((fn [k] (print k)) 12)`
See docs for the `short-fn` function for more details.
.TP
.BR \-d
Enable debug mode. On all terminating signals as well the debug signal, this will
@ -162,11 +183,19 @@ default repl.
.BR \-n
Disable ANSI colors in the repl. Has no effect if no repl is run.
.TP
.BR \-N
Enable 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
arguments, a REPL is opened.
.TP
.BR \-R
If using the REPL, disable loading the user profile from the JANET_PROFILE environment variable.
.TP
.BR \-p
Turn on the persistent flag. By default, when Janet is executing commands from a file and encounters an error,
@ -193,12 +222,28 @@ Precompiles Janet source code into an image, a binary dump that can be efficient
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 \-i
When this flag is passed, a script passed to the interpreter will be treated as a janet image file
rather than a janet source file.
.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 \-w\ level
Set the warning linting level for Janet.
This linting level should be one of :relaxed, :none, :strict, :normal, or a
Janet number. Any linting message that is of a greater lint level than this setting will be displayed as
a warning, but not stop compilation or execution.
.TP
.BR \-x\ level
Set the error linting level for Janet.
This linting level should be one of :relaxed, :none, :strict, :normal, or a
Janet number. Any linting message that is of a greater lint level will cause a compilation error
and stop compilation.
.TP
.BR \-\-
Stop parsing command line arguments. All arguments after this one will be considered file names
@ -213,6 +258,12 @@ 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_PROFILE
.RS
Path to a profile file that the interpreter will load before entering the REPL. This profile file will
not run for scripts, though. This behavior can be disabled with the -R option.
.RE
.B JANET_HASHSEED
.RS
To disable randomization of Janet's PRF on start up, one can set this variable. This can have the
@ -221,5 +272,11 @@ This variable does nothing in the default configuration of Janet, as PRF is disa
cannot be defined for this variable to have an effect.
.RE
.B NO_COLOR
.RS
Turn off color by default in the repl and in the error handler of scripts. This can be changed at runtime
via dynamic bindings *err-color* and *pretty-format*, or via the command line parameters -n and -N.
.RE
.SH AUTHOR
Written by Calvin Rose <calsrose@gmail.com>

1409
jpm

File diff suppressed because it is too large Load Diff

269
jpm.1
View File

@ -1,269 +0,0 @@
.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.
.TP
.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]\ [\fBdepth\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 standalone 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.
.RE
.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.
.RE
.SH AUTHOR
Written by Calvin Rose <calsrose@gmail.com>

View File

@ -1,4 +1,4 @@
# Copyright (c) 2020 Calvin Rose and contributors
# Copyright (c) 2023 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
@ -19,8 +19,8 @@
# IN THE SOFTWARE.
project('janet', 'c',
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.12.2')
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.34.0')
# Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
@ -30,10 +30,11 @@ header_path = join_paths(get_option('prefix'), get_option('includedir'), 'janet'
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
dl_dep = cc.find_library('dl', required : false)
android_spawn_dep = cc.find_library('android-spawn', required : false)
thread_dep = dependency('threads')
# Link options
if build_machine.system() != 'windows'
if get_option('default_library') != 'static' and build_machine.system() != 'windows'
add_project_link_arguments('-rdynamic', language : 'c')
endif
@ -60,8 +61,9 @@ 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_NO_IPV6', not get_option('ipv6'))
conf.set('JANET_NO_EV', not get_option('ev') or get_option('single_threaded'))
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'))
@ -72,6 +74,12 @@ 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'))
conf.set('JANET_EV_NO_EPOLL', not get_option('epoll'))
conf.set('JANET_EV_NO_KQUEUE', not get_option('kqueue'))
conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt'))
conf.set('JANET_NO_FFI', not get_option('ffi'))
conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit'))
conf.set('JANET_NO_CRYPTORAND', not get_option('cryptorand'))
if get_option('os_name') != ''
conf.set('JANET_OS_NAME', get_option('os_name'))
endif
@ -111,6 +119,8 @@ core_src = [
'src/core/corelib.c',
'src/core/debug.c',
'src/core/emit.c',
'src/core/ev.c',
'src/core/ffi.c',
'src/core/fiber.c',
'src/core/gc.c',
'src/core/inttypes.c',
@ -125,14 +135,13 @@ core_src = [
'src/core/regalloc.c',
'src/core/run.c',
'src/core/specials.c',
'src/core/state.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',
@ -157,38 +166,59 @@ mainclient_src = [
janet_boot = executable('janet-boot', core_src, boot_src,
include_directories : incdir,
c_args : '-DJANET_BOOTSTRAP',
dependencies : [m_dep, dl_dep, thread_dep],
dependencies : [m_dep, dl_dep, thread_dep, android_spawn_dep],
native : true)
# Build janet.c
janetc = custom_target('janetc',
input : [janet_boot],
input : [janet_boot, 'src/boot/boot.janet'],
output : 'janet.c',
capture : true,
command : [
janet_boot, meson.current_source_dir(),
'JANET_PATH', janet_path, 'JANET_HEADERPATH', header_path
'JANET_PATH', janet_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)
janet_dependencies = [m_dep, dl_dep, android_spawn_dep]
if not get_option('single_threaded')
janet_dependencies += thread_dep
endif
# Allow building with no shared library
if cc.has_argument('-fvisibility=hidden')
lib_cflags = ['-fvisibility=hidden']
else
lib_cflags = []
endif
if get_option('shared')
libjanet = library('janet', janetc,
include_directories : incdir,
dependencies : janet_dependencies,
version: meson.project_version(),
soversion: version_parts[0] + '.' + version_parts[1],
c_args : lib_cflags,
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']
if cc.has_argument('-fvisibility=hidden')
extra_cflags = ['-fvisibility=hidden', '-DJANET_DLL_IMPORT']
else
extra_cflags = ['-DJANET_DLL_IMPORT']
endif
janet_mainclient = executable('janet', mainclient_src,
include_directories : incdir,
dependencies : janet_dependencies,
link_with: [libjanet],
c_args : extra_cflags,
install : true)
else
extra_cflags = []
# No shared library
janet_mainclient = executable('janet', mainclient_src, janetc,
include_directories : incdir,
dependencies : janet_dependencies,
c_args : lib_cflags,
install : true)
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)
@ -199,7 +229,7 @@ if meson.is_cross_build()
endif
janet_nativeclient = executable('janet-native', janetc, mainclient_src,
include_directories : incdir,
dependencies : [m_dep, dl_dep, thread_dep],
dependencies : janet_dependencies,
c_args : extra_native_cflags,
native : true)
else
@ -215,17 +245,34 @@ docs = custom_target('docs',
# 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'
'test/suite-array.janet',
'test/suite-asm.janet',
'test/suite-boot.janet',
'test/suite-buffer.janet',
'test/suite-capi.janet',
'test/suite-cfuns.janet',
'test/suite-compile.janet',
'test/suite-corelib.janet',
'test/suite-debug.janet',
'test/suite-ev.janet',
'test/suite-ffi.janet',
'test/suite-inttypes.janet',
'test/suite-io.janet',
'test/suite-marsh.janet',
'test/suite-math.janet',
'test/suite-os.janet',
'test/suite-parse.janet',
'test/suite-peg.janet',
'test/suite-pp.janet',
'test/suite-specials.janet',
'test/suite-string.janet',
'test/suite-strtod.janet',
'test/suite-struct.janet',
'test/suite-symcache.janet',
'test/suite-table.janet',
'test/suite-unknown.janet',
'test/suite-value.janet',
'test/suite-vm.janet'
]
foreach t : test_files
test(t, janet_nativeclient, args : files([t]), workdir : meson.current_source_dir())
@ -235,28 +282,30 @@ endforeach
run_target('repl', command : [janet_nativeclient])
# For use as meson subproject (wrap)
janet_dep = declare_dependency(include_directories : incdir,
link_with : libjanet)
if get_option('shared')
janet_dep = declare_dependency(include_directories : incdir,
link_with : libjanet)
# pkgconfig
pkg = import('pkgconfig')
pkg.generate(libjanet,
description: 'Library for the Janet programming language.')
pkg = import('pkgconfig')
pkg.generate(libjanet,
subdirs: 'janet',
description: 'Library for the Janet programming language.')
endif
# 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'))])
patched_janet = custom_target('patched-janeth',
input : ['tools/patch-header.janet', 'src/include/janet.h', jconf],
install : true,
install_dir : join_paths(get_option('includedir'), 'janet'),
build_by_default : true,
output : ['janet_' + meson.project_version() + '.h'],
command : [janet_nativeclient, '@INPUT@', '@OUTPUT@'])
# Create a version of the janet.h header that matches what jpm often expects
if meson.version().version_compare('>=0.61')
install_symlink('janet.h', pointing_to: 'janet/janet_' + meson.project_version() + '.h', install_dir: get_option('includedir'))
install_symlink('janet.h', pointing_to: 'janet_' + meson.project_version() + '.h', install_dir: join_paths(get_option('includedir'), 'janet'))
endif

View File

@ -8,14 +8,20 @@ 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('ipv6', type : 'boolean', value : true)
option('ev', 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('epoll', type : 'boolean', value : true)
option('kqueue', type : 'boolean', value : true)
option('interpreter_interrupt', type : 'boolean', value : true)
option('ffi', type : 'boolean', value : true)
option('ffi_jit', type : 'boolean', value : true)
option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024)
option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200)
@ -24,3 +30,5 @@ option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7f
option('arch_name', type : 'string', value: '')
option('os_name', type : 'string', value: '')
option('shared', type : 'boolean', value: true)
option('cryptorand', type : 'boolean', value: true)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -93,7 +93,7 @@ int main(int argc, const char **argv) {
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);
unsigned char *boot_buffer = janet_malloc(boot_size);
if (NULL == boot_buffer) {
fprintf(stderr, "Failed to allocate boot buffer\n");
exit(1);
@ -105,7 +105,7 @@ int main(int argc, const char **argv) {
fclose(boot_file);
status = janet_dobytes(env, boot_buffer, (int32_t) boot_size, boot_filename, NULL);
free(boot_buffer);
janet_free(boot_buffer);
/* Deinitialize vm */
janet_deinit();

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -70,6 +70,5 @@ int system_test() {
assert(janet_equals(tuple1, tuple2));
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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

View File

@ -1,36 +1,13 @@
/*
* 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. */
/* This will be generated by the build system if this file is not used */
#ifndef JANETCONF_H
#define JANETCONF_H
#define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 12
#define JANET_VERSION_PATCH 2
#define JANET_VERSION_MINOR 34
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.12.2"
#define JANET_VERSION "1.34.0"
/* #define JANET_BUILD "local" */
@ -50,11 +27,14 @@
/* #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_EV */
/* #define JANET_NO_REALPATH */
/* #define JANET_NO_SYMLINKS */
/* #define JANET_NO_UMASK */
/* #define JANET_NO_THREADS */
/* #define JANET_NO_FFI */
/* #define JANET_NO_FFI_JIT */
/* Other settings */
/* #define JANET_DEBUG */
@ -69,6 +49,19 @@
/* #define JANET_STACK_MAX 16384 */
/* #define JANET_OS_NAME my-custom-os */
/* #define JANET_ARCH_NAME pdp-8 */
/* #define JANET_EV_NO_EPOLL */
/* #define JANET_EV_NO_KQUEUE */
/* #define JANET_NO_INTERPRETER_INTERRUPT */
/* #define JANET_NO_IPV6 */
/* #define JANET_NO_CRYPTORAND */
/* #define JANET_USE_STDATOMIC */
/* Custom vm allocator support */
/* #include <mimalloc.h> */
/* #define janet_malloc(X) mi_malloc((X)) */
/* #define janet_realloc(X, Y) mi_realloc((X), (Y)) */
/* #define janet_calloc(X, Y) mi_calloc((X), (Y)) */
/* #define janet_free(X) mi_free((X)) */
/* Main client settings, does not affect library code */
/* #define JANET_SIMPLE_GETLINE */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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,15 @@
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "util.h"
#include "gc.h"
#include "state.h"
#endif
#ifdef JANET_EV
#ifdef JANET_WINDOWS
#include <windows.h>
#endif
#endif
/* Create new userdata */
@ -43,3 +51,154 @@ void *janet_abstract_end(void *x) {
void *janet_abstract(const JanetAbstractType *atype, size_t size) {
return janet_abstract_end(janet_abstract_begin(atype, size));
}
#ifdef JANET_EV
/*
* Threaded abstracts
*/
void *janet_abstract_begin_threaded(const JanetAbstractType *atype, size_t size) {
JanetAbstractHead *header = janet_malloc(sizeof(JanetAbstractHead) + size);
if (NULL == header) {
JANET_OUT_OF_MEMORY;
}
janet_vm.next_collection += size + sizeof(JanetAbstractHead);
header->gc.flags = JANET_MEMORY_THREADED_ABSTRACT;
header->gc.data.next = NULL; /* Clear memory for address sanitizers */
header->gc.data.refcount = 1;
header->size = size;
header->type = atype;
void *abstract = (void *) & (header->data);
janet_table_put(&janet_vm.threaded_abstracts, janet_wrap_abstract(abstract), janet_wrap_false());
return abstract;
}
void *janet_abstract_end_threaded(void *x) {
janet_gc_settype((void *)(janet_abstract_head(x)), JANET_MEMORY_THREADED_ABSTRACT);
return x;
}
void *janet_abstract_threaded(const JanetAbstractType *atype, size_t size) {
return janet_abstract_end_threaded(janet_abstract_begin_threaded(atype, size));
}
/* Refcounting primitives and sync primitives */
#ifdef JANET_WINDOWS
size_t janet_os_mutex_size(void) {
return sizeof(CRITICAL_SECTION);
}
size_t janet_os_rwlock_size(void) {
return sizeof(void *);
}
void janet_os_mutex_init(JanetOSMutex *mutex) {
InitializeCriticalSection((CRITICAL_SECTION *) mutex);
}
void janet_os_mutex_deinit(JanetOSMutex *mutex) {
DeleteCriticalSection((CRITICAL_SECTION *) mutex);
}
void janet_os_mutex_lock(JanetOSMutex *mutex) {
EnterCriticalSection((CRITICAL_SECTION *) mutex);
}
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
/* error handling? May want to keep counter */
LeaveCriticalSection((CRITICAL_SECTION *) mutex);
}
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
InitializeSRWLock((PSRWLOCK) rwlock);
}
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
/* no op? */
(void) rwlock;
}
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
AcquireSRWLockShared((PSRWLOCK) rwlock);
}
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
AcquireSRWLockExclusive((PSRWLOCK) rwlock);
}
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
ReleaseSRWLockShared((PSRWLOCK) rwlock);
}
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
ReleaseSRWLockExclusive((PSRWLOCK) rwlock);
}
#else
size_t janet_os_mutex_size(void) {
return sizeof(pthread_mutex_t);
}
size_t janet_os_rwlock_size(void) {
return sizeof(pthread_rwlock_t);
}
void janet_os_mutex_init(JanetOSMutex *mutex) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init((pthread_mutex_t *) mutex, &attr);
}
void janet_os_mutex_deinit(JanetOSMutex *mutex) {
pthread_mutex_destroy((pthread_mutex_t *) mutex);
}
void janet_os_mutex_lock(JanetOSMutex *mutex) {
pthread_mutex_lock((pthread_mutex_t *) mutex);
}
void janet_os_mutex_unlock(JanetOSMutex *mutex) {
int ret = pthread_mutex_unlock((pthread_mutex_t *) mutex);
if (ret) janet_panic("cannot release lock");
}
void janet_os_rwlock_init(JanetOSRWLock *rwlock) {
pthread_rwlock_init((pthread_rwlock_t *) rwlock, NULL);
}
void janet_os_rwlock_deinit(JanetOSRWLock *rwlock) {
pthread_rwlock_destroy((pthread_rwlock_t *) rwlock);
}
void janet_os_rwlock_rlock(JanetOSRWLock *rwlock) {
pthread_rwlock_rdlock((pthread_rwlock_t *) rwlock);
}
void janet_os_rwlock_wlock(JanetOSRWLock *rwlock) {
pthread_rwlock_wrlock((pthread_rwlock_t *) rwlock);
}
void janet_os_rwlock_runlock(JanetOSRWLock *rwlock) {
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
}
void janet_os_rwlock_wunlock(JanetOSRWLock *rwlock) {
pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
}
#endif
int32_t janet_abstract_incref(void *abst) {
return janet_atomic_inc(&janet_abstract_head(abst)->gc.data.refcount);
}
int32_t janet_abstract_decref(void *abst) {
return janet_atomic_dec(&janet_abstract_head(abst)->gc.data.refcount);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -30,13 +30,11 @@
#include <string.h>
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
static void janet_array_impl(JanetArray *array, int32_t capacity) {
Janet *data = NULL;
if (capacity > 0) {
janet_vm_next_collection += capacity * sizeof(Janet);
data = (Janet *) malloc(sizeof(Janet) * (size_t) capacity);
janet_vm.next_collection += capacity * sizeof(Janet);
data = (Janet *) janet_malloc(sizeof(Janet) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
@ -44,6 +42,19 @@ JanetArray *janet_array(int32_t capacity) {
array->count = 0;
array->capacity = capacity;
array->data = data;
}
/* Creates a new array */
JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
janet_array_impl(array, capacity);
return array;
}
/* Creates a new array with weak references */
JanetArray *janet_array_weak(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY_WEAK, sizeof(JanetArray));
janet_array_impl(array, capacity);
return array;
}
@ -52,7 +63,7 @@ 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) * (size_t) n);
array->data = janet_malloc(sizeof(Janet) * (size_t) n);
if (!array->data) {
JANET_OUT_OF_MEMORY;
}
@ -68,11 +79,11 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t 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));
newData = janet_realloc(old, capacity * sizeof(Janet));
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
janet_vm_next_collection += (capacity - array->capacity) * sizeof(Janet);
janet_vm.next_collection += (capacity - array->capacity) * sizeof(Janet);
array->data = newData;
array->capacity = capacity;
}
@ -122,16 +133,30 @@ Janet janet_array_peek(JanetArray *array) {
/* C Functions */
static Janet cfun_array_new(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_new,
"(array/new capacity)",
"Creates a new empty array with a pre-allocated capacity. The same as "
"`(array)` but can be more efficient if the maximum size of an array is known.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array(cap);
return janet_wrap_array(array);
}
static Janet cfun_array_new_filled(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_weak,
"(array/weak capacity)",
"Creates a new empty array with a pre-allocated capacity and support for weak references. Similar to `array/new`.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetArray *array = janet_array_weak(cap);
return janet_wrap_array(array);
}
JANET_CORE_FN(cfun_array_new_filled,
"(array/new-filled count &opt value)",
"Creates a new array of `count` elements, all set to `value`, which defaults to nil. Returns the new array.") {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
int32_t count = janet_getnat(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
JanetArray *array = janet_array(count);
for (int32_t i = 0; i < count; i++) {
@ -141,7 +166,10 @@ static Janet cfun_array_new_filled(int32_t argc, Janet *argv) {
return janet_wrap_array(array);
}
static Janet cfun_array_fill(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_fill,
"(array/fill arr &opt value)",
"Replace all elements of an array with `value` (defaulting to nil) without changing the length of the array. "
"Returns the modified array.") {
janet_arity(argc, 1, 2);
JanetArray *array = janet_getarray(argv, 0);
Janet x = (argc == 2) ? argv[1] : janet_wrap_nil();
@ -151,19 +179,26 @@ static Janet cfun_array_fill(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_array_pop(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_pop,
"(array/pop arr)",
"Remove the last element of the array and return it. If the array is empty, will return nil. Modifies "
"the input array.") {
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_CORE_FN(cfun_array_peek,
"(array/peek arr)",
"Returns the last element of the array. Does not modify the array.") {
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_CORE_FN(cfun_array_push,
"(array/push arr & xs)",
"Push all the elements of xs to the end of an array. Modifies the input array and returns it.") {
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
if (INT32_MAX - argc + 1 <= array->count) {
@ -176,7 +211,12 @@ static Janet cfun_array_push(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_ensure,
"(array/ensure arr capacity growth)",
"Ensures that the memory backing the array is large enough for `capacity` "
"items at the given rate of growth. `capacity` and `growth` must be integers. "
"If the backing capacity is already enough, then this function does nothing. "
"Otherwise, the backing memory will be reallocated so that there is enough space.") {
janet_fixarity(argc, 3);
JanetArray *array = janet_getarray(argv, 0);
int32_t newcount = janet_getinteger(argv, 1);
@ -186,7 +226,13 @@ static Janet cfun_array_ensure(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_array_slice(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_slice,
"(array/slice arrtup &opt start end)",
"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 array. By default, `start` is 0 and `end` is the length of the array. "
"Note that if the range is negative, it is taken as (start, end] to allow a full "
"negative slice range. Returns a new array.") {
JanetView view = janet_getindexed(argv, 0);
JanetRange range = janet_getslice(argc, argv);
JanetArray *array = janet_array(range.end - range.start);
@ -196,7 +242,12 @@ static Janet cfun_array_slice(int32_t argc, Janet *argv) {
return janet_wrap_array(array);
}
static Janet cfun_array_concat(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_concat,
"(array/concat arr & parts)",
"Concatenates a variable number of arrays (and tuples) into the first argument, "
"which must be 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`.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetArray *array = janet_getarray(argv, 0);
@ -210,6 +261,11 @@ static Janet cfun_array_concat(int32_t argc, Janet *argv) {
int32_t j, len = 0;
const Janet *vals = NULL;
janet_indexed_view(argv[i], &vals, &len);
if (array->data == vals) {
int32_t newcount = array->count + len;
janet_array_ensure(array, newcount, 2);
janet_indexed_view(argv[i], &vals, &len);
}
for (j = 0; j < len; j++)
janet_array_push(array, vals[j]);
}
@ -219,7 +275,12 @@ static Janet cfun_array_concat(int32_t argc, Janet *argv) {
return janet_wrap_array(array);
}
static Janet cfun_array_insert(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_insert,
"(array/insert arr at & xs)",
"Insert all `xs` into array `arr` at index `at`. `at` should be an integer between "
"0 and the length of the array. A negative value for `at` will index backwards from "
"the end of the array, inserting after the index such that inserting at -1 appends to "
"the array. Returns the array.") {
size_t chunksize, restsize;
janet_arity(argc, 2, -1);
JanetArray *array = janet_getarray(argv, 0);
@ -245,13 +306,18 @@ static Janet cfun_array_insert(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_array_remove(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_remove,
"(array/remove arr at &opt 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.") {
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;
at = array->count + at;
}
if (at < 0 || at > array->count)
janet_panicf("removal index %d out of range [0,%d]", at, array->count);
@ -270,12 +336,14 @@ static Janet cfun_array_remove(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_array_trim(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_array_trim,
"(array/trim arr)",
"Set the backing capacity of an array to its current length. Returns the modified array.") {
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));
Janet *newData = janet_realloc(array->data, array->count * sizeof(Janet));
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
@ -284,96 +352,40 @@ static Janet cfun_array_trim(int32_t argc, Janet *argv) {
}
} else {
array->capacity = 0;
free(array->data);
janet_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/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/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/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/peek", cfun_array_peek,
JDOC("(array/peek arr)\n\n"
"Returns the last element of the array. Does not modify the 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/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/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 variable number of arrays (and tuples) into the first argument "
"which must be 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 xs into array arr at index at. at should be an integer between "
"0 and the length of the array. A negative value for at will index backwards 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}
};
JANET_CORE_FN(cfun_array_clear,
"(array/clear arr)",
"Empties an array, setting it's count to 0 but does not free the backing capacity. "
"Returns the modified array.") {
janet_fixarity(argc, 1);
JanetArray *array = janet_getarray(argv, 0);
array->count = 0;
return argv[0];
}
/* Load the array module */
void janet_lib_array(JanetTable *env) {
janet_core_cfuns(env, NULL, array_cfuns);
JanetRegExt array_cfuns[] = {
JANET_CORE_REG("array/new", cfun_array_new),
JANET_CORE_REG("array/weak", cfun_array_weak),
JANET_CORE_REG("array/new-filled", cfun_array_new_filled),
JANET_CORE_REG("array/fill", cfun_array_fill),
JANET_CORE_REG("array/pop", cfun_array_pop),
JANET_CORE_REG("array/peek", cfun_array_peek),
JANET_CORE_REG("array/push", cfun_array_push),
JANET_CORE_REG("array/ensure", cfun_array_ensure),
JANET_CORE_REG("array/slice", cfun_array_slice),
JANET_CORE_REG("array/concat", cfun_array_concat),
JANET_CORE_REG("array/insert", cfun_array_insert),
JANET_CORE_REG("array/remove", cfun_array_remove),
JANET_CORE_REG("array/trim", cfun_array_trim),
JANET_CORE_REG("array/clear", cfun_array_clear),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, array_cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -75,6 +75,7 @@ static const JanetInstructionDef janet_ops[] = {
{"cmp", JOP_COMPARE},
{"cncl", JOP_CANCEL},
{"div", JOP_DIVIDE},
{"divf", JOP_DIVIDE_FLOOR},
{"divim", JOP_DIVIDE_IMMEDIATE},
{"eq", JOP_EQUALS},
{"eqim", JOP_EQUALS_IMMEDIATE},
@ -137,6 +138,7 @@ static const JanetInstructionDef janet_ops[] = {
{"sru", JOP_SHIFT_RIGHT_UNSIGNED},
{"sruim", JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE},
{"sub", JOP_SUBTRACT},
{"subim", JOP_SUBTRACT_IMMEDIATE},
{"tcall", JOP_TAILCALL},
{"tchck", JOP_TYPECHECK}
};
@ -187,7 +189,11 @@ static void janet_asm_longjmp(JanetAssembler *a) {
/* Throw some kind of assembly error */
static void janet_asm_error(JanetAssembler *a, const char *message) {
a->errmessage = janet_formatc("%s, instruction %d", message, a->errindex);
if (a->errindex < 0) {
a->errmessage = janet_formatc("%s", message);
} else {
a->errmessage = janet_formatc("%s, instruction %d", message, a->errindex);
}
janet_asm_longjmp(a);
}
#define janet_asm_assert(a, c, m) do { if (!(c)) janet_asm_error((a), (m)); } while (0)
@ -224,7 +230,7 @@ static int32_t janet_asm_addenv(JanetAssembler *a, Janet envname) {
janet_table_put(&a->envs, envname, janet_wrap_number(envindex));
if (envindex >= a->environments_capacity) {
int32_t newcap = 2 * envindex;
def->environments = realloc(def->environments, newcap * sizeof(int32_t));
def->environments = janet_realloc(def->environments, newcap * sizeof(int32_t));
if (NULL == def->environments) {
JANET_OUT_OF_MEMORY;
}
@ -516,6 +522,7 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
#endif
if (NULL != a.parent) {
janet_asm_deinit(&a);
a.parent->errmessage = a.errmessage;
janet_asm_longjmp(a.parent);
}
result.funcdef = NULL;
@ -553,6 +560,13 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
x = janet_get1(s, janet_ckeywordv("vararg"));
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
/* Initialize slotcount */
def->slotcount = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG) + def->arity;
/* Check structarg */
x = janet_get1(s, janet_ckeywordv("structarg"));
if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
/* Check source */
x = janet_get1(s, janet_ckeywordv("source"));
if (janet_checktype(x, JANET_STRING)) def->source = janet_unwrap_string(x);
@ -582,7 +596,7 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
x = janet_get1(s, janet_ckeywordv("constants"));
if (janet_indexed_view(x, &arr, &count)) {
def->constants_length = count;
def->constants = malloc(sizeof(Janet) * (size_t) count);
def->constants = janet_malloc(sizeof(Janet) * (size_t) count);
if (NULL == def->constants) {
JANET_OUT_OF_MEMORY;
}
@ -597,6 +611,9 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
/* Parse sub funcdefs */
x = janet_get1(s, janet_ckeywordv("closures"));
if (janet_checktype(x, JANET_NIL)) {
x = janet_get1(s, janet_ckeywordv("defs"));
}
if (janet_indexed_view(x, &arr, &count)) {
int32_t i;
for (i = 0; i < count; i++) {
@ -614,7 +631,7 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
newlen = def->defs_length + 1;
if (a.defs_capacity < newlen) {
int32_t newcap = newlen;
def->defs = realloc(def->defs, newcap * sizeof(JanetFuncDef *));
def->defs = janet_realloc(def->defs, newcap * sizeof(JanetFuncDef *));
if (NULL == def->defs) {
JANET_OUT_OF_MEMORY;
}
@ -643,7 +660,7 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
}
/* Allocate bytecode array */
def->bytecode_length = blength;
def->bytecode = malloc(sizeof(uint32_t) * (size_t) blength);
def->bytecode = janet_malloc(sizeof(uint32_t) * (size_t) blength);
if (NULL == def->bytecode) {
JANET_OUT_OF_MEMORY;
}
@ -685,7 +702,7 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
x = janet_get1(s, janet_ckeywordv("sourcemap"));
if (janet_indexed_view(x, &arr, &count)) {
janet_asm_assert(&a, count == def->bytecode_length, "sourcemap must have the same length as the bytecode");
def->sourcemap = malloc(sizeof(JanetSourceMapping) * (size_t) count);
def->sourcemap = janet_malloc(sizeof(JanetSourceMapping) * (size_t) count);
if (NULL == def->sourcemap) {
JANET_OUT_OF_MEMORY;
}
@ -709,16 +726,70 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
}
}
/* Set symbolmap */
def->symbolmap = NULL;
def->symbolmap_length = 0;
x = janet_get1(s, janet_ckeywordv("symbolmap"));
if (janet_indexed_view(x, &arr, &count)) {
def->symbolmap_length = count;
def->symbolmap = janet_malloc(sizeof(JanetSymbolMap) * (size_t)count);
if (NULL == def->symbolmap) {
JANET_OUT_OF_MEMORY;
}
for (i = 0; i < count; i++) {
const Janet *tup;
Janet entry = arr[i];
JanetSymbolMap ss;
if (!janet_checktype(entry, JANET_TUPLE)) {
janet_asm_error(&a, "expected tuple");
}
tup = janet_unwrap_tuple(entry);
if (janet_keyeq(tup[0], "upvalue")) {
ss.birth_pc = UINT32_MAX;
} else if (!janet_checkint(tup[0])) {
janet_asm_error(&a, "expected integer");
} else {
ss.birth_pc = janet_unwrap_integer(tup[0]);
}
if (!janet_checkint(tup[1])) {
janet_asm_error(&a, "expected integer");
}
if (!janet_checkint(tup[2])) {
janet_asm_error(&a, "expected integer");
}
if (!janet_checktype(tup[3], JANET_SYMBOL)) {
janet_asm_error(&a, "expected symbol");
}
ss.death_pc = janet_unwrap_integer(tup[1]);
ss.slot_index = janet_unwrap_integer(tup[2]);
ss.symbol = janet_unwrap_symbol(tup[3]);
def->symbolmap[i] = ss;
}
}
if (def->symbolmap_length) def->flags |= JANET_FUNCDEF_FLAG_HASSYMBOLMAP;
/* Set environments */
def->environments =
realloc(def->environments, def->environments_length * sizeof(int32_t));
if (NULL == def->environments) {
x = janet_get1(s, janet_ckeywordv("environments"));
if (janet_indexed_view(x, &arr, &count)) {
def->environments_length = count;
if (def->environments_length) {
def->environments = janet_realloc(def->environments, def->environments_length * sizeof(int32_t));
}
for (int32_t i = 0; i < count; i++) {
if (!janet_checkint(arr[i])) {
janet_asm_error(&a, "expected integer");
}
def->environments[i] = janet_unwrap_integer(arr[i]);
}
}
if (def->environments_length && NULL == def->environments) {
JANET_OUT_OF_MEMORY;
}
/* Verify the func def */
if (janet_verify(def)) {
janet_asm_error(&a, "invalid assembly");
int verify_status = janet_verify(def);
if (verify_status) {
janet_asm_errorv(&a, janet_formatc("invalid assembly (%d)", verify_status));
}
/* Add final flags */
@ -861,6 +932,29 @@ static Janet janet_disasm_slotcount(JanetFuncDef *def) {
return janet_wrap_integer(def->slotcount);
}
static Janet janet_disasm_symbolslots(JanetFuncDef *def) {
if (def->symbolmap == NULL) {
return janet_wrap_nil();
}
JanetArray *symbolslots = janet_array(def->symbolmap_length);
Janet upvaluekw = janet_ckeywordv("upvalue");
for (int32_t i = 0; i < def->symbolmap_length; i++) {
JanetSymbolMap ss = def->symbolmap[i];
Janet *t = janet_tuple_begin(4);
if (ss.birth_pc == UINT32_MAX) {
t[0] = upvaluekw;
} else {
t[0] = janet_wrap_integer(ss.birth_pc);
}
t[1] = janet_wrap_integer(ss.death_pc);
t[2] = janet_wrap_integer(ss.slot_index);
t[3] = janet_wrap_symbol(ss.symbol);
symbolslots->data[i] = janet_wrap_tuple(janet_tuple_end(t));
}
symbolslots->count = def->symbolmap_length;
return janet_wrap_array(symbolslots);
}
static Janet janet_disasm_bytecode(JanetFuncDef *def) {
JanetArray *bcode = janet_array(def->bytecode_length);
for (int32_t i = 0; i < def->bytecode_length; i++) {
@ -884,6 +978,10 @@ static Janet janet_disasm_vararg(JanetFuncDef *def) {
return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_VARARG);
}
static Janet janet_disasm_structarg(JanetFuncDef *def) {
return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_STRUCTARG);
}
static Janet janet_disasm_constants(JanetFuncDef *def) {
JanetArray *constants = janet_array(def->constants_length);
for (int32_t i = 0; i < def->constants_length; i++) {
@ -933,8 +1031,10 @@ Janet janet_disasm(JanetFuncDef *def) {
janet_table_put(ret, janet_ckeywordv("bytecode"), janet_disasm_bytecode(def));
janet_table_put(ret, janet_ckeywordv("source"), janet_disasm_source(def));
janet_table_put(ret, janet_ckeywordv("vararg"), janet_disasm_vararg(def));
janet_table_put(ret, janet_ckeywordv("structarg"), janet_disasm_structarg(def));
janet_table_put(ret, janet_ckeywordv("name"), janet_disasm_name(def));
janet_table_put(ret, janet_ckeywordv("slotcount"), janet_disasm_slotcount(def));
janet_table_put(ret, janet_ckeywordv("symbolmap"), janet_disasm_symbolslots(def));
janet_table_put(ret, janet_ckeywordv("constants"), janet_disasm_constants(def));
janet_table_put(ret, janet_ckeywordv("sourcemap"), janet_disasm_sourcemap(def));
janet_table_put(ret, janet_ckeywordv("environments"), janet_disasm_environments(def));
@ -942,18 +1042,40 @@ Janet janet_disasm(JanetFuncDef *def) {
return janet_wrap_struct(janet_table_to_struct(ret));
}
/* C Function for assembly */
static Janet cfun_asm(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_asm,
"(asm assembly)",
"Returns a new function that is the compiled result of the assembly.\n"
"The syntax for the assembly can be found on the Janet website, and should correspond\n"
"to the return value of disasm. Will throw an\n"
"error on invalid assembly.") {
janet_fixarity(argc, 1);
JanetAssembleResult res;
res = janet_asm(argv[0], 0);
if (res.status != JANET_ASSEMBLE_OK) {
janet_panics(res.error);
janet_panics(res.error ? res.error : janet_cstring("invalid assembly"));
}
return janet_wrap_function(janet_thunk(res.funcdef));
}
static Janet cfun_disasm(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_disasm,
"(disasm func &opt field)",
"Returns assembly that could be used to compile the given function. "
"func must be a function, not a c function. Will throw on error on a badly "
"typed argument. If given a field name, will only return that part of the function assembly. "
"Possible fields are:\n\n"
"* :arity - number of required and optional arguments.\n"
"* :min-arity - minimum number of arguments function can be called with.\n"
"* :max-arity - maximum number of arguments function can be called with.\n"
"* :vararg - true if function can take a variable number of arguments.\n"
"* :bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n"
"* :source - name of source file that this function was compiled from.\n"
"* :name - name of function.\n"
"* :slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n"
"* :symbolmap - all symbols and their slots.\n"
"* :constants - an array of constants referenced by this function.\n"
"* :sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n"
"* :environments - an internal mapping of which enclosing functions are referenced for bindings.\n"
"* :defs - other function definitions that this function may instantiate.\n") {
janet_arity(argc, 1, 2);
JanetFunction *f = janet_getfunction(argv, 0);
if (argc == 2) {
@ -965,6 +1087,7 @@ static Janet cfun_disasm(int32_t argc, Janet *argv) {
if (!janet_cstrcmp(kw, "source")) return janet_disasm_source(f->def);
if (!janet_cstrcmp(kw, "name")) return janet_disasm_name(f->def);
if (!janet_cstrcmp(kw, "vararg")) return janet_disasm_vararg(f->def);
if (!janet_cstrcmp(kw, "structarg")) return janet_disasm_structarg(f->def);
if (!janet_cstrcmp(kw, "slotcount")) return janet_disasm_slotcount(f->def);
if (!janet_cstrcmp(kw, "constants")) return janet_disasm_constants(f->def);
if (!janet_cstrcmp(kw, "sourcemap")) return janet_disasm_sourcemap(f->def);
@ -976,41 +1099,14 @@ static Janet cfun_disasm(int32_t argc, Janet *argv) {
}
}
static const JanetReg asm_cfuns[] = {
{
"asm", cfun_asm,
JDOC("(asm assembly)\n\n"
"Returns a new function that is the compiled result of the assembly.\n"
"The syntax for the assembly can be found on the Janet website, and should correspond\n"
"to the return value of disasm. Will throw an\n"
"error on invalid assembly.")
},
{
"disasm", cfun_disasm,
JDOC("(disasm func &opt field)\n\n"
"Returns assembly that could be used be compile the given function.\n"
"func must be a function, not a c function. Will throw on error on a badly\n"
"typed argument. If given a field name, will only return that part of the function assembly.\n"
"Possible fields are:\n\n"
"\t:arity - number of required and optional arguments.\n"
"\t:min-arity - minimum number of arguments function can be called with.\n"
"\t:max-arity - maximum number of arguments function can be called with.\n"
"\t:vararg - true if function can take a variable number of arguments.\n"
"\t:bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n"
"\t:source - name of source file that this function was compiled from.\n"
"\t:name - name of function.\n"
"\t:slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n"
"\t:constants - an array of constants referenced by this function.\n"
"\t:sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n"
"\t:environments - an internal mapping of which enclosing functions are referenced for bindings.\n"
"\t:defs - other function definitions that this function may instantiate.\n")
},
{NULL, NULL, NULL}
};
/* Load the library */
void janet_lib_asm(JanetTable *env) {
janet_core_cfuns(env, NULL, asm_cfuns);
JanetRegExt asm_cfuns[] = {
JANET_CORE_REG("asm", cfun_asm),
JANET_CORE_REG("disasm", cfun_disasm),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, asm_cfuns);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -28,15 +28,21 @@
#include "state.h"
#endif
/* Allow for managed buffers that cannot realloc/free their backing memory */
static void janet_buffer_can_realloc(JanetBuffer *buffer) {
if (buffer->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC) {
janet_panic("buffer cannot reallocate foreign memory");
}
}
/* Initialize a buffer */
JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
static JanetBuffer *janet_buffer_init_impl(JanetBuffer *buffer, int32_t capacity) {
uint8_t *data = NULL;
if (capacity > 0) {
janet_gcpressure(capacity);
data = malloc(sizeof(uint8_t) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
if (capacity < 4) capacity = 4;
janet_gcpressure(capacity);
data = janet_malloc(sizeof(uint8_t) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
buffer->count = 0;
buffer->capacity = capacity;
@ -44,15 +50,37 @@ JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
return buffer;
}
/* Initialize a buffer */
JanetBuffer *janet_buffer_init(JanetBuffer *buffer, int32_t capacity) {
janet_buffer_init_impl(buffer, capacity);
buffer->gc.data.next = NULL;
buffer->gc.flags = JANET_MEM_DISABLED;
return buffer;
}
/* Initialize an unmanaged buffer */
JanetBuffer *janet_pointer_buffer_unsafe(void *memory, int32_t capacity, int32_t count) {
if (count < 0) janet_panic("count < 0");
if (capacity < count) janet_panic("capacity < count");
JanetBuffer *buffer = janet_gcalloc(JANET_MEMORY_BUFFER, sizeof(JanetBuffer));
buffer->gc.flags |= JANET_BUFFER_FLAG_NO_REALLOC;
buffer->capacity = capacity;
buffer->count = count;
buffer->data = (uint8_t *) memory;
return buffer;
}
/* Deinitialize a buffer (free data memory) */
void janet_buffer_deinit(JanetBuffer *buffer) {
free(buffer->data);
if (!(buffer->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC)) {
janet_free(buffer->data);
}
}
/* Initialize a buffer */
JanetBuffer *janet_buffer(int32_t capacity) {
JanetBuffer *buffer = janet_gcalloc(JANET_MEMORY_BUFFER, sizeof(JanetBuffer));
return janet_buffer_init(buffer, capacity);
return janet_buffer_init_impl(buffer, capacity);
}
/* Ensure that the buffer has enough internal capacity */
@ -60,10 +88,11 @@ 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;
janet_buffer_can_realloc(buffer);
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));
new_data = janet_realloc(old, (size_t) capacity * sizeof(uint8_t));
if (NULL == new_data) {
JANET_OUT_OF_MEMORY;
}
@ -92,8 +121,9 @@ void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
}
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_buffer_can_realloc(buffer);
int32_t new_capacity = (new_size > (INT32_MAX / 2)) ? INT32_MAX : (new_size * 2);
uint8_t *new_data = janet_realloc(buffer->data, new_capacity * sizeof(uint8_t));
janet_gcpressure(new_capacity - buffer->capacity);
if (NULL == new_data) {
JANET_OUT_OF_MEMORY;
@ -105,8 +135,7 @@ void janet_buffer_extra(JanetBuffer *buffer, int32_t n) {
/* Push a cstring to buffer */
void janet_buffer_push_cstring(JanetBuffer *buffer, const char *cstring) {
int32_t len = 0;
while (cstring[len]) ++len;
int32_t len = (int32_t) strlen(cstring);
janet_buffer_push_bytes(buffer, (const uint8_t *) cstring, len);
}
@ -163,28 +192,52 @@ void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x) {
/* C functions */
static Janet cfun_buffer_new(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_new,
"(buffer/new capacity)",
"Creates a new, empty buffer with enough backing memory for `capacity` bytes. "
"Returns a new buffer of length 0.") {
janet_fixarity(argc, 1);
int32_t cap = janet_getinteger(argv, 0);
JanetBuffer *buffer = janet_buffer(cap);
return janet_wrap_buffer(buffer);
}
static Janet cfun_buffer_new_filled(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_new_filled,
"(buffer/new-filled count &opt byte)",
"Creates a new buffer of length `count` filled with `byte`. By default, `byte` is 0. "
"Returns the new buffer.") {
janet_arity(argc, 1, 2);
int32_t count = janet_getinteger(argv, 0);
if (count < 0) count = 0;
int32_t byte = 0;
if (argc == 2) {
byte = janet_getinteger(argv, 1) & 0xFF;
}
JanetBuffer *buffer = janet_buffer(count);
if (buffer->data)
if (buffer->data && count > 0)
memset(buffer->data, byte, count);
buffer->count = count;
return janet_wrap_buffer(buffer);
}
static Janet cfun_buffer_fill(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_frombytes,
"(buffer/from-bytes & byte-vals)",
"Creates a buffer from integer parameters with byte values. All integers "
"will be coerced to the range of 1 byte 0-255.") {
int32_t i;
JanetBuffer *buffer = janet_buffer(argc);
for (i = 0; i < argc; i++) {
int32_t c = janet_getinteger(argv, i);
buffer->data[i] = c & 0xFF;
}
buffer->count = argc;
return janet_wrap_buffer(buffer);
}
JANET_CORE_FN(cfun_buffer_fill,
"(buffer/fill buffer &opt byte)",
"Fill up a buffer with bytes, defaulting to 0s. Does not change the buffer's length. "
"Returns the modified buffer.") {
janet_arity(argc, 1, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t byte = 0;
@ -197,27 +250,29 @@ static Janet cfun_buffer_fill(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_trim(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_trim,
"(buffer/trim buffer)",
"Set the backing capacity of the buffer to the current length of the buffer. Returns the "
"modified buffer.") {
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;
janet_buffer_can_realloc(buffer);
if (buffer->count < buffer->capacity) {
int32_t newcap = buffer->count > 4 ? buffer->count : 4;
uint8_t *newData = janet_realloc(buffer->data, newcap);
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
} else {
buffer->capacity = 0;
free(buffer->data);
buffer->data = NULL;
buffer->data = newData;
buffer->capacity = newcap;
}
return argv[0];
}
static Janet cfun_buffer_u8(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_u8,
"(buffer/push-byte buffer & xs)",
"Append bytes to a buffer. Will expand the buffer as necessary. "
"Returns the modified buffer. Will throw an error if the buffer overflows.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@ -227,7 +282,11 @@ static Janet cfun_buffer_u8(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_word,
"(buffer/push-word buffer & xs)",
"Append machine words to a buffer. The 4 bytes of the integer are appended "
"in twos complement, little endian order, unsigned for all x. Returns the modified buffer. Will "
"throw an error if the buffer overflows.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@ -241,7 +300,12 @@ static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_chars(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_chars,
"(buffer/push-string buffer & xs)",
"Push byte sequences onto the end of a buffer. "
"Will accept any of strings, keywords, symbols, and buffers. "
"Returns the modified buffer. "
"Will throw an error if the buffer overflows.") {
int32_t i;
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
@ -256,14 +320,203 @@ static Janet cfun_buffer_chars(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_clear(int32_t argc, Janet *argv) {
static int should_reverse_bytes(const Janet *argv, int32_t argc) {
JanetKeyword order_kw = janet_getkeyword(argv, argc);
if (!janet_cstrcmp(order_kw, "le")) {
#if JANET_BIG_ENDIAN
return 1;
#endif
} else if (!janet_cstrcmp(order_kw, "be")) {
#if JANET_LITTLE_ENDIAN
return 1;
#endif
} else if (!janet_cstrcmp(order_kw, "native")) {
return 0;
} else {
janet_panicf("expected endianness :le, :be or :native, got %v", argv[1]);
}
return 0;
}
static void reverse_u32(uint8_t bytes[4]) {
uint8_t temp;
temp = bytes[3];
bytes[3] = bytes[0];
bytes[0] = temp;
temp = bytes[2];
bytes[2] = bytes[1];
bytes[1] = temp;
}
static void reverse_u64(uint8_t bytes[8]) {
uint8_t temp;
temp = bytes[7];
bytes[7] = bytes[0];
bytes[0] = temp;
temp = bytes[6];
bytes[6] = bytes[1];
bytes[1] = temp;
temp = bytes[5];
bytes[5] = bytes[2];
bytes[2] = temp;
temp = bytes[4];
bytes[4] = bytes[3];
bytes[3] = temp;
}
JANET_CORE_FN(cfun_buffer_push_uint16,
"(buffer/push-uint16 buffer order data)",
"Push a 16 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int reverse = should_reverse_bytes(argv, 1);
union {
uint16_t data;
uint8_t bytes[2];
} u;
u.data = (uint16_t) janet_getinteger(argv, 2);
if (reverse) {
uint8_t temp = u.bytes[1];
u.bytes[1] = u.bytes[0];
u.bytes[0] = temp;
}
janet_buffer_push_u16(buffer, *(uint16_t *) u.bytes);
return argv[0];
}
JANET_CORE_FN(cfun_buffer_push_uint32,
"(buffer/push-uint32 buffer order data)",
"Push a 32 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int reverse = should_reverse_bytes(argv, 1);
union {
uint32_t data;
uint8_t bytes[4];
} u;
u.data = (uint32_t) janet_getinteger(argv, 2);
if (reverse)
reverse_u32(u.bytes);
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
return argv[0];
}
JANET_CORE_FN(cfun_buffer_push_uint64,
"(buffer/push-uint64 buffer order data)",
"Push a 64 bit unsigned integer data onto the end of the buffer. "
"Returns the modified buffer.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int reverse = should_reverse_bytes(argv, 1);
union {
uint64_t data;
uint8_t bytes[8];
} u;
u.data = (uint64_t) janet_getuinteger64(argv, 2);
if (reverse)
reverse_u64(u.bytes);
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
return argv[0];
}
JANET_CORE_FN(cfun_buffer_push_float32,
"(buffer/push-float32 buffer order data)",
"Push the underlying bytes of a 32 bit float data onto the end of the buffer. "
"Returns the modified buffer.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int reverse = should_reverse_bytes(argv, 1);
union {
float data;
uint8_t bytes[4];
} u;
u.data = (float) janet_getnumber(argv, 2);
if (reverse)
reverse_u32(u.bytes);
janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes);
return argv[0];
}
JANET_CORE_FN(cfun_buffer_push_float64,
"(buffer/push-float64 buffer order data)",
"Push the underlying bytes of a 64 bit float data onto the end of the buffer. "
"Returns the modified buffer.") {
janet_fixarity(argc, 3);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int reverse = should_reverse_bytes(argv, 1);
union {
double data;
uint8_t bytes[8];
} u;
u.data = janet_getnumber(argv, 2);
if (reverse)
reverse_u64(u.bytes);
janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes);
return argv[0];
}
static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) {
for (int32_t i = argc_offset; i < argc; i++) {
if (janet_checktype(argv[i], JANET_NUMBER)) {
janet_buffer_push_u8(buffer, (uint8_t)(janet_getinteger(argv, i) & 0xFF));
} else {
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);
}
}
}
JANET_CORE_FN(cfun_buffer_push_at,
"(buffer/push-at buffer index & xs)",
"Same as buffer/push, but copies the new data into the buffer "
" at index `index`.") {
janet_arity(argc, 2, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t index = janet_getinteger(argv, 1);
int32_t old_count = buffer->count;
if (index < 0 || index > old_count) {
janet_panicf("index out of range [0, %d)", old_count);
}
buffer->count = index;
buffer_push_impl(buffer, argv, 2, argc);
if (buffer->count < old_count) {
buffer->count = old_count;
}
return argv[0];
}
JANET_CORE_FN(cfun_buffer_push,
"(buffer/push buffer & xs)",
"Push both individual bytes and byte sequences to a buffer. For each x in xs, "
"push the byte if x is an integer, otherwise push the bytesequence to the buffer. "
"Thus, this function behaves like both `buffer/push-string` and `buffer/push-byte`. "
"Returns the modified buffer. "
"Will throw an error if the buffer overflows.") {
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
buffer_push_impl(buffer, argv, 1, argc);
return argv[0];
}
JANET_CORE_FN(cfun_buffer_clear,
"(buffer/clear buffer)",
"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.") {
janet_fixarity(argc, 1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
buffer->count = 0;
return argv[0];
}
static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_popn,
"(buffer/popn buffer n)",
"Removes the last `n` bytes from the buffer. Returns the modified buffer.") {
janet_fixarity(argc, 2);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t n = janet_getinteger(argv, 1);
@ -276,7 +529,12 @@ static Janet cfun_buffer_popn(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_slice(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_slice,
"(buffer/slice bytes &opt start end)",
"Takes a slice of a byte sequence from `start` to `end`. The range is half open, "
"[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.") {
JanetByteView view = janet_getbytes(argv, 0);
JanetRange range = janet_getslice(argc, argv);
JanetBuffer *buffer = janet_buffer(range.end - range.start);
@ -300,7 +558,9 @@ static void bitloc(int32_t argc, Janet *argv, JanetBuffer **b, int32_t *index, i
*bit = which_bit;
}
static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_bitset,
"(buffer/bit-set buffer index)",
"Sets the bit at the given bit-index. Returns the buffer.") {
int bit;
int32_t index;
JanetBuffer *buffer;
@ -309,7 +569,9 @@ static Janet cfun_buffer_bitset(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_bitclear,
"(buffer/bit-clear buffer index)",
"Clears the bit at the given bit-index. Returns the buffer.") {
int bit;
int32_t index;
JanetBuffer *buffer;
@ -318,7 +580,9 @@ static Janet cfun_buffer_bitclear(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_bitget,
"(buffer/bit buffer index)",
"Gets the bit at the given bit-index. Returns true if the bit is set, false if not.") {
int bit;
int32_t index;
JanetBuffer *buffer;
@ -326,7 +590,9 @@ static Janet cfun_buffer_bitget(int32_t argc, Janet *argv) {
return janet_wrap_boolean(buffer->data[index] & (1 << bit));
}
static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_bittoggle,
"(buffer/bit-toggle buffer index)",
"Toggles the bit at the given bit index in buffer. Returns the buffer.") {
int bit;
int32_t index;
JanetBuffer *buffer;
@ -335,20 +601,26 @@ static Janet cfun_buffer_bittoggle(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_blit,
"(buffer/blit dest src &opt dest-start src-start src-end)",
"Insert the contents of `src` into `dest`. Can optionally take indices that "
"indicate which part of `src` to copy into which part of `dest`. Indices can be "
"negative in order to index from the end of `src` or `dest`. Returns `dest`.") {
janet_arity(argc, 2, 5);
JanetBuffer *dest = janet_getbuffer(argv, 0);
JanetByteView src = janet_getbytes(argv, 1);
int same_buf = src.bytes == dest->data;
int32_t offset_dest = 0;
int32_t offset_src = 0;
if (argc > 2)
if (argc > 2 && !janet_checktype(argv[2], JANET_NIL))
offset_dest = janet_gethalfrange(argv, 2, dest->count, "dest-start");
if (argc > 3)
if (argc > 3 && !janet_checktype(argv[3], JANET_NIL))
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");
int32_t src_end = src.len;
if (!janet_checktype(argv[4], JANET_NIL))
src_end = janet_gethalfrange(argv, 4, src.len, "src-end");
length_src = src_end - offset_src;
if (length_src < 0) length_src = 0;
} else {
@ -372,7 +644,10 @@ static Janet cfun_buffer_blit(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_buffer_format(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_buffer_format,
"(buffer/format buffer format & args)",
"Snprintf like functionality for printing values into a buffer. Returns "
"the modified buffer.") {
janet_arity(argc, 2, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
const char *strfrmt = (const char *) janet_getstring(argv, 1);
@ -380,106 +655,55 @@ static Janet cfun_buffer_format(int32_t argc, Janet *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/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/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/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/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/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/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}
};
JANET_CORE_FN(cfun_buffer_format_at,
"(buffer/format-at buffer at format & args)",
"Snprintf like functionality for printing values into a buffer. Returns "
"the modified buffer.") {
janet_arity(argc, 2, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
int32_t at = janet_getinteger(argv, 1);
if (at < 0) {
at += buffer->count + 1;
}
if (at > buffer->count || at < 0) janet_panicf("expected index at to be in range [0, %d), got %d", buffer->count, at);
int32_t oldcount = buffer->count;
buffer->count = at;
const char *strfrmt = (const char *) janet_getstring(argv, 2);
janet_buffer_format(buffer, strfrmt, 2, argc, argv);
if (buffer->count < oldcount) {
buffer->count = oldcount;
}
return argv[0];
}
void janet_lib_buffer(JanetTable *env) {
janet_core_cfuns(env, NULL, buffer_cfuns);
JanetRegExt buffer_cfuns[] = {
JANET_CORE_REG("buffer/new", cfun_buffer_new),
JANET_CORE_REG("buffer/new-filled", cfun_buffer_new_filled),
JANET_CORE_REG("buffer/from-bytes", cfun_buffer_frombytes),
JANET_CORE_REG("buffer/fill", cfun_buffer_fill),
JANET_CORE_REG("buffer/trim", cfun_buffer_trim),
JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8),
JANET_CORE_REG("buffer/push-word", cfun_buffer_word),
JANET_CORE_REG("buffer/push-string", cfun_buffer_chars),
JANET_CORE_REG("buffer/push-uint16", cfun_buffer_push_uint16),
JANET_CORE_REG("buffer/push-uint32", cfun_buffer_push_uint32),
JANET_CORE_REG("buffer/push-uint64", cfun_buffer_push_uint64),
JANET_CORE_REG("buffer/push-float32", cfun_buffer_push_float32),
JANET_CORE_REG("buffer/push-float64", cfun_buffer_push_float64),
JANET_CORE_REG("buffer/push", cfun_buffer_push),
JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at),
JANET_CORE_REG("buffer/popn", cfun_buffer_popn),
JANET_CORE_REG("buffer/clear", cfun_buffer_clear),
JANET_CORE_REG("buffer/slice", cfun_buffer_slice),
JANET_CORE_REG("buffer/bit-set", cfun_buffer_bitset),
JANET_CORE_REG("buffer/bit-clear", cfun_buffer_bitclear),
JANET_CORE_REG("buffer/bit", cfun_buffer_bitget),
JANET_CORE_REG("buffer/bit-toggle", cfun_buffer_bittoggle),
JANET_CORE_REG("buffer/blit", cfun_buffer_blit),
JANET_CORE_REG("buffer/format", cfun_buffer_format),
JANET_CORE_REG("buffer/format-at", cfun_buffer_format_at),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, buffer_cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -25,6 +25,7 @@
#include <janet.h>
#include "gc.h"
#include "util.h"
#include "regalloc.h"
#endif
/* Look up table for instructions */
@ -36,11 +37,13 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_0, /* JOP_RETURN_NIL, */
JINT_SSI, /* JOP_ADD_IMMEDIATE, */
JINT_SSS, /* JOP_ADD, */
JINT_SSI, /* JOP_SUBTRACT_IMMEDIATE, */
JINT_SSS, /* JOP_SUBTRACT, */
JINT_SSI, /* JOP_MULTIPLY_IMMEDIATE, */
JINT_SSS, /* JOP_MULTIPLY, */
JINT_SSI, /* JOP_DIVIDE_IMMEDIATE, */
JINT_SSS, /* JOP_DIVIDE, */
JINT_SSS, /* JOP_DIVIDE_FLOOR */
JINT_SSS, /* JOP_MODULO, */
JINT_SSS, /* JOP_REMAINDER, */
JINT_SSS, /* JOP_BAND, */
@ -106,6 +109,294 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = {
JINT_SSS /* JOP_CANCEL, */
};
/* Remove all noops while preserving jumps and debugging information.
* Useful as part of a filtering compiler pass. */
void janet_bytecode_remove_noops(JanetFuncDef *def) {
/* Get an instruction rewrite map so we can rewrite jumps */
uint32_t *pc_map = janet_smalloc(sizeof(uint32_t) * (1 + def->bytecode_length));
uint32_t new_bytecode_length = 0;
for (int32_t i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i];
uint32_t opcode = instr & 0x7F;
pc_map[i] = new_bytecode_length;
if (opcode != JOP_NOOP) {
new_bytecode_length++;
}
}
pc_map[def->bytecode_length] = new_bytecode_length;
/* Linear scan rewrite bytecode and sourcemap. Also fix jumps. */
int32_t j = 0;
for (int32_t i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i];
uint32_t opcode = instr & 0x7F;
int32_t old_jump_target = 0;
int32_t new_jump_target = 0;
switch (opcode) {
case JOP_NOOP:
continue;
case JOP_JUMP:
/* relative pc is in DS field of instruction */
old_jump_target = i + (((int32_t)instr) >> 8);
new_jump_target = pc_map[old_jump_target];
instr += (new_jump_target - old_jump_target + (i - j)) << 8;
break;
case JOP_JUMP_IF:
case JOP_JUMP_IF_NIL:
case JOP_JUMP_IF_NOT:
case JOP_JUMP_IF_NOT_NIL:
/* relative pc is in ES field of instruction */
old_jump_target = i + (((int32_t)instr) >> 16);
new_jump_target = pc_map[old_jump_target];
instr += (new_jump_target - old_jump_target + (i - j)) << 16;
break;
default:
break;
}
def->bytecode[j] = instr;
if (def->sourcemap != NULL) {
def->sourcemap[j] = def->sourcemap[i];
}
j++;
}
/* Rewrite symbolmap */
for (int32_t i = 0; i < def->symbolmap_length; i++) {
JanetSymbolMap *sm = def->symbolmap + i;
/* Don't rewrite upvalue mappings */
if (sm->birth_pc < UINT32_MAX) {
sm->birth_pc = pc_map[sm->birth_pc];
sm->death_pc = pc_map[sm->death_pc];
}
}
def->bytecode_length = new_bytecode_length;
def->bytecode = janet_realloc(def->bytecode, def->bytecode_length * sizeof(uint32_t));
janet_sfree(pc_map);
}
/* Remove redundant loads, moves and other instructions if possible and convert them to
* noops. Input is assumed valid bytecode. */
void janet_bytecode_movopt(JanetFuncDef *def) {
JanetcRegisterAllocator ra;
int recur = 1;
/* Iterate this until no more instructions can be removed. */
while (recur) {
janetc_regalloc_init(&ra);
/* Look for slots that have writes but no reads (and aren't in the closure bitset). */
if (def->closure_bitset != NULL) {
for (int32_t i = 0; i < def->slotcount; i++) {
int32_t index = i >> 5;
uint32_t mask = 1U << (((uint32_t) i) & 31);
if (def->closure_bitset[index] & mask) {
janetc_regalloc_touch(&ra, i);
}
}
}
#define AA ((instr >> 8) & 0xFF)
#define BB ((instr >> 16) & 0xFF)
#define CC (instr >> 24)
#define DD (instr >> 8)
#define EE (instr >> 16)
/* Check reads and writes */
for (int32_t i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i];
switch (instr & 0x7F) {
/* Group instructions my how they read from slots */
/* No reads or writes */
default:
janet_assert(0, "unhandled instruction");
case JOP_JUMP:
case JOP_NOOP:
case JOP_RETURN_NIL:
/* Write A */
case JOP_LOAD_INTEGER:
case JOP_LOAD_CONSTANT:
case JOP_LOAD_UPVALUE:
case JOP_CLOSURE:
/* Write D */
case JOP_LOAD_NIL:
case JOP_LOAD_TRUE:
case JOP_LOAD_FALSE:
case JOP_LOAD_SELF:
break;
case JOP_MAKE_ARRAY:
case JOP_MAKE_BUFFER:
case JOP_MAKE_STRING:
case JOP_MAKE_STRUCT:
case JOP_MAKE_TABLE:
case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE:
/* Reads from the stack, don't remove */
janetc_regalloc_touch(&ra, DD);
break;
/* Read A */
case JOP_ERROR:
case JOP_TYPECHECK:
case JOP_JUMP_IF:
case JOP_JUMP_IF_NOT:
case JOP_JUMP_IF_NIL:
case JOP_JUMP_IF_NOT_NIL:
case JOP_SET_UPVALUE:
/* Write E, Read A */
case JOP_MOVE_FAR:
janetc_regalloc_touch(&ra, AA);
break;
/* Read B */
case JOP_SIGNAL:
/* Write A, Read B */
case JOP_ADD_IMMEDIATE:
case JOP_SUBTRACT_IMMEDIATE:
case JOP_MULTIPLY_IMMEDIATE:
case JOP_DIVIDE_IMMEDIATE:
case JOP_SHIFT_LEFT_IMMEDIATE:
case JOP_SHIFT_RIGHT_IMMEDIATE:
case JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE:
case JOP_GREATER_THAN_IMMEDIATE:
case JOP_LESS_THAN_IMMEDIATE:
case JOP_EQUALS_IMMEDIATE:
case JOP_NOT_EQUALS_IMMEDIATE:
case JOP_GET_INDEX:
janetc_regalloc_touch(&ra, BB);
break;
/* Read D */
case JOP_RETURN:
case JOP_PUSH:
case JOP_PUSH_ARRAY:
case JOP_TAILCALL:
janetc_regalloc_touch(&ra, DD);
break;
/* Write A, Read E */
case JOP_MOVE_NEAR:
case JOP_LENGTH:
case JOP_BNOT:
case JOP_CALL:
janetc_regalloc_touch(&ra, EE);
break;
/* Read A, B */
case JOP_PUT_INDEX:
janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, BB);
break;
/* Read A, E */
case JOP_PUSH_2:
janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, EE);
break;
/* Read B, C */
case JOP_PROPAGATE:
/* Write A, Read B and C */
case JOP_BAND:
case JOP_BOR:
case JOP_BXOR:
case JOP_ADD:
case JOP_SUBTRACT:
case JOP_MULTIPLY:
case JOP_DIVIDE:
case JOP_DIVIDE_FLOOR:
case JOP_MODULO:
case JOP_REMAINDER:
case JOP_SHIFT_LEFT:
case JOP_SHIFT_RIGHT:
case JOP_SHIFT_RIGHT_UNSIGNED:
case JOP_GREATER_THAN:
case JOP_LESS_THAN:
case JOP_EQUALS:
case JOP_COMPARE:
case JOP_IN:
case JOP_GET:
case JOP_GREATER_THAN_EQUAL:
case JOP_LESS_THAN_EQUAL:
case JOP_NOT_EQUALS:
case JOP_CANCEL:
case JOP_RESUME:
case JOP_NEXT:
janetc_regalloc_touch(&ra, BB);
janetc_regalloc_touch(&ra, CC);
break;
/* Read A, B, C */
case JOP_PUT:
case JOP_PUSH_3:
janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, BB);
janetc_regalloc_touch(&ra, CC);
break;
}
}
/* Iterate and set noops on instructions that make writes that no one ever reads.
* Only set noops for instructions with no side effects - moves, loads, etc. that can't
* raise errors (outside of systemic errors like oom or stack overflow). */
recur = 0;
for (int32_t i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i];
switch (instr & 0x7F) {
default:
break;
/* Write D */
case JOP_LOAD_NIL:
case JOP_LOAD_TRUE:
case JOP_LOAD_FALSE:
case JOP_LOAD_SELF:
case JOP_MAKE_ARRAY:
case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE: {
if (!janetc_regalloc_check(&ra, DD)) {
def->bytecode[i] = JOP_NOOP;
recur = 1;
}
}
break;
/* Write E, Read A */
case JOP_MOVE_FAR: {
if (!janetc_regalloc_check(&ra, EE)) {
def->bytecode[i] = JOP_NOOP;
recur = 1;
}
}
break;
/* Write A, Read E */
case JOP_MOVE_NEAR:
/* Write A, Read B */
case JOP_GET_INDEX:
/* Write A */
case JOP_LOAD_INTEGER:
case JOP_LOAD_CONSTANT:
case JOP_LOAD_UPVALUE:
case JOP_CLOSURE: {
if (!janetc_regalloc_check(&ra, AA)) {
def->bytecode[i] = JOP_NOOP;
recur = 1;
}
}
break;
}
}
janetc_regalloc_deinit(&ra);
#undef AA
#undef BB
#undef CC
#undef DD
#undef EE
}
}
/* Verify some bytecode */
int janet_verify(JanetFuncDef *def) {
int vargs = !!(def->flags & JANET_FUNCDEF_FLAG_VARARG);
@ -218,6 +509,7 @@ JanetFuncDef *janet_funcdef_alloc(void) {
def->closure_bitset = NULL;
def->flags = 0;
def->slotcount = 0;
def->symbolmap = NULL;
def->arity = 0;
def->min_arity = 0;
def->max_arity = INT32_MAX;
@ -229,6 +521,7 @@ JanetFuncDef *janet_funcdef_alloc(void) {
def->constants_length = 0;
def->bytecode_length = 0;
def->environments_length = 0;
def->symbolmap_length = 0;
return def;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -35,6 +35,13 @@
#endif
#endif
#ifdef JANET_USE_STDATOMIC
#include <stdatomic.h>
/* We don't need stdatomic on most compilers since we use compiler builtins for atomic operations.
* Some (TCC), explicitly require using stdatomic.h and don't have any exposed builtins (that I know of).
* For TCC and similar compilers, one would need -std=c11 or similar then to get access. */
#endif
JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
#ifdef JANET_TOP_LEVEL_SIGNAL
JANET_TOP_LEVEL_SIGNAL(msg);
@ -51,13 +58,15 @@ JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
}
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 (janet_vm.return_reg != NULL) {
*janet_vm.return_reg = message;
if (NULL != janet_vm.fiber) {
janet_vm.fiber->flags |= JANET_FIBER_DID_LONGJUMP;
}
#if defined(JANET_BSD) || defined(JANET_APPLE)
_longjmp(*janet_vm_jmp_buf, sig);
_longjmp(*janet_vm.signal_buf, sig);
#else
longjmp(*janet_vm_jmp_buf, sig);
longjmp(*janet_vm.signal_buf, sig);
#endif
} else {
const char *str = (const char *)janet_formatc("janet top level signal - %v\n", message);
@ -147,6 +156,23 @@ int janet_getmethod(const uint8_t *method, const JanetMethod *methods, Janet *ou
return 0;
}
Janet janet_nextmethod(const JanetMethod *methods, Janet key) {
if (!janet_checktype(key, JANET_NIL)) {
while (methods->name) {
if (janet_keyeq(key, methods->name)) {
methods++;
break;
}
methods++;
}
}
if (methods->name) {
return janet_ckeywordv(methods->name);
} else {
return janet_wrap_nil();
}
}
DEFINE_GETTER(number, NUMBER, double)
DEFINE_GETTER(array, ARRAY, JanetArray *)
DEFINE_GETTER(tuple, TUPLE, const Janet *)
@ -190,12 +216,46 @@ const char *janet_optcstring(const Janet *argv, int32_t argc, int32_t n, const c
#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");
if (!janet_checktype(argv[n], JANET_STRING)) {
janet_panic_type(argv[n], n, JANET_TFLAG_STRING);
}
return janet_getcbytes(argv, n);
}
const char *janet_getcbytes(const Janet *argv, int32_t n) {
/* Ensure buffer 0-padded */
if (janet_checktype(argv[n], JANET_BUFFER)) {
JanetBuffer *b = janet_unwrap_buffer(argv[n]);
if ((b->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC) && b->count == b->capacity) {
/* Make a copy with janet_smalloc in the rare case we have a buffer that
* cannot be realloced and pushing a 0 byte would panic. */
char *new_string = janet_smalloc(b->count + 1);
memcpy(new_string, b->data, b->count);
new_string[b->count] = 0;
if (strlen(new_string) != (size_t) b->count) goto badzeros;
return new_string;
} else {
/* Ensure trailing 0 */
janet_buffer_push_u8(b, 0);
b->count--;
if (strlen((char *)b->data) != (size_t) b->count) goto badzeros;
return (const char *) b->data;
}
}
JanetByteView view = janet_getbytes(argv, n);
const char *cstr = (const char *)view.bytes;
if (strlen(cstr) != (size_t) view.len) goto badzeros;
return cstr;
badzeros:
janet_panic("bytes contain embedded 0s");
}
const char *janet_optcbytes(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_getcbytes(argv, n);
}
int32_t janet_getnat(const Janet *argv, int32_t n) {
@ -240,12 +300,36 @@ int32_t janet_getinteger(const Janet *argv, int32_t n) {
return janet_unwrap_integer(x);
}
uint32_t janet_getuinteger(const Janet *argv, int32_t n) {
Janet x = argv[n];
if (!janet_checkuint(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) {
#ifdef JANET_INT_TYPES
return janet_unwrap_s64(argv[n]);
#else
Janet x = argv[n];
if (!janet_checkint64(x)) {
janet_panicf("bad slot #%d, expected 64 bit signed integer, got %v", n, x);
}
return (int64_t) janet_unwrap_number(x);
#endif
}
uint64_t janet_getuinteger64(const Janet *argv, int32_t n) {
#ifdef JANET_INT_TYPES
return janet_unwrap_u64(argv[n]);
#else
Janet x = argv[n];
if (!janet_checkuint64(x)) {
janet_panicf("bad slot #%d, expected 64 bit unsigned integer, got %v", n, x);
}
return (uint64_t) janet_unwrap_number(x);
#endif
}
size_t janet_getsize(const Janet *argv, int32_t n) {
@ -261,16 +345,30 @@ int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const c
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);
janet_panicf("%s index %d out of range [%d,%d]", which, (int64_t) raw, -(int64_t)length - 1, (int64_t) length);
return not_raw;
}
int32_t janet_getstartrange(const Janet *argv, int32_t argc, int32_t n, int32_t length) {
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
return 0;
}
return janet_gethalfrange(argv, n, length, "start");
}
int32_t janet_getendrange(const Janet *argv, int32_t argc, int32_t n, int32_t length) {
if (n >= argc || janet_checktype(argv[n], JANET_NIL)) {
return length;
}
return janet_gethalfrange(argv, n, length, "end");
}
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);
janet_panicf("%s index %d out of range [%d,%d)", which, (int64_t)raw, -(int64_t)length, (int64_t)length);
return not_raw;
}
@ -317,48 +415,34 @@ 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;
}
range.start = janet_getstartrange(argv, argc, 1, length);
range.end = janet_getendrange(argv, argc, 2, length);
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) {
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));
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);
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);
if (!janet_vm.fiber->env) {
janet_vm.fiber->env = janet_table(1);
}
janet_table_put(janet_vm_fiber->env, janet_ckeywordv(name), value);
janet_table_put(janet_vm.fiber->env, janet_ckeywordv(name), value);
}
}
@ -414,9 +498,41 @@ void *janet_optabstract(const Janet *argv, int32_t argc, int32_t n, const JanetA
return janet_getabstract(argv, n, at);
}
/* Atomic refcounts */
JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x) {
#ifdef JANET_WINDOWS
return InterlockedIncrement(x);
#elif defined(JANET_USE_STDATOMIC)
return atomic_fetch_add_explicit(x, 1, memory_order_relaxed) + 1;
#else
return __atomic_add_fetch(x, 1, __ATOMIC_RELAXED);
#endif
}
JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x) {
#ifdef JANET_WINDOWS
return InterlockedDecrement(x);
#elif defined(JANET_USE_STDATOMIC)
return atomic_fetch_add_explicit(x, -1, memory_order_acq_rel) - 1;
#else
return __atomic_add_fetch(x, -1, __ATOMIC_ACQ_REL);
#endif
}
JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x) {
#ifdef JANET_WINDOWS
return InterlockedOr(x, 0);
#elif defined(JANET_USE_STDATOMIC)
return atomic_load_explicit(x, memory_order_acquire);
#else
return __atomic_load_n(x, __ATOMIC_ACQUIRE);
#endif
}
/* Some definitions for function-like macros */
JANET_API JanetStructHead *(janet_struct_head)(const JanetKV *st) {
JANET_API JanetStructHead *(janet_struct_head)(JanetStruct st) {
return janet_struct_head(st);
}
@ -424,10 +540,10 @@ JANET_API JanetAbstractHead *(janet_abstract_head)(const void *abstract) {
return janet_abstract_head(abstract);
}
JANET_API JanetStringHead *(janet_string_head)(const uint8_t *s) {
JANET_API JanetStringHead *(janet_string_head)(JanetString s) {
return janet_string_head(s);
}
JANET_API JanetTupleHead *(janet_tuple_head)(const Janet *tuple) {
JANET_API JanetTupleHead *(janet_tuple_head)(JanetTuple tuple) {
return janet_tuple_head(tuple);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -99,7 +99,7 @@ static JanetSlot opfunction(
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;
if (integer > INT8_MAX || integer < INT8_MIN) return 0;
*out = (int8_t) integer;
return 1;
}
@ -116,12 +116,11 @@ static JanetSlot opreduce(
JanetSlot *args,
int op,
int opim,
Janet nullary) {
Janet nullary,
Janet unary) {
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) {
@ -132,19 +131,19 @@ static JanetSlot opreduce(
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);
janetc_emit_sss(c, op, t, janetc_cslot(unary), args[0], 1);
}
return t;
}
t = janetc_gettarget(opts);
if (opim && can_slot_be_imm(args[1], &imm)) {
janetc_emit_ssi(c, opim, t, args[0], neg ? -imm : imm, 1);
janetc_emit_ssi(c, opim, t, args[0], 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);
janetc_emit_ssi(c, opim, t, t, imm, 1);
} else {
janetc_emit_sss(c, op, t, t, args[i], 1);
}
@ -155,7 +154,7 @@ static JanetSlot opreduce(
/* Function optimizers */
static JanetSlot do_propagate(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_PROPAGATE, 0, janet_wrap_nil());
return opreduce(opts, args, JOP_PROPAGATE, 0, janet_wrap_nil(), janet_wrap_nil());
}
static JanetSlot do_error(JanetFopts opts, JanetSlot *args) {
janetc_emit_s(opts.compiler, JOP_ERROR, args[0], 0);
@ -172,7 +171,7 @@ static JanetSlot do_debug(JanetFopts opts, JanetSlot *args) {
return t;
}
static JanetSlot do_in(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_IN, 0, janet_wrap_nil());
return opreduce(opts, args, JOP_IN, 0, janet_wrap_nil(), janet_wrap_nil());
}
static JanetSlot do_get(JanetFopts opts, JanetSlot *args) {
if (janet_v_count(args) == 3) {
@ -192,20 +191,14 @@ static JanetSlot do_get(JanetFopts opts, JanetSlot *args) {
c->buffer[label] |= (current - label) << 16;
return t;
} else {
return opreduce(opts, args, JOP_GET, 0, janet_wrap_nil());
return opreduce(opts, args, JOP_GET, 0, janet_wrap_nil(), 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());
return opreduce(opts, args, JOP_COMPARE, 0, janet_wrap_nil(), janet_wrap_nil());
}
static JanetSlot do_put(JanetFopts opts, JanetSlot *args) {
if (opts.flags & JANET_FOPTS_DROP) {
@ -262,34 +255,43 @@ static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) {
/* Variadic operators specialization */
static JanetSlot do_add(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_ADD, JOP_ADD_IMMEDIATE, janet_wrap_integer(0));
return opreduce(opts, args, JOP_ADD, JOP_ADD_IMMEDIATE, janet_wrap_integer(0), janet_wrap_integer(0));
}
static JanetSlot do_sub(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SUBTRACT, -JOP_ADD_IMMEDIATE, janet_wrap_integer(0));
return opreduce(opts, args, JOP_SUBTRACT, JOP_SUBTRACT_IMMEDIATE, janet_wrap_integer(0), janet_wrap_integer(0));
}
static JanetSlot do_mul(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_MULTIPLY, JOP_MULTIPLY_IMMEDIATE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_MULTIPLY, JOP_MULTIPLY_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_div(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_DIVIDE, JOP_DIVIDE_IMMEDIATE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_DIVIDE, JOP_DIVIDE_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_divf(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_DIVIDE_FLOOR, 0, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_modulo(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_MODULO, 0, janet_wrap_integer(0), janet_wrap_integer(1));
}
static JanetSlot do_remainder(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_REMAINDER, 0, janet_wrap_integer(0), janet_wrap_integer(1));
}
static JanetSlot do_band(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BAND, 0, janet_wrap_integer(-1));
return opreduce(opts, args, JOP_BAND, 0, janet_wrap_integer(-1), janet_wrap_integer(-1));
}
static JanetSlot do_bor(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BOR, 0, janet_wrap_integer(0));
return opreduce(opts, args, JOP_BOR, 0, janet_wrap_integer(0), janet_wrap_integer(0));
}
static JanetSlot do_bxor(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_BXOR, 0, janet_wrap_integer(0));
return opreduce(opts, args, JOP_BXOR, 0, janet_wrap_integer(0), janet_wrap_integer(0));
}
static JanetSlot do_lshift(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_LEFT, JOP_SHIFT_LEFT_IMMEDIATE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_LEFT, JOP_SHIFT_LEFT_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_rshift(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_RIGHT, JOP_SHIFT_RIGHT_IMMEDIATE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_RIGHT, JOP_SHIFT_RIGHT_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_rshiftu(JanetFopts opts, JanetSlot *args) {
return opreduce(opts, args, JOP_SHIFT_RIGHT_UNSIGNED, JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, janet_wrap_integer(1));
return opreduce(opts, args, JOP_SHIFT_RIGHT_UNSIGNED, JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, janet_wrap_integer(1), janet_wrap_integer(1));
}
static JanetSlot do_bnot(JanetFopts opts, JanetSlot *args) {
return genericSS(opts, JOP_BNOT, args[0]);
@ -383,10 +385,11 @@ static const JanetFunOptimizer optimizers[] = {
{fixarity2, do_propagate},
{arity2or3, do_get},
{arity1or2, do_next},
{fixarity2, do_modulo},
{fixarity2, do_remainder},
{NULL, do_modulo},
{NULL, do_remainder},
{fixarity2, do_cmp},
{fixarity2, do_cancel},
{NULL, do_divf}
};
const JanetFunOptimizer *janetc_funopt(uint32_t flags) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -53,6 +53,36 @@ void janetc_cerror(JanetCompiler *c, const char *m) {
janetc_error(c, janet_cstring(m));
}
static const char *janet_lint_level_names[] = {
"relaxed",
"normal",
"strict"
};
/* Emit compiler linter messages */
void janetc_lintf(JanetCompiler *c, JanetCompileLintLevel level, const char *format, ...) {
if (NULL != c->lints) {
/* format message */
va_list args;
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);
const uint8_t *str = janet_string(buffer.data, buffer.count);
janet_buffer_deinit(&buffer);
/* construct linting payload */
Janet *payload = janet_tuple_begin(4);
payload[0] = janet_ckeywordv(janet_lint_level_names[level]);
payload[1] = c->current_mapping.line == -1 ? janet_wrap_nil() : janet_wrap_integer(c->current_mapping.line);
payload[2] = c->current_mapping.column == -1 ? janet_wrap_nil() : janet_wrap_integer(c->current_mapping.column);
payload[3] = janet_wrap_string(str);
janet_array_push(c->lints, janet_wrap_tuple(janet_tuple_end(payload)));
}
}
/* Free a slot */
void janetc_freeslot(JanetCompiler *c, JanetSlot s) {
if (s.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF | JANET_SLOT_NAMED)) return;
@ -63,10 +93,14 @@ void janetc_freeslot(JanetCompiler *c, JanetSlot s) {
/* Add a slot to a scope with a symbol associated with it (def or var). */
void janetc_nameslot(JanetCompiler *c, const uint8_t *sym, JanetSlot s) {
SymPair sp;
int32_t cnt = janet_v_count(c->buffer);
sp.sym = sym;
sp.sym2 = sym;
sp.slot = s;
sp.keep = 0;
sp.slot.flags |= JANET_SLOT_NAMED;
sp.birth_pc = cnt ? cnt - 1 : 0;
sp.death_pc = UINT32_MAX;
janet_v_push(c->scope->syms, sp);
}
@ -129,21 +163,27 @@ void janetc_popscope(JanetCompiler *c) {
if (oldscope->flags & JANET_SCOPE_CLOSURE) {
newscope->flags |= JANET_SCOPE_CLOSURE;
}
if (newscope->ra.max < oldscope->ra.max)
if (newscope->ra.max < oldscope->ra.max) {
newscope->ra.max = oldscope->ra.max;
/* Keep upvalue slots */
for (int32_t i = 0; i < janet_v_count(oldscope->syms); i++) {
SymPair pair = oldscope->syms[i];
if (pair.keep) {
/* The variable should not be lexically accessible */
pair.sym = NULL;
janet_v_push(newscope->syms, pair);
janetc_regalloc_touch(&newscope->ra, pair.slot.index);
}
}
/* Keep upvalue slots and symbols for debugging. */
for (int32_t i = 0; i < janet_v_count(oldscope->syms); i++) {
SymPair pair = oldscope->syms[i];
/* The variable should not be lexically accessible */
pair.sym = NULL;
if (pair.death_pc == UINT32_MAX) {
pair.death_pc = (uint32_t) janet_v_count(c->buffer);
}
if (pair.keep) {
/* The variable should also not be included in the locals */
pair.sym2 = NULL;
janetc_regalloc_touch(&newscope->ra, pair.slot.index);
}
janet_v_push(newscope->syms, pair);
}
}
/* Free the old scope */
janet_v_free(oldscope->consts);
janet_v_free(oldscope->syms);
@ -167,6 +207,39 @@ void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
}
}
static int lookup_missing(
JanetCompiler *c,
const uint8_t *sym,
JanetFunction *handler,
JanetBinding *out) {
int32_t minar = handler->def->min_arity;
int32_t maxar = handler->def->max_arity;
if (minar > 1 || maxar < 1) {
janetc_error(c, janet_cstring("missing symbol lookup handler must take 1 argument"));
return 0;
}
Janet args[1] = { janet_wrap_symbol(sym) };
JanetFiber *fiberp = janet_fiber(handler, 64, 1, args);
if (NULL == fiberp) {
janetc_error(c, janet_cstring("failed to call missing symbol lookup handler"));
return 0;
}
fiberp->env = c->env;
int lock = janet_gclock();
Janet tempOut;
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
janet_gcunlock(lock);
if (status != JANET_SIGNAL_OK) {
janetc_error(c, janet_formatc("(lookup) %V", tempOut));
return 0;
}
/* Convert return value as entry. */
/* Alternative could use janet_resolve_ext(c->env, sym) to read result from environment. */
*out = janet_binding_from_entry(tempOut);
return 1;
}
/* Allow searching for symbols. Return information about the symbol */
JanetSlot janetc_resolve(
JanetCompiler *c,
@ -199,24 +272,62 @@ JanetSlot janetc_resolve(
/* Symbol not found - check for global */
{
Janet check;
JanetBindingType btype = janet_resolve(c->env, sym, &check);
switch (btype) {
JanetBinding binding = janet_resolve_ext(c->env, sym);
if (binding.type == JANET_BINDING_NONE) {
Janet handler = janet_table_get(c->env, janet_ckeywordv("missing-symbol"));
switch (janet_type(handler)) {
case JANET_NIL:
break;
case JANET_FUNCTION:
if (!lookup_missing(c, sym, janet_unwrap_function(handler), &binding))
return janetc_cslot(janet_wrap_nil());
break;
default:
janetc_error(c, janet_formatc("invalid lookup handler %V", handler));
return janetc_cslot(janet_wrap_nil());
}
}
switch (binding.type) {
default:
case JANET_BINDING_NONE:
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);
ret = janetc_cslot(binding.value);
break;
case JANET_BINDING_DYNAMIC_DEF:
case JANET_BINDING_DYNAMIC_MACRO:
ret = janetc_cslot(binding.value);
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOTTYPE_ANY;
ret.flags &= ~JANET_SLOT_CONSTANT;
break;
case JANET_BINDING_VAR: {
JanetSlot ret = janetc_cslot(check);
/* TODO save type info */
ret = janetc_cslot(binding.value);
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
ret.flags &= ~JANET_SLOT_CONSTANT;
return ret;
break;
}
}
JanetCompileLintLevel depLevel = JANET_C_LINT_RELAXED;
switch (binding.deprecation) {
case JANET_BINDING_DEP_NONE:
break;
case JANET_BINDING_DEP_RELAXED:
depLevel = JANET_C_LINT_RELAXED;
break;
case JANET_BINDING_DEP_NORMAL:
depLevel = JANET_C_LINT_NORMAL;
break;
case JANET_BINDING_DEP_STRICT:
depLevel = JANET_C_LINT_STRICT;
break;
}
if (binding.deprecation != JANET_BINDING_DEP_NONE) {
janetc_lintf(c, depLevel, "%q is deprecated", janet_wrap_symbol(sym));
}
return ret;
}
/* Symbol was found */
@ -233,6 +344,7 @@ found:
}
/* non-local scope needs to expose its environment */
JanetScope *original_scope = scope;
pair->keep = 1;
while (scope && !(scope->flags & JANET_SCOPE_FUNCTION))
scope = scope->parent;
@ -254,7 +366,7 @@ found:
/* Check if scope already has env. If so, break */
len = janet_v_count(scope->envs);
for (j = 0; j < len; j++) {
if (scope->envs[j] == envindex) {
if (scope->envs[j].envindex == envindex) {
scopefound = 1;
envindex = j;
break;
@ -263,7 +375,10 @@ found:
/* Add the environment if it is not already referenced */
if (!scopefound) {
len = janet_v_count(scope->envs);
janet_v_push(scope->envs, envindex);
JanetEnvRef ref;
ref.envindex = envindex;
ref.scope = original_scope;
janet_v_push(scope->envs, ref);
envindex = len;
}
}
@ -307,6 +422,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
int32_t i;
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
for (i = 0; i < len; i++) {
janet_v_push(ret, janetc_value(subopts, vals[i]));
}
@ -317,6 +433,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
const JanetKV *kvs = NULL;
int32_t cap = 0, len = 0;
janet_dictionary_view(ds, &kvs, &len, &cap);
@ -399,6 +516,7 @@ void janetc_throwaway(JanetFopts opts, Janet x) {
int32_t mapbufstart = janet_v_count(c->mapbuffer);
janetc_scope(&unusedScope, c, JANET_SCOPE_UNUSED, "unusued");
janetc_value(opts, x);
janetc_lintf(c, JANET_C_LINT_STRICT, "dead code, consider removing %.2q", x);
janetc_popscope(c);
if (c->buffer) {
janet_v__cnt(c->buffer) = bufstart;
@ -439,22 +557,22 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
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);
"%v expects at most %d argument%s, got at least %d",
fun.constant, max, max == 1 ? "" : "s", 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);
"%v expects at most %d argument%s, got %d",
fun.constant, max, max == 1 ? "" : "s", 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);
"%v expects at least %d argument%s, got %d",
fun.constant, min, min == 1 ? "" : "s", min_arity);
janetc_error(c, es);
}
}
@ -504,10 +622,40 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
static JanetSlot janetc_maker(JanetFopts opts, JanetSlot *slots, int op) {
JanetCompiler *c = opts.compiler;
JanetSlot retslot;
janetc_pushslots(c, slots);
janetc_freeslots(c, slots);
retslot = janetc_gettarget(opts);
janetc_emit_s(c, op, retslot, 1);
/* Check if this structure is composed entirely of constants */
int can_inline = 1;
for (int32_t i = 0; i < janet_v_count(slots); i++) {
if (!(slots[i].flags & JANET_SLOT_CONSTANT) ||
(slots[i].flags & JANET_SLOT_SPLICED)) {
can_inline = 0;
break;
}
}
if (can_inline && (op == JOP_MAKE_STRUCT)) {
JanetKV *st = janet_struct_begin(janet_v_count(slots) / 2);
for (int32_t i = 0; i < janet_v_count(slots); i += 2) {
Janet k = slots[i].constant;
Janet v = slots[i + 1].constant;
janet_struct_put(st, k, v);
}
retslot = janetc_cslot(janet_wrap_struct(janet_struct_end(st)));
janetc_freeslots(c, slots);
} else if (can_inline && (op == JOP_MAKE_TUPLE)) {
Janet *tup = janet_tuple_begin(janet_v_count(slots));
for (int32_t i = 0; i < janet_v_count(slots); i++) {
tup[i] = slots[i].constant;
}
retslot = janetc_cslot(janet_wrap_tuple(janet_tuple_end(tup)));
janetc_freeslots(c, slots);
} else {
janetc_pushslots(c, slots);
janetc_freeslots(c, slots);
retslot = janetc_gettarget(opts);
janetc_emit_s(c, op, retslot, 1);
}
return retslot;
}
@ -573,7 +721,7 @@ static int macroexpand1(
}
Janet macroval;
JanetBindingType btype = janet_resolve(c->env, name, &macroval);
if (btype != JANET_BINDING_MACRO ||
if (!(btype == JANET_BINDING_MACRO || btype == JANET_BINDING_DYNAMIC_MACRO) ||
!janet_checktype(macroval, JANET_FUNCTION))
return 0;
@ -598,9 +746,14 @@ static int macroexpand1(
int lock = janet_gclock();
Janet mf_kw = janet_ckeywordv("macro-form");
janet_table_put(c->env, mf_kw, x);
Janet ml_kw = janet_ckeywordv("macro-lints");
if (c->lints) {
janet_table_put(c->env, ml_kw, janet_wrap_array(c->lints));
}
Janet tempOut;
JanetSignal status = janet_continue(fiberp, janet_wrap_nil(), &tempOut);
janet_table_put(c->env, mf_kw, janet_wrap_nil());
janet_table_put(c->env, ml_kw, janet_wrap_nil());
janet_gcunlock(lock);
if (status != JANET_SIGNAL_OK) {
const uint8_t *es = janet_formatc("(macro) %V", tempOut);
@ -733,7 +886,10 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
/* Copy envs */
def->environments_length = janet_v_count(scope->envs);
def->environments = janet_v_flatten(scope->envs);
def->environments = janet_malloc(sizeof(int32_t) * def->environments_length);
for (int32_t i = 0; i < def->environments_length; i++) {
def->environments[i] = scope->envs[i].envindex;
}
def->constants_length = janet_v_count(scope->consts);
def->constants = janet_v_flatten(scope->consts);
@ -745,7 +901,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
def->bytecode_length = janet_v_count(c->buffer) - scope->bytecode_start;
if (def->bytecode_length) {
size_t s = sizeof(int32_t) * (size_t) def->bytecode_length;
def->bytecode = malloc(s);
def->bytecode = janet_malloc(s);
if (NULL == def->bytecode) {
JANET_OUT_OF_MEMORY;
}
@ -753,7 +909,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
janet_v__cnt(c->buffer) = scope->bytecode_start;
if (NULL != c->mapbuffer && c->source) {
size_t s = sizeof(JanetSourceMapping) * (size_t) def->bytecode_length;
def->sourcemap = malloc(s);
def->sourcemap = janet_malloc(s);
if (NULL == def->sourcemap) {
JANET_OUT_OF_MEMORY;
}
@ -778,7 +934,7 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
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);
uint32_t *chunks = janet_calloc(slotchunks, sizeof(uint32_t));
if (NULL == chunks) {
JANET_OUT_OF_MEMORY;
}
@ -788,14 +944,71 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
def->closure_bitset = chunks;
}
/* Capture symbol to local mapping */
JanetSymbolMap *locals = NULL;
/* Symbol -> upvalue mapping */
JanetScope *top = c->scope;
while (top->parent) top = top->parent;
for (JanetScope *s = top; s != NULL; s = s->child) {
for (int32_t j = 0; j < janet_v_count(scope->envs); j++) {
JanetEnvRef ref = scope->envs[j];
JanetScope *upscope = ref.scope;
if (upscope != s) continue;
for (int32_t i = 0; i < janet_v_count(upscope->syms); i++) {
SymPair pair = upscope->syms[i];
if (pair.sym2) {
JanetSymbolMap jsm;
jsm.birth_pc = UINT32_MAX;
jsm.death_pc = j;
jsm.slot_index = pair.slot.index;
jsm.symbol = pair.sym2;
janet_v_push(locals, jsm);
}
}
}
}
/* Symbol -> slot mapping */
for (int32_t i = 0; i < janet_v_count(scope->syms); i++) {
SymPair pair = scope->syms[i];
if (pair.sym2) {
JanetSymbolMap jsm;
if (pair.death_pc == UINT32_MAX) {
jsm.death_pc = def->bytecode_length;
} else {
jsm.death_pc = pair.death_pc - scope->bytecode_start;
}
/* Handle birth_pc == 0 correctly */
if ((uint32_t) scope->bytecode_start > pair.birth_pc) {
jsm.birth_pc = 0;
} else {
jsm.birth_pc = pair.birth_pc - scope->bytecode_start;
}
janet_assert(jsm.birth_pc <= jsm.death_pc, "birth pc after death pc");
janet_assert(jsm.birth_pc < (uint32_t) def->bytecode_length, "bad birth pc");
janet_assert(jsm.death_pc <= (uint32_t) def->bytecode_length, "bad death pc");
jsm.slot_index = pair.slot.index;
jsm.symbol = pair.sym2;
janet_v_push(locals, jsm);
}
}
def->symbolmap_length = janet_v_count(locals);
def->symbolmap = janet_v_flatten(locals);
if (def->symbolmap_length) def->flags |= JANET_FUNCDEF_FLAG_HASSYMBOLMAP;
/* Pop the scope */
janetc_popscope(c);
/* Do basic optimization */
janet_bytecode_movopt(def);
janet_bytecode_remove_noops(def);
return def;
}
/* Initialize a compiler */
static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where) {
static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where, JanetArray *lints) {
c->scope = NULL;
c->buffer = NULL;
c->mapbuffer = NULL;
@ -804,6 +1017,7 @@ static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where)
c->source = where;
c->current_mapping.line = -1;
c->current_mapping.column = -1;
c->lints = lints;
/* Init result */
c->result.error = NULL;
c->result.status = JANET_COMPILE_OK;
@ -821,12 +1035,13 @@ static void janetc_deinit(JanetCompiler *c) {
}
/* Compile a form. */
JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where) {
JanetCompileResult janet_compile_lint(Janet source,
JanetTable *env, const uint8_t *where, JanetArray *lints) {
JanetCompiler c;
JanetScope rootscope;
JanetFopts fopts;
janetc_init(&c, env, where);
janetc_init(&c, env, where, lints);
/* Push a function scope */
janetc_scope(&rootscope, &c, JANET_SCOPE_FUNCTION | JANET_SCOPE_TOP, "root");
@ -841,7 +1056,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");
def->name = janet_cstring("thunk");
janet_def_addflags(def);
c.result.funcdef = def;
} else {
@ -854,26 +1069,51 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
return c.result;
}
JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where) {
return janet_compile_lint(source, env, where, NULL);
}
/* C Function for compiling */
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;
JANET_CORE_FN(cfun_compile,
"(compile ast &opt env source lints)",
"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. "
"If a `lints` array is given, linting messages will be appended to the array. "
"Each message will be a tuple of the form `(level line col message)`.") {
janet_arity(argc, 1, 4);
JanetTable *env = (argc > 1 && !janet_checktype(argv[1], JANET_NIL))
? janet_gettable(argv, 1) : janet_vm.fiber->env;
if (NULL == env) {
env = janet_table(0);
janet_vm_fiber->env = env;
janet_vm.fiber->env = env;
}
const uint8_t *source = NULL;
if (argc == 3) {
source = janet_getstring(argv, 2);
if (argc >= 3) {
Janet x = argv[2];
if (janet_checktype(x, JANET_STRING)) {
source = janet_unwrap_string(x);
} else if (janet_checktype(x, JANET_KEYWORD)) {
source = janet_unwrap_keyword(x);
} else if (!janet_checktype(x, JANET_NIL)) {
janet_panic_type(x, 2, JANET_TFLAG_STRING | JANET_TFLAG_KEYWORD);
}
}
JanetCompileResult res = janet_compile(argv[0], env, source);
JanetArray *lints = (argc >= 4 && !janet_checktype(argv[3], JANET_NIL))
? janet_getarray(argv, 3) : NULL;
JanetCompileResult res = janet_compile_lint(argv[0], env, source, lints);
if (res.status == JANET_COMPILE_OK) {
return janet_wrap_function(janet_thunk(res.funcdef));
} else {
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.error_mapping.line > 0) {
janet_table_put(t, janet_ckeywordv("line"), janet_wrap_integer(res.error_mapping.line));
}
if (res.error_mapping.column > 0) {
janet_table_put(t, janet_ckeywordv("column"), janet_wrap_integer(res.error_mapping.column));
}
if (res.macrofiber) {
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
}
@ -881,18 +1121,10 @@ static Janet cfun(int32_t argc, Janet *argv) {
}
}
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}
};
void janet_lib_compile(JanetTable *env) {
janet_core_cfuns(env, NULL, compile_cfuns);
JanetRegExt cfuns[] = {
JANET_CORE_REG("compile", cfun_compile),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -29,6 +29,13 @@
#include "regalloc.h"
#endif
/* Levels for compiler warnings */
typedef enum {
JANET_C_LINT_RELAXED,
JANET_C_LINT_NORMAL,
JANET_C_LINT_STRICT
} JanetCompileLintLevel;
/* Tags for some functions for the prepared inliner */
#define JANET_FUN_DEBUG 1
#define JANET_FUN_ERROR 2
@ -62,6 +69,7 @@
#define JANET_FUN_REMAINDER 30
#define JANET_FUN_CMP 31
#define JANET_FUN_CANCEL 32
#define JANET_FUN_DIVIDE_FLOOR 33
/* Compiler typedefs */
typedef struct JanetCompiler JanetCompiler;
@ -78,10 +86,10 @@ typedef struct JanetSpecial JanetSpecial;
#define JANET_SLOT_MUTABLE 0x40000
#define JANET_SLOT_REF 0x80000
#define JANET_SLOT_RETURNED 0x100000
/* Needed for handling single element arrays as global vars. */
/* Used for unquote-splicing */
#define JANET_SLOT_SPLICED 0x200000
#define JANET_SLOT_DEP_NOTE 0x200000
#define JANET_SLOT_DEP_WARN 0x400000
#define JANET_SLOT_DEP_ERROR 0x800000
#define JANET_SLOT_SPLICED 0x1000000
#define JANET_SLOTTYPE_ANY 0xFFFF
@ -104,13 +112,21 @@ struct JanetSlot {
typedef struct SymPair {
JanetSlot slot;
const uint8_t *sym;
const uint8_t *sym2;
int keep;
uint32_t birth_pc;
uint32_t death_pc;
} SymPair;
typedef struct JanetEnvRef {
int32_t envindex;
JanetScope *scope;
} JanetEnvRef;
/* A lexical scope during compilation */
struct JanetScope {
/* For debugging */
/* For debugging the compiler */
const char *name;
/* Scopes are doubly linked list */
@ -126,7 +142,7 @@ struct JanetScope {
/* FuncDefs */
JanetFuncDef **defs;
/* Regsiter allocator */
/* Register allocator */
JanetcRegisterAllocator ra;
/* Upvalue allocator */
@ -135,7 +151,7 @@ struct JanetScope {
/* 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;
JanetEnvRef *envs;
int32_t bytecode_start;
int flags;
@ -164,11 +180,15 @@ struct JanetCompiler {
/* Prevent unbounded recursion */
int recursion_guard;
/* Collect linting results */
JanetArray *lints;
};
#define JANET_FOPTS_TAIL 0x10000
#define JANET_FOPTS_HINT 0x20000
#define JANET_FOPTS_DROP 0x40000
#define JANET_FOPTS_ACCEPT_SPLICE 0x80000
/* Options for compiling a single form */
struct JanetFopts {
@ -217,7 +237,7 @@ JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len);
/* Get a bunch of slots for function arguments */
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds);
/* Push slots load via janetc_toslots. */
/* Push slots loaded via janetc_toslots. */
int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
/* Free slots loaded via janetc_toslots */
@ -230,6 +250,9 @@ JanetSlot janetc_return(JanetCompiler *c, JanetSlot s);
void janetc_error(JanetCompiler *c, const uint8_t *m);
void janetc_cerror(JanetCompiler *c, const char *m);
/* Linting */
void janetc_lintf(JanetCompiler *C, JanetCompileLintLevel level, const char *format, ...);
/* Dispatch to correct form compiler */
JanetSlot janetc_value(JanetFopts opts, Janet x);
@ -245,4 +268,8 @@ JanetSlot janetc_cslot(Janet x);
/* Search for a symbol */
JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
/* Bytecode optimization */
void janet_bytecode_movopt(JanetFuncDef *def);
void janet_bytecode_remove_noops(JanetFuncDef *def);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -55,7 +55,7 @@ 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 */
JanetGCObject *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_line = -1;
@ -86,7 +86,7 @@ void janet_debug_find(
}
}
}
current = current->next;
current = current->data.next;
}
if (best_def) {
*def_out = best_def;
@ -96,13 +96,19 @@ void janet_debug_find(
}
}
void janet_stacktrace(JanetFiber *fiber, Janet err) {
const char *prefix = janet_checktype(err, JANET_NIL) ? NULL : "";
janet_stacktrace_ext(fiber, err, prefix);
}
/* Error reporting. This can be emulated from within Janet, but for
* consitency with the top level code it is defined once. */
void janet_stacktrace(JanetFiber *fiber, Janet err) {
void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix) {
int32_t fi;
const char *errstr = (const char *)janet_to_string(err);
JanetFiber **fibers = NULL;
int wrote_error = 0;
int wrote_error = !prefix;
int print_color = janet_truthy(janet_dyn("err-color"));
if (print_color) janet_eprintf("\x1b[31m");
@ -116,6 +122,7 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
fiber = fibers[fi];
int32_t i = fiber->frame;
while (i > 0) {
JanetCFunRegistry *reg = NULL;
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
JanetFuncDef *def = NULL;
i = frame->prevframe;
@ -123,11 +130,10 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
/* Print prelude to stack frame */
if (!wrote_error) {
JanetFiberStatus status = janet_fiber_status(fiber);
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
janet_eprintf("%s%s: %s\n",
prefix,
prefix ? prefix : "",
janet_status_names[status],
errstr);
errstr ? errstr : janet_status_names[status]);
wrote_error = 1;
}
@ -142,15 +148,23 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
} 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
reg = janet_registry_get(cfun);
if (NULL != reg && NULL != reg->name) {
if (reg->name_prefix) {
janet_eprintf(" %s/%s", reg->name_prefix, reg->name);
} else {
janet_eprintf(" %s", reg->name);
}
if (NULL != reg->source_file) {
janet_eprintf(" [%s]", reg->source_file);
}
} else {
janet_eprintf(" <cfunction>");
}
}
}
if (frame->flags & JANET_STACKFRAME_TAILCALL)
janet_eprintf(" (tailcall)");
janet_eprintf(" (tail call)");
if (frame->func && frame->pc) {
int32_t off = (int32_t)(frame->pc - def->bytecode);
if (def->sourcemap) {
@ -159,8 +173,18 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
} else {
janet_eprintf(" pc=%d", off);
}
} else if (NULL != reg) {
/* C Function */
if (reg->source_line > 0) {
janet_eprintf(" on line %d", (long) reg->source_line);
}
}
janet_eprintf("\n");
/* Print fiber points optionally. Clutters traces but provides info
if (i <= 0 && fi > 0) {
janet_eprintf(" in parent fiber\n");
}
*/
}
}
@ -193,7 +217,13 @@ static void helper_find_fun(int32_t argc, Janet *argv, JanetFuncDef **def, int32
*bytecode_offset = offset;
}
static Janet cfun_debug_break(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_break,
"(debug/break source line col)",
"Sets a breakpoint in `source` 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\" 10 4)\n\n"
"will set a breakpoint at line 10, 4th column of the file core.janet.") {
JanetFuncDef *def;
int32_t offset;
helper_find(argc, argv, &def, &offset);
@ -201,7 +231,11 @@ static Janet cfun_debug_break(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_unbreak,
"(debug/unbreak source line column)",
"Remove a breakpoint with a source key at a given line and column. "
"Will throw an error if the breakpoint "
"cannot be found.") {
JanetFuncDef *def;
int32_t offset = 0;
helper_find(argc, argv, &def, &offset);
@ -209,7 +243,11 @@ static Janet cfun_debug_unbreak(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_fbreak,
"(debug/fbreak fun &opt pc)",
"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.") {
JanetFuncDef *def;
int32_t offset = 0;
helper_find_fun(argc, argv, &def, &offset);
@ -217,7 +255,9 @@ static Janet cfun_debug_fbreak(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_unfbreak,
"(debug/unfbreak fun &opt pc)",
"Unset a breakpoint set with debug/fbreak.") {
JanetFuncDef *def;
int32_t offset;
helper_find_fun(argc, argv, &def, &offset);
@ -225,7 +265,12 @@ static Janet cfun_debug_unfbreak(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
static Janet cfun_debug_lineage(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_lineage,
"(debug/lineage fib)",
"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.") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(0);
@ -250,9 +295,20 @@ static Janet doframe(JanetStackFrame *frame) {
} 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_ckeywordv("name"), name);
JanetCFunRegistry *reg = janet_registry_get(cfun);
if (NULL != reg->name) {
if (NULL != reg->name_prefix) {
janet_table_put(t, janet_ckeywordv("name"), janet_wrap_string(janet_formatc("%s/%s", reg->name_prefix, reg->name)));
} else {
janet_table_put(t, janet_ckeywordv("name"), janet_cstringv(reg->name));
}
if (NULL != reg->source_file) {
janet_table_put(t, janet_ckeywordv("source"), janet_cstringv(reg->source_file));
}
if (reg->source_line > 0) {
janet_table_put(t, janet_ckeywordv("source-line"), janet_wrap_integer(reg->source_line));
janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(1));
}
}
}
janet_table_put(t, janet_ckeywordv("c"), janet_wrap_true());
@ -263,6 +319,7 @@ static Janet doframe(JanetStackFrame *frame) {
if (frame->func && frame->pc) {
Janet *stack = (Janet *)frame + JANET_FRAME_SIZE;
JanetArray *slots;
janet_assert(def != NULL, "def != NULL");
off = (int32_t)(frame->pc - def->bytecode);
janet_table_put(t, janet_ckeywordv("pc"), janet_wrap_integer(off));
if (def->sourcemap) {
@ -278,11 +335,46 @@ static Janet doframe(JanetStackFrame *frame) {
safe_memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
slots->count = def->slotcount;
janet_table_put(t, janet_ckeywordv("slots"), janet_wrap_array(slots));
/* Add local bindings */
if (def->symbolmap) {
JanetTable *local_bindings = janet_table(0);
for (int32_t i = def->symbolmap_length - 1; i >= 0; i--) {
JanetSymbolMap jsm = def->symbolmap[i];
Janet value = janet_wrap_nil();
uint32_t pc = (uint32_t)(frame->pc - def->bytecode);
if (jsm.birth_pc == UINT32_MAX) {
JanetFuncEnv *env = frame->func->envs[jsm.death_pc];
if (env->offset > 0) {
value = env->as.fiber->data[env->offset + jsm.slot_index];
} else {
value = env->as.values[jsm.slot_index];
}
} else if (pc >= jsm.birth_pc && pc < jsm.death_pc) {
value = stack[jsm.slot_index];
}
janet_table_put(local_bindings, janet_wrap_symbol(jsm.symbol), value);
}
janet_table_put(t, janet_ckeywordv("locals"), janet_wrap_table(local_bindings));
}
}
return janet_wrap_table(t);
}
static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_stack,
"(debug/stack fib)",
"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"
"* :c - true if the stack frame is a c function invocation\n\n"
"* :source-column - the current source column of the stack frame\n\n"
"* :function - the function that the stack frame represents\n\n"
"* :source-line - the current source line of the stack frame\n\n"
"* :name - the human-friendly name of the function\n\n"
"* :pc - integer indicating the location of the program counter\n\n"
"* :source - string with the file path or other identifier for the source code\n\n"
"* :slots - array of all values in each slot\n\n"
"* :tail - boolean indicating a tail call") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(0);
@ -298,14 +390,24 @@ static Janet cfun_debug_stack(int32_t argc, Janet *argv) {
return janet_wrap_array(array);
}
static Janet cfun_debug_stacktrace(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
JANET_CORE_FN(cfun_debug_stacktrace,
"(debug/stacktrace fiber &opt err prefix)",
"Prints a nice looking stacktrace for a fiber. Can optionally provide "
"an error value to print the stack trace with. If `prefix` is nil or not "
"provided, will skip the error line. Returns the fiber.") {
janet_arity(argc, 1, 3);
JanetFiber *fiber = janet_getfiber(argv, 0);
janet_stacktrace(fiber, argv[1]);
Janet x = argc == 1 ? janet_wrap_nil() : argv[1];
const char *prefix = janet_optcstring(argv, argc, 2, NULL);
janet_stacktrace_ext(fiber, x, prefix);
return argv[0];
}
static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_argstack,
"(debug/arg-stack fiber)",
"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.") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
JanetArray *array = janet_array(fiber->stacktop - fiber->stackstart);
@ -314,7 +416,11 @@ static Janet cfun_debug_argstack(int32_t argc, Janet *argv) {
return janet_wrap_array(array);
}
static Janet cfun_debug_step(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_debug_step,
"(debug/step fiber &opt x)",
"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.") {
janet_arity(argc, 1, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
Janet out = janet_wrap_nil();
@ -322,85 +428,19 @@ static Janet cfun_debug_step(int32_t argc, Janet *argv) {
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/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 */
void janet_lib_debug(JanetTable *env) {
janet_core_cfuns(env, NULL, debug_cfuns);
JanetRegExt debug_cfuns[] = {
JANET_CORE_REG("debug/break", cfun_debug_break),
JANET_CORE_REG("debug/unbreak", cfun_debug_unbreak),
JANET_CORE_REG("debug/fbreak", cfun_debug_fbreak),
JANET_CORE_REG("debug/unfbreak", cfun_debug_unfbreak),
JANET_CORE_REG("debug/arg-stack", cfun_debug_argstack),
JANET_CORE_REG("debug/stack", cfun_debug_stack),
JANET_CORE_REG("debug/stacktrace", cfun_debug_stacktrace),
JANET_CORE_REG("debug/lineage", cfun_debug_lineage),
JANET_CORE_REG("debug/step", cfun_debug_step),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, debug_cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -26,6 +26,7 @@
#include "emit.h"
#include "vector.h"
#include "regalloc.h"
#include "util.h"
#endif
/* Get a register */
@ -128,7 +129,8 @@ static void janetc_movenear(JanetCompiler *c,
((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) |
JOP_LOAD_UPVALUE);
} else if (src.index > 0xFF || src.index != dest) {
} else if (src.index != dest) {
janet_assert(src.index >= 0, "bad slot");
janetc_emit(c,
((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) |
@ -155,6 +157,7 @@ static void janetc_moveback(JanetCompiler *c,
((uint32_t)(src) << 8) |
JOP_SET_UPVALUE);
} else if (dest.index != src) {
janet_assert(dest.index >= 0, "bad slot");
janetc_emit(c,
((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) |

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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

3278
src/core/ev.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -26,9 +26,10 @@
#define JANET_FEATURES_H_defined
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|| defined(__bsdi__) || defined(__DragonFly__)
/* Use BSD soucre on any BSD systems, include OSX */
|| defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__)
/* Use BSD source on any BSD systems, include OSX */
# define _BSD_SOURCE
# define _POSIX_C_SOURCE 200809L
#else
/* Use POSIX feature flags */
# ifndef _POSIX_C_SOURCE
@ -36,13 +37,31 @@
# endif
#endif
#if defined(__APPLE__)
#define _DARWIN_C_SOURCE
#endif
/* Needed for sched.h for cpu count */
#ifdef __linux__
#define _GNU_SOURCE
#endif
#if defined(WIN32) || defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#endif
/* Needed for realpath on linux */
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
#define _XOPEN_SOURCE 500
/* needed for inet_pton and InitializeSRWLock */
#ifdef __MINGW32__
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif
/* Needed for realpath on linux, as well as pthread rwlocks. */
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#if _XOPEN_SOURCE < 600
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
/* Needed for timegm and other extensions when building with -std=c99.
@ -52,4 +71,11 @@
#define _NETBSD_SOURCE
#endif
/* Needed for several things when building with -std=c99. */
#if !__BSD_VISIBLE && (defined(__DragonFly__) || defined(__FreeBSD__))
#define __BSD_VISIBLE 1
#endif
#define _FILE_OFFSET_BITS 64
#endif

1593
src/core/ffi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -37,6 +37,14 @@ static void fiber_reset(JanetFiber *fiber) {
fiber->child = NULL;
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
fiber->env = NULL;
fiber->last_value = janet_wrap_nil();
#ifdef JANET_EV
fiber->sched_id = 0;
fiber->ev_callback = NULL;
fiber->ev_state = NULL;
fiber->ev_stream = NULL;
fiber->supervisor_channel = NULL;
#endif
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
}
@ -47,11 +55,11 @@ static JanetFiber *fiber_alloc(int32_t capacity) {
capacity = 32;
}
fiber->capacity = capacity;
data = malloc(sizeof(Janet) * (size_t) capacity);
data = janet_malloc(sizeof(Janet) * (size_t) capacity);
if (NULL == data) {
JANET_OUT_OF_MEMORY;
}
janet_vm_next_collection += sizeof(Janet) * capacity;
janet_vm.next_collection += sizeof(Janet) * capacity;
fiber->data = data;
return fiber;
}
@ -75,8 +83,12 @@ JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee, int32_t
}
fiber->stacktop = newstacktop;
}
/* Don't panic on failure since we use this to implement janet_pcall */
if (janet_fiber_funcframe(fiber, callee)) return NULL;
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
#ifdef JANET_EV
fiber->supervisor_channel = NULL;
#endif
return fiber;
}
@ -90,12 +102,12 @@ JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, c
static void janet_fiber_refresh_memory(JanetFiber *fiber) {
int32_t n = fiber->capacity;
if (n) {
Janet *newData = malloc(sizeof(Janet) * n);
Janet *newData = janet_malloc(sizeof(Janet) * n);
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
memcpy(newData, fiber->data, fiber->capacity * sizeof(Janet));
free(fiber->data);
janet_free(fiber->data);
fiber->data = newData;
}
}
@ -103,12 +115,15 @@ static void janet_fiber_refresh_memory(JanetFiber *fiber) {
/* 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);
int32_t old_size = fiber->capacity;
int32_t diff = n - old_size;
Janet *newData = janet_realloc(fiber->data, sizeof(Janet) * n);
if (NULL == newData) {
JANET_OUT_OF_MEMORY;
}
fiber->data = newData;
fiber->capacity = n;
janet_vm.next_collection += sizeof(Janet) * diff;
}
/* Grow fiber if needed */
@ -224,8 +239,8 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
fiber->data + tuplehead,
oldtop - tuplehead)
: janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
oldtop - tuplehead));
fiber->data + tuplehead,
oldtop - tuplehead));
}
}
@ -241,8 +256,8 @@ static void janet_env_detach(JanetFuncEnv *env) {
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;
Janet *vmem = janet_malloc(s);
janet_vm.next_collection += (uint32_t) s;
if (NULL == vmem) {
JANET_OUT_OF_MEMORY;
}
@ -355,8 +370,8 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
fiber->data + tuplehead,
fiber->stacktop - tuplehead)
: janet_wrap_tuple(janet_tuple_n(
fiber->data + tuplehead,
fiber->stacktop - tuplehead));
fiber->data + tuplehead,
fiber->stacktop - tuplehead));
}
stacksize = tuplehead - fiber->stackstart + 1;
} else {
@ -410,8 +425,7 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) {
newframe->flags = 0;
}
/* Pop a stack frame from the fiber. Returns the new stack frame, or
* NULL if there are no more frames */
/* Pop a stack frame from the fiber. */
void janet_fiber_popframe(JanetFiber *fiber) {
JanetStackFrame *frame = janet_fiber_frame(fiber);
if (fiber->frame == 0) return;
@ -430,16 +444,19 @@ JanetFiberStatus janet_fiber_status(JanetFiber *f) {
}
JanetFiber *janet_current_fiber(void) {
return janet_vm_fiber;
return janet_vm.fiber;
}
JanetFiber *janet_root_fiber(void) {
return janet_vm_root_fiber;
return janet_vm.root_fiber;
}
/* CFuns */
static Janet cfun_fiber_getenv(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_getenv,
"(fiber/getenv fiber)",
"Gets the environment for a fiber. Returns nil if no such table is "
"set yet.") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return fiber->env ?
@ -447,7 +464,10 @@ static Janet cfun_fiber_getenv(int32_t argc, Janet *argv) {
janet_wrap_nil();
}
static Janet cfun_fiber_setenv(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_setenv,
"(fiber/setenv fiber table)",
"Sets the environment table for a fiber. Set to nil to remove the current "
"environment.") {
janet_fixarity(argc, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
if (janet_checktype(argv[1], JANET_NIL)) {
@ -458,15 +478,44 @@ static Janet cfun_fiber_setenv(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JANET_CORE_FN(cfun_fiber_new,
"(fiber/new func &opt sigmask env)",
"Create a new fiber with function body func. Can optionally "
"take a set of signals `sigmask` to capture from child fibers, "
"and an environment table `env`. The mask is specified as a keyword where each character "
"is used to indicate a signal to block. If the ev module is enabled, and "
"this fiber is used as an argument to `ev/go`, these \"blocked\" signals "
"will result in messages being sent to the supervisor channel. "
"The default sigmask is :y. "
"For example,\n\n"
" (fiber/new myfun :e123)\n\n"
"blocks error signals and user signals 1, 2 and 3. The signals are "
"as follows:\n\n"
"* :a - block all signals\n"
"* :d - block debug signals\n"
"* :e - block error signals\n"
"* :t - block termination signals: error + user[0-4]\n"
"* :u - block user signals\n"
"* :y - block yield signals\n"
"* :w - block await signals (user9)\n"
"* :r - block interrupt signals (user8)\n"
"* :0-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"
"* :i - inherit the environment from the current fiber\n"
"* :p - the environment table's prototype is the current environment table") {
janet_arity(argc, 1, 3);
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) {
janet_assert(fiber != NULL, "bad fiber arity check");
if (argc == 3 && !janet_checktype(argv[2], JANET_NIL)) {
fiber->env = janet_gettable(argv, 2);
}
if (argc >= 2) {
int32_t i;
JanetByteView view = janet_getbytes(argv, 1);
fiber->flags = JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
@ -477,7 +526,7 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
} else {
switch (view.bytes[i]) {
default:
janet_panicf("invalid flag %c, expected a, t, d, e, u, y, i, or p", view.bytes[i]);
janet_panicf("invalid flag %c, expected a, t, d, e, u, y, w, r, i, or p", view.bytes[i]);
break;
case 'a':
fiber->flags |=
@ -507,18 +556,24 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
case 'y':
fiber->flags |= JANET_FIBER_MASK_YIELD;
break;
case 'w':
fiber->flags |= JANET_FIBER_MASK_USER9;
break;
case 'r':
fiber->flags |= JANET_FIBER_MASK_USER8;
break;
case 'i':
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(0);
if (!janet_vm.fiber->env) {
janet_vm.fiber->env = janet_table(0);
}
fiber->env = janet_vm_fiber->env;
fiber->env = janet_vm.fiber->env;
break;
case 'p':
if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(0);
if (!janet_vm.fiber->env) {
janet_vm.fiber->env = janet_table(0);
}
fiber->env = janet_table(0);
fiber->env->proto = janet_vm_fiber->env;
fiber->env->proto = janet_vm.fiber->env;
break;
}
}
@ -527,32 +582,55 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
return janet_wrap_fiber(fiber);
}
static Janet cfun_fiber_status(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_status,
"(fiber/status fib)",
"Get the status of a fiber. The status will be one of:\n\n"
"* :dead - the fiber has finished\n"
"* :error - the fiber has errored out\n"
"* :debug - the fiber is suspended in debug mode\n"
"* :pending - the fiber has been yielded\n"
"* :user(0-7) - the fiber is suspended by a user signal\n"
"* :interrupted - the fiber was interrupted\n"
"* :suspended - the fiber is waiting to be resumed by the scheduler\n"
"* :alive - the fiber is currently running and cannot be resumed\n"
"* :new - the fiber has just been created and not yet run") {
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 Janet cfun_fiber_current(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_current,
"(fiber/current)",
"Returns the currently running fiber.") {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_fiber(janet_vm_fiber);
return janet_wrap_fiber(janet_vm.fiber);
}
static Janet cfun_fiber_root(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_root,
"(fiber/root)",
"Returns the current root fiber. The root fiber is the oldest ancestor "
"that does not have a parent.") {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_fiber(janet_vm_root_fiber);
return janet_wrap_fiber(janet_vm.root_fiber);
}
static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_fiber_maxstack,
"(fiber/maxstack fib)",
"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. ") {
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_CORE_FN(cfun_fiber_setmaxstack,
"(fiber/setmaxstack fib maxstack)",
"Sets the maximum stack size in janet values for a fiber. By default, the "
"maximum stack size is usually 8192.") {
janet_fixarity(argc, 2);
JanetFiber *fiber = janet_getfiber(argv, 0);
int32_t maxs = janet_getinteger(argv, 1);
@ -563,9 +641,7 @@ static Janet cfun_fiber_setmaxstack(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
int janet_fiber_can_resume(JanetFiber *fiber) {
JanetFiberStatus s = janet_fiber_status(fiber);
int isFinished = s == JANET_STATUS_DEAD ||
s == JANET_STATUS_ERROR ||
@ -574,90 +650,39 @@ static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
s == JANET_STATUS_USER2 ||
s == JANET_STATUS_USER3 ||
s == JANET_STATUS_USER4;
return janet_wrap_boolean(!isFinished);
return !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_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/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/current", cfun_fiber_current,
JDOC("(fiber/current)\n\n"
"Returns the currently running fiber.")
},
{
"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}
};
JANET_CORE_FN(cfun_fiber_can_resume,
"(fiber/can-resume? fiber)",
"Check if a fiber is finished and cannot be resumed.") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return janet_wrap_boolean(janet_fiber_can_resume(fiber));
}
JANET_CORE_FN(cfun_fiber_last_value,
"(fiber/last-value fiber)",
"Get the last value returned or signaled from the fiber.") {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return fiber->last_value;
}
/* Module entry point */
void janet_lib_fiber(JanetTable *env) {
janet_core_cfuns(env, NULL, fiber_cfuns);
JanetRegExt fiber_cfuns[] = {
JANET_CORE_REG("fiber/new", cfun_fiber_new),
JANET_CORE_REG("fiber/status", cfun_fiber_status),
JANET_CORE_REG("fiber/root", cfun_fiber_root),
JANET_CORE_REG("fiber/current", cfun_fiber_current),
JANET_CORE_REG("fiber/maxstack", cfun_fiber_maxstack),
JANET_CORE_REG("fiber/setmaxstack", cfun_fiber_setmaxstack),
JANET_CORE_REG("fiber/getenv", cfun_fiber_getenv),
JANET_CORE_REG("fiber/setenv", cfun_fiber_setenv),
JANET_CORE_REG("fiber/can-resume?", cfun_fiber_can_resume),
JANET_CORE_REG("fiber/last-value", cfun_fiber_last_value),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, fiber_cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -46,8 +46,8 @@
#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_MASK 0x3F0000
#define JANET_FIBER_RESUME_SIGNAL 0x400000
#define JANET_FIBER_STATUS_OFFSET 16
#define JANET_FIBER_BREAKPOINT 0x1000000
@ -56,7 +56,12 @@
#define JANET_FIBER_DID_LONGJUMP 0x8000000
#define JANET_FIBER_FLAG_MASK 0xF000000
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
#define JANET_FIBER_EV_FLAG_CANCELED 0x10000
#define JANET_FIBER_EV_FLAG_SUSPENDED 0x20000
#define JANET_FIBER_FLAG_ROOT 0x40000
#define JANET_FIBER_EV_FLAG_IN_FLIGHT 0x1
/* used only on windows, should otherwise be unset */
#define janet_fiber_set_status(f, s) do {\
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\
@ -77,4 +82,8 @@ void janet_fiber_popframe(JanetFiber *fiber);
void janet_env_maybe_detach(JanetFuncEnv *env);
int janet_env_valid(JanetFuncEnv *env);
#ifdef JANET_EV
void janet_fiber_did_resume(JanetFiber *fiber);
#endif
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -28,30 +28,9 @@
#include "gc.h"
#include "util.h"
#include "fiber.h"
#include "vector.h"
#endif
struct JanetScratch {
JanetScratchFinalizer finalize;
long long mem[]; /* for proper alignment */
};
/* GC State */
JANET_THREAD_LOCAL void *janet_vm_blocks;
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 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);
static void janet_mark_funcdef(JanetFuncDef *def);
@ -71,7 +50,7 @@ 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;
janet_vm.next_collection += s;
}
/* Mark a value */
@ -126,6 +105,14 @@ static void janet_mark_buffer(JanetBuffer *buffer) {
}
static void janet_mark_abstract(void *adata) {
#ifdef JANET_EV
/* Check if abstract type is a threaded abstract type. If it is, marking means
* updating the threaded_abstract table. */
if ((janet_abstract_head(adata)->gc.flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_THREADED_ABSTRACT) {
janet_table_put(&janet_vm.threaded_abstracts, janet_wrap_abstract(adata), janet_wrap_true());
return;
}
#endif
if (janet_gc_reachable(janet_abstract_head(adata)))
return;
janet_gc_mark(janet_abstract_head(adata));
@ -136,6 +123,8 @@ static void janet_mark_abstract(void *adata) {
/* Mark a bunch of items in memory */
static void janet_mark_many(const Janet *values, int32_t n) {
if (values == NULL)
return;
const Janet *end = values + n;
while (values < end) {
janet_mark(*values);
@ -143,6 +132,24 @@ static void janet_mark_many(const Janet *values, int32_t n) {
}
}
/* Mark a bunch of key values items in memory */
static void janet_mark_keys(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n;
while (kvs < end) {
janet_mark(kvs->key);
kvs++;
}
}
/* Mark a bunch of key values items in memory */
static void janet_mark_values(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n;
while (kvs < end) {
janet_mark(kvs->value);
kvs++;
}
}
/* Mark a bunch of key values items in memory */
static void janet_mark_kvs(const JanetKV *kvs, int32_t n) {
const JanetKV *end = kvs + n;
@ -157,7 +164,9 @@ static void janet_mark_array(JanetArray *array) {
if (janet_gc_reachable(array))
return;
janet_gc_mark(array);
janet_mark_many(array->data, array->count);
if (janet_gc_type((JanetGCObject *) array) == JANET_MEMORY_ARRAY) {
janet_mark_many(array->data, array->count);
}
}
static void janet_mark_table(JanetTable *table) {
@ -165,7 +174,15 @@ recur: /* Manual tail recursion */
if (janet_gc_reachable(table))
return;
janet_gc_mark(table);
janet_mark_kvs(table->data, table->capacity);
enum JanetMemoryType memtype = janet_gc_type(table);
if (memtype == JANET_MEMORY_TABLE_WEAKK) {
janet_mark_values(table->data, table->capacity);
} else if (memtype == JANET_MEMORY_TABLE_WEAKV) {
janet_mark_keys(table->data, table->capacity);
} else if (memtype == JANET_MEMORY_TABLE) {
janet_mark_kvs(table->data, table->capacity);
}
/* do nothing for JANET_MEMORY_TABLE_WEAKKV */
if (table->proto) {
table = table->proto;
goto recur;
@ -173,10 +190,13 @@ recur: /* Manual tail recursion */
}
static void janet_mark_struct(const JanetKV *st) {
recur:
if (janet_gc_reachable(janet_struct_head(st)))
return;
janet_gc_mark(janet_struct_head(st));
janet_mark_kvs(st, janet_struct_capacity(st));
st = janet_struct_proto(st);
if (st) goto recur;
}
static void janet_mark_tuple(const Janet *tuple) {
@ -217,6 +237,12 @@ static void janet_mark_funcdef(JanetFuncDef *def) {
janet_mark_string(def->source);
if (def->name)
janet_mark_string(def->name);
if (def->symbolmap) {
for (int i = 0; i < def->symbolmap_length; i++) {
janet_mark_string(def->symbolmap[i].symbol);
}
}
}
static void janet_mark_function(JanetFunction *func) {
@ -225,11 +251,14 @@ static void janet_mark_function(JanetFunction *func) {
if (janet_gc_reachable(func))
return;
janet_gc_mark(func);
numenvs = func->def->environments_length;
for (i = 0; i < numenvs; ++i) {
janet_mark_funcenv(func->envs[i]);
if (NULL != func->def) {
/* this should always be true, except if function is only partially constructed */
numenvs = func->def->environments_length;
for (i = 0; i < numenvs; ++i) {
janet_mark_funcenv(func->envs[i]);
}
janet_mark_funcdef(func->def);
}
janet_mark_funcdef(func->def);
}
static void janet_mark_fiber(JanetFiber *fiber) {
@ -240,6 +269,8 @@ recur:
return;
janet_gc_mark(fiber);
janet_mark(fiber->last_value);
/* Mark values on the argument stack */
janet_mark_many(fiber->data + fiber->stackstart,
fiber->stacktop - fiber->stackstart);
@ -261,6 +292,18 @@ recur:
if (fiber->env)
janet_mark_table(fiber->env);
#ifdef JANET_EV
if (fiber->supervisor_channel) {
janet_mark_abstract(fiber->supervisor_channel);
}
if (fiber->ev_stream) {
janet_mark_abstract(fiber->ev_stream);
}
if (fiber->ev_callback) {
fiber->ev_callback(fiber, JANET_ASYNC_EVENT_MARK);
}
#endif
/* Explicit tail recursion */
if (fiber->child) {
fiber = fiber->child;
@ -278,14 +321,22 @@ static void janet_deinit_block(JanetGCObject *mem) {
janet_symbol_deinit(((JanetStringHead *) mem)->data);
break;
case JANET_MEMORY_ARRAY:
free(((JanetArray *) mem)->data);
janet_free(((JanetArray *) mem)->data);
break;
case JANET_MEMORY_TABLE:
free(((JanetTable *) mem)->data);
break;
case JANET_MEMORY_FIBER:
free(((JanetFiber *)mem)->data);
janet_free(((JanetTable *) mem)->data);
break;
case JANET_MEMORY_FIBER: {
JanetFiber *f = (JanetFiber *)mem;
#ifdef JANET_EV
if (f->ev_state && !(f->flags & JANET_FIBER_EV_FLAG_IN_FLIGHT)) {
janet_ev_dec_refcount();
janet_free(f->ev_state);
}
#endif
janet_free(f->data);
}
break;
case JANET_MEMORY_BUFFER:
janet_buffer_deinit((JanetBuffer *) mem);
break;
@ -299,46 +350,171 @@ static void janet_deinit_block(JanetGCObject *mem) {
case JANET_MEMORY_FUNCENV: {
JanetFuncEnv *env = (JanetFuncEnv *)mem;
if (0 == env->offset)
free(env->as.values);
janet_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);
janet_free(def->defs);
janet_free(def->environments);
janet_free(def->constants);
janet_free(def->bytecode);
janet_free(def->sourcemap);
janet_free(def->closure_bitset);
janet_free(def->symbolmap);
}
break;
}
}
/* Check that a value x has been visited in the mark phase */
static int janet_check_liveref(Janet x) {
switch (janet_type(x)) {
default:
return 1;
case JANET_ARRAY:
case JANET_TABLE:
case JANET_FUNCTION:
case JANET_BUFFER:
case JANET_FIBER:
return janet_gc_reachable(janet_unwrap_pointer(x));
case JANET_STRING:
case JANET_SYMBOL:
case JANET_KEYWORD:
return janet_gc_reachable(janet_string_head(janet_unwrap_string(x)));
case JANET_ABSTRACT:
return janet_gc_reachable(janet_abstract_head(janet_unwrap_abstract(x)));
case JANET_TUPLE:
return janet_gc_reachable(janet_tuple_head(janet_unwrap_tuple(x)));
case JANET_STRUCT:
return janet_gc_reachable(janet_struct_head(janet_unwrap_struct(x)));
}
}
/* 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() {
JanetGCObject *previous = NULL;
JanetGCObject *current = janet_vm_blocks;
JanetGCObject *current = janet_vm.weak_blocks;
JanetGCObject *next;
/* Sweep weak heap to drop weak refs */
while (NULL != current) {
next = current->next;
next = current->data.next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
/* Check for dead references */
enum JanetMemoryType type = janet_gc_type(current);
if (type == JANET_MEMORY_ARRAY_WEAK) {
JanetArray *array = (JanetArray *) current;
for (uint32_t i = 0; i < (uint32_t) array->count; i++) {
if (!janet_check_liveref(array->data[i])) {
array->data[i] = janet_wrap_nil();
}
}
} else {
JanetTable *table = (JanetTable *) current;
int check_values = (type == JANET_MEMORY_TABLE_WEAKV) || (type == JANET_MEMORY_TABLE_WEAKKV);
int check_keys = (type == JANET_MEMORY_TABLE_WEAKK) || (type == JANET_MEMORY_TABLE_WEAKKV);
JanetKV *end = table->data + table->capacity;
JanetKV *kvs = table->data;
while (kvs < end) {
int drop = 0;
if (check_keys && !janet_check_liveref(kvs->key)) drop = 1;
if (check_values && !janet_check_liveref(kvs->value)) drop = 1;
if (drop) {
/* Inlined from janet_table_remove without search */
table->count--;
table->deleted++;
kvs->key = janet_wrap_nil();
kvs->value = janet_wrap_false();
}
kvs++;
}
}
}
current = next;
}
/* Sweep weak heap to free blocks */
previous = NULL;
current = janet_vm.weak_blocks;
while (NULL != current) {
next = current->data.next;
if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) {
previous = current;
current->flags &= ~JANET_MEM_REACHABLE;
} else {
janet_vm_block_count--;
janet_vm.block_count--;
janet_deinit_block(current);
if (NULL != previous) {
previous->next = next;
previous->data.next = next;
} else {
janet_vm_blocks = next;
janet_vm.weak_blocks = next;
}
free(current);
janet_free(current);
}
current = next;
}
/* Sweep main heap to free blocks */
previous = NULL;
current = janet_vm.blocks;
while (NULL != current) {
next = current->data.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->data.next = next;
} else {
janet_vm.blocks = next;
}
janet_free(current);
}
current = next;
}
#ifdef JANET_EV
/* Sweep threaded abstract types for references to decrement */
JanetKV *items = janet_vm.threaded_abstracts.data;
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
/* If item was not visited during the mark phase, then this
* abstract type isn't present in the heap and needs its refcount
* decremented, and shouuld be removed from table. If the refcount is
* then 0, the item will be collected. This ensures that only one interpreter
* will clean up the threaded abstract. */
/* If not visited... */
if (!janet_truthy(items[i].value)) {
void *abst = janet_unwrap_abstract(items[i].key);
if (0 == janet_abstract_decref(abst)) {
/* Run finalizer */
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
}
/* Free memory */
janet_free(janet_abstract_head(abst));
}
/* Mark as tombstone in place */
items[i].key = janet_wrap_nil();
items[i].value = janet_wrap_false();
janet_vm.threaded_abstracts.deleted++;
janet_vm.threaded_abstracts.count--;
}
/* Reset for next sweep */
items[i].value = janet_wrap_false();
}
}
#endif
}
/* Allocate some memory that is tracked for garbage collection */
@ -346,8 +522,8 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
JanetGCObject *mem;
/* Make sure everything is inited */
janet_assert(NULL != janet_vm_cache, "please initialize janet before use");
mem = malloc(size);
janet_assert(NULL != janet_vm.cache, "please initialize janet before use");
mem = janet_malloc(size);
/* Check for bad malloc */
if (NULL == mem) {
@ -358,10 +534,17 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
mem->flags = type;
/* Prepend block to heap list */
janet_vm_next_collection += size;
mem->next = janet_vm_blocks;
janet_vm_blocks = mem;
janet_vm_block_count++;
janet_vm.next_collection += size;
if (type < JANET_MEMORY_TABLE_WEAKK) {
/* normal heap */
mem->data.next = janet_vm.blocks;
janet_vm.blocks = mem;
} else {
/* weak heap */
mem->data.next = janet_vm.weak_blocks;
janet_vm.weak_blocks = mem;
}
janet_vm.block_count++;
return (void *)mem;
}
@ -370,15 +553,15 @@ static void free_one_scratch(JanetScratch *s) {
if (NULL != s->finalize) {
s->finalize((char *) s->mem);
}
free(s);
janet_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]);
for (size_t i = 0; i < janet_vm.scratch_len; i++) {
free_one_scratch(janet_vm.scratch_mem[i]);
}
janet_scratch_len = 0;
janet_vm.scratch_len = 0;
}
static JanetScratch *janet_mem2scratch(void *mem) {
@ -389,28 +572,31 @@ static JanetScratch *janet_mem2scratch(void *mem) {
/* Run garbage collection */
void janet_collect(void) {
uint32_t i;
if (janet_vm_gc_suspend) return;
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.
janet_vm.gc_mark_phase = 1;
/* Try to 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);
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();
orig_rootcount = janet_vm.root_count;
#ifdef JANET_EV
janet_ev_mark();
#endif
janet_mark_fiber(janet_vm.root_fiber);
for (i = 0; i < orig_rootcount; i++)
janet_mark(janet_vm_roots[i]);
while (orig_rootcount < janet_vm_root_count) {
Janet x = janet_vm_roots[--janet_vm_root_count];
janet_mark(janet_vm.roots[i]);
while (orig_rootcount < janet_vm.root_count) {
Janet x = janet_vm.roots[--janet_vm.root_count];
janet_mark(x);
}
janet_vm.gc_mark_phase = 0;
janet_sweep();
janet_vm_next_collection = 0;
janet_vm.next_collection = 0;
janet_free_all_scratch();
}
@ -418,17 +604,17 @@ void janet_collect(void) {
* 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) {
size_t newcount = janet_vm_root_count + 1;
if (newcount > janet_vm_root_capacity) {
size_t newcount = janet_vm.root_count + 1;
if (newcount > janet_vm.root_capacity) {
size_t newcap = 2 * newcount;
janet_vm_roots = realloc(janet_vm_roots, sizeof(Janet) * newcap);
if (NULL == janet_vm_roots) {
janet_vm.roots = janet_realloc(janet_vm.roots, sizeof(Janet) * newcap);
if (NULL == janet_vm.roots) {
JANET_OUT_OF_MEMORY;
}
janet_vm_root_capacity = newcap;
janet_vm.root_capacity = newcap;
}
janet_vm_roots[janet_vm_root_count] = root;
janet_vm_root_count = newcount;
janet_vm.roots[janet_vm.root_count] = root;
janet_vm.root_count = newcount;
}
/* Identity equality for GC purposes */
@ -449,11 +635,11 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
/* Remove a root value from the GC. This allows the gc to potentially reclaim
* a value and all its children. */
int janet_gcunroot(Janet root) {
Janet *vtop = janet_vm_roots + janet_vm_root_count;
Janet *vtop = janet_vm.roots + janet_vm.root_count;
/* Search from top to bottom as access is most likely LIFO */
for (Janet *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];
*v = janet_vm.roots[--janet_vm.root_count];
return 1;
}
}
@ -462,12 +648,12 @@ 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 *vtop = janet_vm.roots + janet_vm.root_count;
int ret = 0;
/* Search from top to bottom as access is most likely LIFO */
for (Janet *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];
*v = janet_vm.roots[--janet_vm.root_count];
vtop--;
ret = 1;
}
@ -477,44 +663,61 @@ int janet_gcunrootall(Janet root) {
/* Free all allocated memory */
void janet_clear_memory(void) {
JanetGCObject *current = janet_vm_blocks;
#ifdef JANET_EV
JanetKV *items = janet_vm.threaded_abstracts.data;
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
void *abst = janet_unwrap_abstract(items[i].key);
if (0 == janet_abstract_decref(abst)) {
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
}
janet_free(janet_abstract_head(abst));
}
}
}
#endif
JanetGCObject *current = janet_vm.blocks;
while (NULL != current) {
janet_deinit_block(current);
JanetGCObject *next = current->next;
free(current);
JanetGCObject *next = current->data.next;
janet_free(current);
current = next;
}
janet_vm_blocks = NULL;
janet_vm.blocks = NULL;
janet_free_all_scratch();
free(janet_scratch_mem);
janet_free(janet_vm.scratch_mem);
}
/* Primitives for suspending GC. */
int janet_gclock(void) {
return janet_vm_gc_suspend++;
return janet_vm.gc_suspend++;
}
void janet_gcunlock(int handle) {
janet_vm_gc_suspend = handle;
janet_vm.gc_suspend = handle;
}
/* Scratch memory API */
/* Scratch memory API
* Scratch memory allocations do not need to be free (but optionally can be), and will be automatically cleaned
* up in the next call to janet_collect. */
void *janet_smalloc(size_t size) {
JanetScratch *s = malloc(sizeof(JanetScratch) + size);
JanetScratch *s = janet_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 (janet_vm.scratch_len == janet_vm.scratch_cap) {
size_t newcap = 2 * janet_vm.scratch_cap + 2;
JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_vm.scratch_mem, newcap * sizeof(JanetScratch));
if (NULL == newmem) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_cap = newcap;
janet_scratch_mem = newmem;
janet_vm.scratch_cap = newcap;
janet_vm.scratch_mem = newmem;
}
janet_scratch_mem[janet_scratch_len++] = s;
janet_vm.scratch_mem[janet_vm.scratch_len++] = s;
return (char *)(s->mem);
}
@ -531,14 +734,14 @@ void *janet_scalloc(size_t nmemb, size_t size) {
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 (janet_vm.scratch_len) {
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
if (janet_vm.scratch_mem[i] == s) {
JanetScratch *news = janet_realloc(s, size + sizeof(JanetScratch));
if (NULL == news) {
JANET_OUT_OF_MEMORY;
}
janet_scratch_mem[i] = news;
janet_vm.scratch_mem[i] = news;
return (char *)(news->mem);
}
if (i == 0) break;
@ -555,10 +758,10 @@ void janet_sfinalizer(void *mem, JanetScratchFinalizer 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];
if (janet_vm.scratch_len) {
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
if (janet_vm.scratch_mem[i] == s) {
janet_vm.scratch_mem[i] = janet_vm.scratch_mem[--janet_vm.scratch_len];
free_one_scratch(s);
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -55,10 +55,15 @@ enum JanetMemoryType {
JANET_MEMORY_FUNCTION,
JANET_MEMORY_ABSTRACT,
JANET_MEMORY_FUNCENV,
JANET_MEMORY_FUNCDEF
JANET_MEMORY_FUNCDEF,
JANET_MEMORY_THREADED_ABSTRACT,
JANET_MEMORY_TABLE_WEAKK,
JANET_MEMORY_TABLE_WEAKV,
JANET_MEMORY_TABLE_WEAKKV,
JANET_MEMORY_ARRAY_WEAK
};
/* To allocate collectable memory, one must calk janet_alloc, initialize the memory,
/* To allocate collectable memory, one must call janet_alloc, initialize the memory,
* and then call when janet_enablegc when it is initailize and reachable by the gc (on the JANET stack) */
void *janet_gcalloc(enum JanetMemoryType type, size_t size);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose & contributors
* Copyright (c) 2023 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
@ -39,6 +39,8 @@
static int it_s64_get(void *p, Janet key, Janet *out);
static int it_u64_get(void *p, Janet key, Janet *out);
static Janet janet_int64_next(void *p, Janet key);
static Janet janet_uint64_next(void *p, Janet key);
static int32_t janet_int64_hash(void *p1, size_t size) {
(void) size;
@ -71,13 +73,13 @@ static void *int64_unmarshal(JanetMarshalContext *ctx) {
static void it_s64_tostring(void *p, JanetBuffer *buffer) {
char str[32];
sprintf(str, "%" PRId64, *((int64_t *)p));
snprintf(str, sizeof(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));
snprintf(str, sizeof(str), "%" PRIu64, *((uint64_t *)p));
janet_buffer_push_cstring(buffer, str);
}
@ -92,7 +94,8 @@ const JanetAbstractType janet_s64_type = {
it_s64_tostring,
janet_int64_compare,
janet_int64_hash,
JANET_ATEND_HASH
janet_int64_next,
JANET_ATEND_NEXT
};
const JanetAbstractType janet_u64_type = {
@ -106,7 +109,8 @@ const JanetAbstractType janet_u64_type = {
it_u64_tostring,
janet_uint64_compare,
janet_int64_hash,
JANET_ATEND_HASH
janet_uint64_next,
JANET_ATEND_NEXT
};
int64_t janet_unwrap_s64(Janet x) {
@ -114,10 +118,9 @@ int64_t janet_unwrap_s64(Janet x) {
default:
break;
case JANET_NUMBER : {
double dbl = janet_unwrap_number(x);
if (fabs(dbl) <= MAX_INT_IN_DBL)
return (int64_t)dbl;
break;
double d = janet_unwrap_number(x);
if (!janet_checkint64range(d)) break;
return (int64_t) d;
}
case JANET_STRING: {
int64_t value;
@ -134,7 +137,7 @@ int64_t janet_unwrap_s64(Janet x) {
break;
}
}
janet_panic("bad s64 initializer");
janet_panicf("can not convert %t %q to 64 bit signed integer", x, x);
return 0;
}
@ -143,10 +146,9 @@ uint64_t janet_unwrap_u64(Janet 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;
double d = janet_unwrap_number(x);
if (!janet_checkuint64range(d)) break;
return (uint64_t) d;
}
case JANET_STRING: {
uint64_t value;
@ -163,7 +165,7 @@ uint64_t janet_unwrap_u64(Janet x) {
break;
}
}
janet_panic("bad u64 initializer");
janet_panicf("can not convert %t %q to a 64 bit unsigned integer", x, x);
return 0;
}
@ -187,33 +189,122 @@ Janet janet_wrap_u64(uint64_t x) {
return janet_wrap_abstract(box);
}
static Janet cfun_it_s64_new(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_it_s64_new,
"(int/s64 value)",
"Create a boxed signed 64 bit integer from a string value.") {
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_CORE_FN(cfun_it_u64_new,
"(int/u64 value)",
"Create a boxed unsigned 64 bit integer from a string value.") {
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.
//
JANET_CORE_FN(cfun_to_number,
"(int/to-number value)",
"Convert an int/u64 or int/s64 to a number. Fails if the number is out of range for an int32.") {
janet_fixarity(argc, 1);
if (janet_type(argv[0]) == JANET_ABSTRACT) {
void *abst = janet_unwrap_abstract(argv[0]);
if (janet_abstract_type(abst) == &janet_s64_type) {
int64_t value = *((int64_t *)abst);
if (value > JANET_INTMAX_INT64) {
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
}
if (value < -JANET_INTMAX_INT64) {
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
}
return janet_wrap_number((double)value);
}
if (janet_abstract_type(abst) == &janet_u64_type) {
uint64_t value = *((uint64_t *)abst);
if (value > JANET_INTMAX_INT64) {
janet_panicf("cannot convert %q to a number, must be in the range [%q, %q]", argv[0], janet_wrap_number(JANET_INTMIN_DOUBLE), janet_wrap_number(JANET_INTMAX_DOUBLE));
}
return janet_wrap_number((double)value);
}
}
janet_panicf("expected int/u64 or int/s64, got %q", argv[0]);
}
JANET_CORE_FN(cfun_to_bytes,
"(int/to-bytes value &opt endianness buffer)",
"Write the bytes of an `int/s64` or `int/u64` into a buffer.\n"
"The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n"
"Returns the modified buffer.\n"
"The `endianness` parameter indicates the byte order:\n"
"- `nil` (unset): system byte order\n"
"- `:le`: little-endian, least significant byte first\n"
"- `:be`: big-endian, most significant byte first\n") {
janet_arity(argc, 1, 3);
if (janet_is_int(argv[0]) == JANET_INT_NONE) {
janet_panicf("int/to-bytes: expected an int/s64 or int/u64, got %q", argv[0]);
}
int reverse = 0;
if (argc > 1 && !janet_checktype(argv[1], JANET_NIL)) {
JanetKeyword endianness_kw = janet_getkeyword(argv, 1);
if (!janet_cstrcmp(endianness_kw, "le")) {
#if JANET_BIG_ENDIAN
reverse = 1;
#endif
} else if (!janet_cstrcmp(endianness_kw, "be")) {
#if JANET_LITTLE_ENDIAN
reverse = 1;
#endif
} else {
janet_panicf("int/to-bytes: expected endianness :le, :be or nil, got %v", argv[1]);
}
}
JanetBuffer *buffer = NULL;
if (argc > 2 && !janet_checktype(argv[2], JANET_NIL)) {
if (!janet_checktype(argv[2], JANET_BUFFER)) {
janet_panicf("int/to-bytes: expected buffer or nil, got %q", argv[2]);
}
buffer = janet_unwrap_buffer(argv[2]);
janet_buffer_extra(buffer, 8);
} else {
buffer = janet_buffer(8);
}
uint8_t *bytes = janet_unwrap_abstract(argv[0]);
if (reverse) {
for (int i = 0; i < 8; ++i) {
buffer->data[buffer->count + 7 - i] = bytes[i];
}
} else {
memcpy(buffer->data + buffer->count, bytes, 8);
}
buffer->count += 8;
return janet_wrap_buffer(buffer);
}
/*
* Code to support polymorphic comparison.
* int/u64 and int/s64 support a "compare" method that allows
* 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))) {
return 0;
} else if ((y > JANET_INTMIN_DOUBLE) && (y < JANET_INTMAX_DOUBLE)) {
double dx = (double) x;
return compare_double_double(dx, y);
} else if (y > ((double) INT64_MAX)) {
@ -228,10 +319,10 @@ static int compare_int64_double(int64_t x, double y) {
static int compare_uint64_double(uint64_t x, double y) {
if (isnan(y)) {
return 0; // clojure and python do this
return 0;
} else if (y < 0) {
return 1;
} else if ((y >= 0) && (y < ((double) MAX_INT_IN_DBL))) {
} else if ((y >= 0) && (y < JANET_INTMAX_DOUBLE)) {
double dx = (double) x;
return compare_double_double(dx, y);
} else if (y > ((double) UINT64_MAX)) {
@ -242,11 +333,11 @@ static int compare_uint64_double(uint64_t x, double y) {
}
}
static Janet cfun_it_s64_compare(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
if (janet_is_int(argv[0]) != JANET_INT_S64)
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:
@ -261,7 +352,6 @@ static Janet cfun_it_s64_compare(int32_t argc, Janet *argv) {
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);
@ -280,8 +370,9 @@ static Janet cfun_it_s64_compare(int32_t argc, Janet *argv) {
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?
if (janet_is_int(argv[0]) != JANET_INT_U64) {
janet_panic("compare method requires int/u64 as first argument");
}
uint64_t x = janet_unwrap_u64(argv[0]);
switch (janet_type(argv[1])) {
default:
@ -296,7 +387,6 @@ static Janet cfun_it_u64_compare(int32_t argc, Janet *argv) {
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);
@ -313,25 +403,52 @@ static Janet cfun_it_u64_compare(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
/*
* In C, signed arithmetic overflow is undefined behvior
* but unsigned arithmetic overflow is twos complement
*
* Reference:
* https://en.cppreference.com/w/cpp/language/ub
* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
*
* This means OPMETHOD & OPMETHODINVERT must always use
* unsigned arithmetic internally, regardless of the true type.
* This will not affect the end result (property of twos complement).
*/
#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]); \
/* This avoids undefined behavior. See above for why. */ \
*box = (T) ((uint64_t) (*box)) oper ((uint64_t) 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) { \
static Janet cfun_it_##type##_##name##i(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]); \
/* This avoids undefined behavior. See above for why. */ \
*box = (T) ((uint64_t) *box) oper ((uint64_t) janet_unwrap_##type(argv[0])); \
return janet_wrap_abstract(box); \
} \
#define UNARYMETHOD(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
janet_fixarity(argc, 1); \
T *box = janet_abstract(&janet_##type##_type, sizeof(T)); \
*box = oper(janet_unwrap_##type(argv[0])); \
return janet_wrap_abstract(box); \
} \
#define DIVZERO(name) DIVZERO_##name
#define DIVZERO_div janet_panic("division by zero")
#define DIVZERO_rem janet_panic("division by zero")
#define DIVZERO_mod 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); \
@ -339,19 +456,19 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
*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 == 0) DIVZERO(name); \
*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) { \
static Janet cfun_it_##type##_##name##i(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 == 0) DIVZERO(name); \
*box oper##= value; \
return janet_wrap_abstract(box); \
} \
@ -363,7 +480,7 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
*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 == 0) DIVZERO(name); \
if ((value == -1) && (*box == INT64_MIN)) janet_panic("INT64_MIN divided by -1"); \
*box oper##= value; \
} \
@ -371,29 +488,49 @@ static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
} \
#define DIVMETHODINVERT_SIGNED(T, type, name, oper) \
static Janet cfun_it_##type##_##name(int32_t argc, Janet *argv) { \
static Janet cfun_it_##type##_##name##i(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 == 0) DIVZERO(name); \
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);
static Janet cfun_it_s64_divf(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
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;
int64_t op1 = janet_unwrap_s64(argv[0]);
int64_t op2 = janet_unwrap_s64(argv[1]);
if (op2 == 0) janet_panic("division by zero");
int64_t x = op1 / op2;
*box = x - (((op1 ^ op2) < 0) && (x * op2 != op1));
return janet_wrap_abstract(box);
}
static Janet cfun_it_s64_divfi(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
int64_t *box = janet_abstract(&janet_s64_type, sizeof(int64_t));
int64_t op2 = janet_unwrap_s64(argv[0]);
int64_t op1 = janet_unwrap_s64(argv[1]);
if (op2 == 0) janet_panic("division by zero");
int64_t x = op1 / op2;
*box = x - (((op1 ^ op2) < 0) && (x * op2 != op1));
return janet_wrap_abstract(box);
}
static Janet cfun_it_s64_mod(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]);
if (op2 == 0) {
*box = op1;
} else {
int64_t x = op1 % op2;
*box = (((op1 ^ op2) < 0) && (x != 0)) ? x + op2 : x;
}
return janet_wrap_abstract(box);
}
@ -401,40 +538,45 @@ static Janet cfun_it_s64_mod(int32_t argc, Janet *argv) {
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;
int64_t op2 = janet_unwrap_s64(argv[0]);
int64_t op1 = janet_unwrap_s64(argv[1]);
if (op2 == 0) {
*box = op1;
} else {
int64_t x = op1 % op2;
*box = (((op1 ^ op2) < 0) && (x != 0)) ? x + op2 : x;
}
*box = x;
return janet_wrap_abstract(box);
}
OPMETHOD(int64_t, s64, add, +)
OPMETHOD(int64_t, s64, sub, -)
OPMETHODINVERT(int64_t, s64, subi, -)
OPMETHODINVERT(int64_t, s64, sub, -)
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, %)
DIVMETHODINVERT_SIGNED(int64_t, s64, div, /)
DIVMETHODINVERT_SIGNED(int64_t, s64, rem, %)
OPMETHOD(int64_t, s64, and, &)
OPMETHOD(int64_t, s64, or, |)
OPMETHOD(int64_t, s64, xor, ^)
UNARYMETHOD(int64_t, s64, not, ~)
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, -)
OPMETHODINVERT(uint64_t, u64, sub, -)
OPMETHOD(uint64_t, u64, mul, *)
DIVMETHOD(uint64_t, u64, div, /)
DIVMETHOD(uint64_t, u64, rem, %)
DIVMETHOD(uint64_t, u64, mod, %)
DIVMETHODINVERT(uint64_t, u64, divi, /)
DIVMETHODINVERT(uint64_t, u64, modi, %)
DIVMETHODINVERT(uint64_t, u64, div, /)
DIVMETHODINVERT(uint64_t, u64, rem, %)
DIVMETHODINVERT(uint64_t, u64, mod, %)
OPMETHOD(uint64_t, u64, and, &)
OPMETHOD(uint64_t, u64, or, |)
OPMETHOD(uint64_t, u64, xor, ^)
UNARYMETHOD(uint64_t, u64, not, ~)
OPMETHOD(uint64_t, u64, lshift, <<)
OPMETHOD(uint64_t, u64, rshift, >>)
@ -443,7 +585,6 @@ OPMETHOD(uint64_t, u64, rshift, >>)
#undef DIVMETHOD_SIGNED
#undef COMPMETHOD
static JanetMethod it_s64_methods[] = {
{"+", cfun_it_s64_add},
{"r+", cfun_it_s64_add},
@ -453,6 +594,8 @@ static JanetMethod it_s64_methods[] = {
{"r*", cfun_it_s64_mul},
{"/", cfun_it_s64_div},
{"r/", cfun_it_s64_divi},
{"div", cfun_it_s64_divf},
{"rdiv", cfun_it_s64_divfi},
{"mod", cfun_it_s64_mod},
{"rmod", cfun_it_s64_modi},
{"%", cfun_it_s64_rem},
@ -463,10 +606,10 @@ static JanetMethod it_s64_methods[] = {
{"r|", cfun_it_s64_or},
{"^", cfun_it_s64_xor},
{"r^", cfun_it_s64_xor},
{"~", cfun_it_s64_not},
{"<<", cfun_it_s64_lshift},
{">>", cfun_it_s64_rshift},
{"compare", cfun_it_s64_compare},
{NULL, NULL}
};
@ -479,23 +622,35 @@ static JanetMethod it_u64_methods[] = {
{"r*", cfun_it_u64_mul},
{"/", cfun_it_u64_div},
{"r/", cfun_it_u64_divi},
{"div", cfun_it_u64_div},
{"rdiv", 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_rem},
{"r%", cfun_it_u64_remi},
{"&", 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_not},
{"<<", cfun_it_u64_lshift},
{">>", cfun_it_u64_rshift},
{"compare", cfun_it_u64_compare},
{NULL, NULL}
};
static Janet janet_int64_next(void *p, Janet key) {
(void) p;
return janet_nextmethod(it_s64_methods, key);
}
static Janet janet_uint64_next(void *p, Janet key) {
(void) p;
return janet_nextmethod(it_u64_methods, key);
}
static int it_s64_get(void *p, Janet key, Janet *out) {
(void) p;
if (!janet_checktype(key, JANET_KEYWORD))
@ -510,23 +665,16 @@ static int it_u64_get(void *p, Janet key, Janet *out) {
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);
JanetRegExt it_cfuns[] = {
JANET_CORE_REG("int/s64", cfun_it_s64_new),
JANET_CORE_REG("int/u64", cfun_it_u64_new),
JANET_CORE_REG("int/to-number", cfun_to_number),
JANET_CORE_REG("int/to-bytes", cfun_to_bytes),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, it_cfuns);
janet_register_abstract_type(&janet_s64_type);
janet_register_abstract_type(&janet_u64_type);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -39,6 +39,12 @@ static int cfun_io_gc(void *p, size_t len);
static int io_file_get(void *p, Janet key, Janet *out);
static void io_file_marshal(void *p, JanetMarshalContext *ctx);
static void *io_file_unmarshal(JanetMarshalContext *ctx);
static Janet io_file_next(void *p, Janet key);
#ifdef JANET_WINDOWS
#define ftell _ftelli64
#define fseek _fseeki64
#endif
const JanetAbstractType janet_file_type = {
"core/file",
@ -48,7 +54,11 @@ const JanetAbstractType janet_file_type = {
NULL,
io_file_marshal,
io_file_unmarshal,
JANET_ATEND_UNMARSHAL
NULL, /* tostring */
NULL, /* compare */
NULL, /* hash */
io_file_next,
JANET_ATEND_NEXT
};
/* Check arguments to fopen */
@ -64,12 +74,15 @@ static int32_t checkflags(const uint8_t *str) {
break;
case 'w':
flags |= JANET_FILE_WRITE;
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
break;
case 'a':
flags |= JANET_FILE_APPEND;
janet_sandbox_assert(JANET_SANDBOX_FS);
break;
case 'r':
flags |= JANET_FILE_READ;
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
break;
}
for (i = 1; i < len; i++) {
@ -79,6 +92,7 @@ static int32_t checkflags(const uint8_t *str) {
break;
case '+':
if (flags & JANET_FILE_UPDATE) return -1;
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
flags |= JANET_FILE_UPDATE;
break;
case 'b':
@ -107,49 +121,36 @@ static void *makef(FILE *f, int32_t flags) {
return iof;
}
/* Open a process */
#ifndef JANET_NO_PROCESSES
static Janet cfun_io_popen(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
const uint8_t *fname = janet_getstring(argv, 0);
const uint8_t *fmode = NULL;
int32_t flags;
if (argc == 2) {
fmode = janet_getkeyword(argv, 1);
flags = JANET_FILE_PIPED | checkflags(fmode);
if (flags & (JANET_FILE_UPDATE | JANET_FILE_BINARY | JANET_FILE_APPEND)) {
janet_panicf("invalid popen file mode :%S, expected :r or :w", fmode);
}
fmode = (const uint8_t *)((fmode[0] == 'r') ? "r" : "w");
} else {
fmode = (const uint8_t *)"r";
flags = JANET_FILE_PIPED | JANET_FILE_READ;
}
#ifdef JANET_WINDOWS
#define popen _popen
#endif
FILE *f = popen((const char *)fname, (const char *)fmode);
if (!f) {
if (flags & JANET_FILE_NONIL)
janet_panicf("failed to popen %s: %s", fname, strerror(errno));
return janet_wrap_nil();
}
return janet_makefile(f, flags);
}
#endif
static Janet cfun_io_temp(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_temp,
"(file/temp)",
"Open an anonymous temporary file that is removed on close. "
"Raises an error on failure.") {
janet_sandbox_assert(JANET_SANDBOX_FS_TEMP);
(void)argv;
janet_fixarity(argc, 0);
// XXX use mkostemp when we can to avoid CLOEXEC race.
FILE *tmp = tmpfile();
if (!tmp)
janet_panicf("unable to create temporary file - %s", strerror(errno));
janet_panicf("unable to create temporary file - %s", janet_strerror(errno));
return janet_makefile(tmp, JANET_FILE_WRITE | JANET_FILE_READ | JANET_FILE_BINARY);
}
static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JANET_CORE_FN(cfun_io_fopen,
"(file/open path &opt mode buffer-size)",
"Open a file. `path` is an absolute or relative path, and "
"`mode` is a set of flags indicating the mode to open the file in. "
"`mode` is a keyword where each character represents a flag. If the file "
"cannot be opened, returns nil, otherwise returns the new file handle. "
"Mode flags:\n\n"
"* r - allow reading from the file\n\n"
"* w - allow writing to the file\n\n"
"* a - append to the file\n\n"
"Following one of the initial flags, 0 or more of the following flags can be appended:\n\n"
"* b - open the file in binary mode (rather than text mode)\n\n"
"* + - append to the file instead of overwriting it\n\n"
"* n - error if the file cannot be opened instead of returning nil\n\n"
"See fopen (<stdio.h>, C99) for further details.") {
janet_arity(argc, 1, 3);
const uint8_t *fname = janet_getstring(argv, 0);
const uint8_t *fmode;
int32_t flags;
@ -158,11 +159,21 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
flags = checkflags(fmode);
} else {
fmode = (const uint8_t *)"r";
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
flags = JANET_FILE_READ;
}
FILE *f = fopen((const char *)fname, (const char *)fmode);
if (f != NULL) {
size_t bufsize = janet_optsize(argv, argc, 2, BUFSIZ);
if (bufsize != BUFSIZ) {
int result = setvbuf(f, NULL, bufsize ? _IOFBF : _IONBF, bufsize);
if (result) {
janet_panic("failed to set buffer size for file");
}
}
}
return f ? janet_makefile(f, flags)
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil())
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, janet_strerror(errno)), janet_wrap_nil())
: janet_wrap_nil();
}
@ -179,7 +190,16 @@ static void read_chunk(JanetFile *iof, JanetBuffer *buffer, int32_t nBytesMax) {
}
/* Read a certain number of bytes into memory */
static Janet cfun_io_fread(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_fread,
"(file/read f what &opt buf)",
"Read a number of bytes from a file `f` into a buffer. A buffer `buf` can "
"be provided as an optional third argument, otherwise a new buffer "
"is created. `what` can either be an integer or a keyword. Returns the "
"buffer with file contents. "
"Values for `what`:\n\n"
"* :all - read the whole file\n\n"
"* :line - read up to and including the next newline character\n\n"
"* n (integer) - read up to n bytes from the file") {
janet_arity(argc, 2, 3);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED) janet_panic("file is closed");
@ -219,7 +239,10 @@ static Janet cfun_io_fread(int32_t argc, Janet *argv) {
}
/* Write bytes to a file */
static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_fwrite,
"(file/write f bytes)",
"Writes to a file. 'bytes' must be string, buffer, or symbol. Returns the "
"file.") {
janet_arity(argc, 1, -1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
@ -241,75 +264,85 @@ static Janet cfun_io_fwrite(int32_t argc, Janet *argv) {
return argv[0];
}
/* Flush the bytes in the file */
static Janet cfun_io_fflush(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
static void io_assert_writeable(JanetFile *iof) {
if (iof->flags & JANET_FILE_CLOSED)
janet_panic("file is closed");
if (!(iof->flags & (JANET_FILE_WRITE | JANET_FILE_APPEND | JANET_FILE_UPDATE)))
janet_panic("file is not writeable");
}
/* Flush the bytes in the file */
JANET_CORE_FN(cfun_io_fflush,
"(file/flush f)",
"Flush any buffered bytes to the file system. In most files, writes are "
"buffered for efficiency reasons. Returns the file handle.") {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
io_assert_writeable(iof);
if (fflush(iof->file))
janet_panic("could not flush file");
return argv[0];
}
#ifdef JANET_WINDOWS
#define pclose _pclose
#define WEXITSTATUS(x) x
#endif
/* For closing files from C API */
int janet_file_close(JanetFile *file) {
int ret = 0;
if (!(file->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
ret = fclose(file->file);
file->flags |= JANET_FILE_CLOSED;
file->file = NULL; /* NULL derefence is easier to debug then other problems */
return ret;
}
return 0;
}
/* Cleanup a file */
static int cfun_io_gc(void *p, size_t len) {
(void) len;
JanetFile *iof = (JanetFile *)p;
if (!(iof->flags & (JANET_FILE_NOT_CLOSEABLE | JANET_FILE_CLOSED))) {
/* We can't panic inside a gc, so just ignore bad statuses here */
if (iof->flags & JANET_FILE_PIPED) {
#ifndef JANET_NO_PROCESSES
pclose(iof->file);
#endif
} else {
fclose(iof->file);
}
}
janet_file_close(iof);
return 0;
}
/* Close a file */
static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_fclose,
"(file/close f)",
"Close a file and release all related resources. When you are "
"done reading a file, close it to prevent a resource leak and let "
"other processes read the file.") {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
return janet_wrap_nil();
if (iof->flags & (JANET_FILE_NOT_CLOSEABLE))
janet_panic("file not closable");
if (iof->flags & JANET_FILE_PIPED) {
#ifndef JANET_NO_PROCESSES
int status = pclose(iof->file);
iof->flags |= JANET_FILE_CLOSED;
if (status == -1) janet_panic("could not close file");
return janet_wrap_integer(WEXITSTATUS(status));
#else
return janet_wrap_nil();
#endif
} else {
if (fclose(iof->file)) {
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
janet_panic("could not close file");
}
iof->flags |= JANET_FILE_CLOSED;
return janet_wrap_nil();
if (fclose(iof->file)) {
iof->flags |= JANET_FILE_NOT_CLOSEABLE;
janet_panic("could not close file");
}
iof->flags |= JANET_FILE_CLOSED;
return janet_wrap_nil();
}
/* Seek a file */
static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_fseek,
"(file/seek f &opt whence n)",
"Jump to a relative location in the file `f`. `whence` must be one of:\n\n"
"* :cur - jump relative to the current file location\n\n"
"* :set - jump relative to the beginning of the file\n\n"
"* :end - jump relative to the end of the file\n\n"
"By default, `whence` is :cur. Optionally a value `n` may be passed "
"for the relative number of bytes to seek in the file. `n` may be a real "
"number to handle large files of more than 4GB. Returns the file handle.") {
janet_arity(argc, 2, 3);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
janet_panic("file is closed");
long int offset = 0;
int64_t offset = 0;
int whence = SEEK_CUR;
if (argc >= 2) {
const uint8_t *whence_sym = janet_getkeyword(argv, 1);
@ -323,18 +356,31 @@ static Janet cfun_io_fseek(int32_t argc, Janet *argv) {
janet_panicf("expected one of :cur, :set, :end, got %v", argv[1]);
}
if (argc == 3) {
offset = (long) janet_getinteger64(argv, 2);
offset = (int64_t) janet_getinteger64(argv, 2);
}
}
if (fseek(iof->file, offset, whence)) janet_panic("error seeking file");
return argv[0];
}
JANET_CORE_FN(cfun_io_ftell,
"(file/tell f)",
"Get the current value of the file position for file `f`.") {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
janet_panic("file is closed");
int64_t pos = ftell(iof->file);
if (pos == -1) janet_panic("error getting position in file");
return janet_wrap_number((double)pos);
}
static JanetMethod io_file_methods[] = {
{"close", cfun_io_fclose},
{"flush", cfun_io_fflush},
{"read", cfun_io_fread},
{"seek", cfun_io_fseek},
{"tell", cfun_io_ftell},
{"write", cfun_io_fwrite},
{NULL, NULL}
};
@ -346,6 +392,11 @@ static int io_file_get(void *p, Janet key, Janet *out) {
return janet_getmethod(janet_unwrap_keyword(key), io_file_methods, out);
}
static Janet io_file_next(void *p, Janet key) {
(void) p;
return janet_nextmethod(io_file_methods, key);
}
static void io_file_marshal(void *p, JanetMarshalContext *ctx) {
JanetFile *iof = (JanetFile *)p;
if (ctx->flags & JANET_MARSHAL_UNSAFE) {
@ -415,6 +466,19 @@ static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
janet_buffer_push_u8(buf, '\n');
return janet_wrap_nil();
}
case JANET_FUNCTION: {
/* Special case function */
JanetFunction *fun = janet_unwrap_function(x);
JanetBuffer *buf = janet_buffer(0);
for (int32_t i = offset; i < argc; ++i) {
janet_to_string_b(buf, argv[i]);
}
if (newline)
janet_buffer_push_u8(buf, '\n');
Janet args[1] = { janet_wrap_buffer(buf) };
janet_call(fun, 1, args);
return janet_wrap_nil();
}
case JANET_NIL:
f = dflt_file;
if (f == NULL) janet_panic("cannot print to nil");
@ -424,6 +488,7 @@ static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
if (janet_abstract_type(abstract) != &janet_file_type)
return janet_wrap_nil();
JanetFile *iofile = abstract;
io_assert_writeable(iofile);
f = iofile->file;
break;
}
@ -454,35 +519,53 @@ static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
return janet_wrap_nil();
}
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
int newline, const char *name, FILE *dflt_file) {
Janet x = janet_dyn(name);
return cfun_io_print_impl_x(argc, argv, newline, dflt_file, 0, x);
}
static Janet cfun_io_print(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_print,
"(print & xs)",
"Print values to the console (standard out). Value are converted "
"to strings if they are not already. After printing all values, a "
"newline character is printed. Use the value of `(dyn :out stdout)` to determine "
"what to push characters to. Expects `(dyn :out stdout)` to be either a core/file or "
"a buffer. Returns nil.") {
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
}
static Janet cfun_io_prin(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_prin,
"(prin & xs)",
"Same as `print`, but does not add trailing newline.") {
return cfun_io_print_impl(argc, argv, 0, "out", stdout);
}
static Janet cfun_io_eprint(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_eprint,
"(eprint & xs)",
"Same as `print`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
return cfun_io_print_impl(argc, argv, 1, "err", stderr);
}
static Janet cfun_io_eprin(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_eprin,
"(eprin & xs)",
"Same as `prin`, but uses `(dyn :err stderr)` instead of `(dyn :out stdout)`.") {
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
}
static Janet cfun_io_xprint(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_xprint,
"(xprint to & xs)",
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
"newline character. The value to print "
"to is the first argument, and is otherwise the same as `print`. Returns nil.") {
janet_arity(argc, 1, -1);
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}
static Janet cfun_io_xprin(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_xprin,
"(xprin to & xs)",
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
"to is the first argument, and is otherwise the same as `prin`. Returns nil.") {
janet_arity(argc, 1, -1);
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
@ -501,6 +584,16 @@ static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
if (newline) janet_buffer_push_u8(buf, '\n');
return janet_wrap_nil();
}
case JANET_FUNCTION: {
/* Special case function */
JanetFunction *fun = janet_unwrap_function(x);
JanetBuffer *buf = janet_buffer(0);
janet_buffer_format(buf, fmt, offset, argc, argv);
if (newline) janet_buffer_push_u8(buf, '\n');
Janet args[1] = { janet_wrap_buffer(buf) };
janet_call(fun, 1, args);
return janet_wrap_nil();
}
case JANET_NIL:
f = dflt_file;
if (f == NULL) janet_panic("cannot print to nil");
@ -510,6 +603,10 @@ static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
if (janet_abstract_type(abstract) != &janet_file_type)
return janet_wrap_nil();
JanetFile *iofile = abstract;
if (iofile->flags & JANET_FILE_CLOSED) {
janet_panic("cannot print to closed file");
}
io_assert_writeable(iofile);
f = iofile->file;
break;
}
@ -525,7 +622,7 @@ static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
/* Clear buffer to make things easier for GC */
buf->count = 0;
buf->capacity = 0;
free(buf->data);
janet_free(buf->data);
buf->data = NULL;
return janet_wrap_nil();
}
@ -538,28 +635,40 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
}
static Janet cfun_io_printf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_printf,
"(printf fmt & xs)",
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :out stdout)` with a trailing newline.") {
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
}
static Janet cfun_io_prinf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_prinf,
"(prinf fmt & xs)",
"Like `printf` but with no trailing newline.") {
return cfun_io_printf_impl(argc, argv, 0, "out", stdout);
}
static Janet cfun_io_eprintf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_eprintf,
"(eprintf fmt & xs)",
"Prints output formatted as if with `(string/format fmt ;xs)` to `(dyn :err stderr)` with a trailing newline.") {
return cfun_io_printf_impl(argc, argv, 1, "err", stderr);
}
static Janet cfun_io_eprinf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_eprinf,
"(eprinf fmt & xs)",
"Like `eprintf` but with no trailing newline.") {
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
}
static Janet cfun_io_xprintf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_xprintf,
"(xprintf to fmt & xs)",
"Like `printf` but prints to an explicit file or value `to`. Returns nil.") {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
}
static Janet cfun_io_xprinf(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_xprinf,
"(xprinf to fmt & xs)",
"Like `prinf` but prints to an explicit file or value `to`. Returns nil.") {
janet_arity(argc, 2, -1);
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
}
@ -582,14 +691,18 @@ static void janet_flusher(const char *name, FILE *dflt_file) {
}
}
static Janet cfun_io_flush(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_flush,
"(flush)",
"Flush `(dyn :out stdout)` if it is a file, otherwise do nothing.") {
janet_fixarity(argc, 0);
(void) argv;
janet_flusher("out", stdout);
return janet_wrap_nil();
}
static Janet cfun_io_eflush(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_io_eflush,
"(eflush)",
"Flush `(dyn :err stderr)` if it is a file, otherwise do nothing.") {
janet_fixarity(argc, 0);
(void) argv;
janet_flusher("err", stderr);
@ -618,12 +731,23 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
if (janet_abstract_type(abstract) != &janet_file_type)
break;
JanetFile *iofile = abstract;
io_assert_writeable(iofile);
f = iofile->file;
}
fwrite(buffer.data, buffer.count, 1, f);
janet_buffer_deinit(&buffer);
break;
}
case JANET_FUNCTION: {
JanetFunction *fun = janet_unwrap_function(x);
int32_t len = 0;
while (format[len]) len++;
JanetBuffer *buf = janet_buffer(len);
janet_formatbv(buf, format, args);
Janet args[1] = { janet_wrap_buffer(buf) };
janet_call(fun, 1, args);
break;
}
case JANET_BUFFER:
janet_formatbv(janet_unwrap_buffer(x), format, args);
break;
@ -632,178 +756,23 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
return;
}
static const JanetReg io_cfuns[] = {
{
"print", cfun_io_print,
JDOC("(print & xs)\n\n"
"Print values to the console (standard out). Value are converted "
"to strings if they are not already. After printing all values, a "
"newline character is printed. Use the value of (dyn :out stdout) to determine "
"what to push characters to. Expects (dyn :out stdout) to be either a core/file or "
"a buffer. Returns nil.")
},
{
"prin", cfun_io_prin,
JDOC("(prin & xs)\n\n"
"Same as print, but does not add trailing newline.")
},
{
"printf", cfun_io_printf,
JDOC("(printf fmt & xs)\n\n"
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :out stdout) with a trailing newline.")
},
{
"prinf", cfun_io_prinf,
JDOC("(prinf fmt & xs)\n\n"
"Like printf but with no trailing newline.")
},
{
"eprin", cfun_io_eprin,
JDOC("(eprin & xs)\n\n"
"Same as prin, but uses (dyn :err stderr) instead of (dyn :out stdout).")
},
{
"eprint", cfun_io_eprint,
JDOC("(eprint & xs)\n\n"
"Same as print, but uses (dyn :err stderr) instead of (dyn :out stdout).")
},
{
"eprintf", cfun_io_eprintf,
JDOC("(eprintf fmt & xs)\n\n"
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :err stderr) with a trailing newline.")
},
{
"eprinf", cfun_io_eprinf,
JDOC("(eprinf fmt & xs)\n\n"
"Like eprintf but with no trailing newline.")
},
{
"xprint", cfun_io_xprint,
JDOC("(xprint to & xs)\n\n"
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
"newline character. The value to print "
"to is the first argument, and is otherwise the same as print. Returns nil.")
},
{
"xprin", cfun_io_xprin,
JDOC("(xprin to & xs)\n\n"
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
"to is the first argument, and is otherwise the same as prin. Returns nil.")
},
{
"xprintf", cfun_io_xprintf,
JDOC("(xprint to fmt & xs)\n\n"
"Like printf but prints to an explicit file or value to. Returns nil.")
},
{
"xprinf", cfun_io_xprinf,
JDOC("(xprin to fmt & xs)\n\n"
"Like prinf but prints to an explicit file or value to. Returns nil.")
},
{
"flush", cfun_io_flush,
JDOC("(flush)\n\n"
"Flush (dyn :out stdout) if it is a file, otherwise do nothing.")
},
{
"eflush", cfun_io_eflush,
JDOC("(eflush)\n\n"
"Flush (dyn :err stderr) if it is a file, otherwise do nothing.")
},
{
"file/temp", cfun_io_temp,
JDOC("(file/temp)\n\n"
"Open an anonymous temporary file that is removed on close."
"Raises an error on failure.")
},
{
"file/open", cfun_io_fopen,
JDOC("(file/open path &opt mode)\n\n"
"Open a file. path is an absolute or relative path, and "
"mode is a set of flags indicating the mode to open the file in. "
"mode is a keyword where each character represents a flag. If the file "
"cannot be opened, returns nil, otherwise returns the new file handle. "
"Mode flags:\n\n"
"\tr - allow reading from the file\n"
"\tw - allow writing to the file\n"
"\ta - append to the file\n"
"\tb - open the file in binary mode (rather than text mode)\n"
"\t+ - append to the file instead of overwriting it\n"
"\tn - error if the file cannot be opened instead of returning nil")
},
{
"file/close", cfun_io_fclose,
JDOC("(file/close f)\n\n"
"Close a file and release all related resources. When you are "
"done reading a file, close it to prevent a resource leak and let "
"other processes read the file. If the file is the result of a file/popen "
"call, close waits for and returns the process exit status.")
},
{
"file/read", cfun_io_fread,
JDOC("(file/read f what &opt buf)\n\n"
"Read a number of bytes from a file into a buffer. A buffer can "
"be provided as an optional fourth argument, otherwise a new buffer "
"is created. 'what' can either be an integer or a keyword. Returns the "
"buffer with file contents. "
"Values for 'what':\n\n"
"\t:all - read the whole file\n"
"\t:line - read up to and including the next newline character\n"
"\tn (integer) - read up to n bytes from the file")
},
{
"file/write", cfun_io_fwrite,
JDOC("(file/write f bytes)\n\n"
"Writes to a file. 'bytes' must be string, buffer, or symbol. Returns the "
"file.")
},
{
"file/flush", cfun_io_fflush,
JDOC("(file/flush f)\n\n"
"Flush any buffered bytes to the file system. In most files, writes are "
"buffered for efficiency reasons. Returns the file handle.")
},
{
"file/seek", cfun_io_fseek,
JDOC("(file/seek f &opt whence n)\n\n"
"Jump to a relative location in the file. 'whence' must be one of\n\n"
"\t:cur - jump relative to the current file location\n"
"\t:set - jump relative to the beginning of the file\n"
"\t:end - jump relative to the end of the file\n\n"
"By default, 'whence' is :cur. Optionally a value n may be passed "
"for the relative number of bytes to seek in the file. n may be a real "
"number to handle large files of more the 4GB. Returns the file handle.")
},
#ifndef JANET_NO_PROCESSES
{
"file/popen", cfun_io_popen,
JDOC("(file/popen path &opt mode)\n\n"
"Open a file that is backed by a process. The file must be opened in either "
"the :r (read) or the :w (write) mode. In :r mode, the stdout of the "
"process can be read from the file. In :w mode, the stdin of the process "
"can be written to. Returns the new file.")
},
#endif
{NULL, NULL, NULL}
};
/* C API */
JanetFile *janet_getjfile(const Janet *argv, int32_t n) {
return janet_getabstract(argv, n, &janet_file_type);
}
FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags) {
JanetFile *iof = janet_getabstract(argv, n, &janet_file_type);
if (NULL != flags) *flags = iof->flags;
return iof->file;
}
JanetFile *janet_makejfile(FILE *f, int flags) {
JanetFile *janet_makejfile(FILE *f, int32_t flags) {
return makef(f, flags);
}
Janet janet_makefile(FILE *f, int flags) {
Janet janet_makefile(FILE *f, int32_t flags) {
return janet_wrap_abstract(makef(f, flags));
}
@ -811,7 +780,7 @@ JanetAbstract janet_checkfile(Janet j) {
return janet_checkabstract(j, &janet_file_type);
}
FILE *janet_unwrapfile(Janet j, int *flags) {
FILE *janet_unwrapfile(Janet j, int32_t *flags) {
JanetFile *iof = janet_unwrap_abstract(j);
if (NULL != flags) *flags = iof->flags;
return iof->file;
@ -819,20 +788,45 @@ FILE *janet_unwrapfile(Janet j, int *flags) {
/* Module entry point */
void janet_lib_io(JanetTable *env) {
janet_core_cfuns(env, NULL, io_cfuns);
JanetRegExt io_cfuns[] = {
JANET_CORE_REG("print", cfun_io_print),
JANET_CORE_REG("prin", cfun_io_prin),
JANET_CORE_REG("printf", cfun_io_printf),
JANET_CORE_REG("prinf", cfun_io_prinf),
JANET_CORE_REG("eprin", cfun_io_eprin),
JANET_CORE_REG("eprint", cfun_io_eprint),
JANET_CORE_REG("eprintf", cfun_io_eprintf),
JANET_CORE_REG("eprinf", cfun_io_eprinf),
JANET_CORE_REG("xprint", cfun_io_xprint),
JANET_CORE_REG("xprin", cfun_io_xprin),
JANET_CORE_REG("xprintf", cfun_io_xprintf),
JANET_CORE_REG("xprinf", cfun_io_xprinf),
JANET_CORE_REG("flush", cfun_io_flush),
JANET_CORE_REG("eflush", cfun_io_eflush),
JANET_CORE_REG("file/temp", cfun_io_temp),
JANET_CORE_REG("file/open", cfun_io_fopen),
JANET_CORE_REG("file/close", cfun_io_fclose),
JANET_CORE_REG("file/read", cfun_io_fread),
JANET_CORE_REG("file/write", cfun_io_fwrite),
JANET_CORE_REG("file/flush", cfun_io_fflush),
JANET_CORE_REG("file/seek", cfun_io_fseek),
JANET_CORE_REG("file/tell", cfun_io_ftell),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, io_cfuns);
janet_register_abstract_type(&janet_file_type);
int default_flags = JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE;
/* stdout */
janet_core_def(env, "stdout",
JANET_CORE_DEF(env, "stdout",
janet_makefile(stdout, JANET_FILE_APPEND | default_flags),
JDOC("The standard output file."));
"The standard output file.");
/* stderr */
janet_core_def(env, "stderr",
JANET_CORE_DEF(env, "stderr",
janet_makefile(stderr, JANET_FILE_APPEND | default_flags),
JDOC("The standard error file."));
"The standard error file.");
/* stdin */
janet_core_def(env, "stdin",
JANET_CORE_DEF(env, "stdin",
janet_makefile(stdin, JANET_FILE_READ | default_flags),
JDOC("The standard input file."));
"The standard input file.");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -37,6 +37,7 @@ typedef struct {
JanetFuncEnv **seen_envs;
JanetFuncDef **seen_defs;
int32_t nextid;
int maybe_cycles;
} MarshalState;
/* Lead bytes in marshaling protocol */
@ -63,7 +64,12 @@ enum {
LB_FUNCENV_REF, /* 219 */
LB_FUNCDEF_REF, /* 220 */
LB_UNSAFE_CFUNCTION, /* 221 */
LB_UNSAFE_POINTER /* 222 */
LB_UNSAFE_POINTER, /* 222 */
LB_STRUCT_PROTO, /* 223 */
#ifdef JANET_EV
LB_THREADED_ABSTRACT, /* 224 */
LB_POINTER_BUFFER, /* 224 */
#endif
} LeadBytes;
/* Helper to look inside an entry in an environment */
@ -148,6 +154,10 @@ static void pushbytes(MarshalState *st, const uint8_t *bytes, int32_t len) {
janet_buffer_push_bytes(st->buf, bytes, len);
}
static void pushpointer(MarshalState *st, const void *ptr) {
janet_buffer_push_bytes(st->buf, (const uint8_t *) &ptr, sizeof(ptr));
}
/* Marshal a size_t onto the buffer */
static void push64(MarshalState *st, uint64_t x) {
if (x <= 0xF0) {
@ -175,6 +185,19 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags);
/* Prevent stack overflows */
#define MARSH_STACKCHECK if ((flags & 0xFFFF) > JANET_RECURSION_GUARD) janet_panic("stack overflow")
/* Quick check if a fiber cannot be marshalled. This is will
* have no false positives, but may have false negatives. */
static int fiber_cannot_be_marshalled(JanetFiber *fiber) {
if (janet_fiber_status(fiber) == JANET_STATUS_ALIVE) return 1;
int32_t i = fiber->frame;
while (i > 0) {
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
if (!frame->func) return 1; /* has cfunction on stack */
i = frame->prevframe;
}
return 0;
}
/* Marshal a function env */
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
MARSH_STACKCHECK;
@ -187,7 +210,9 @@ static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
}
janet_env_valid(env);
janet_v_push(st->seen_envs, env);
if (env->offset > 0 && (JANET_STATUS_ALIVE == janet_fiber_status(env->as.fiber))) {
/* Special case for early detachment */
if (env->offset > 0 && fiber_cannot_be_marshalled(env->as.fiber)) {
pushint(st, 0);
pushint(st, env->length);
Janet *values = env->as.fiber->data + env->offset;
@ -236,6 +261,7 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
}
/* Add to lookup */
janet_v_push(st->seen_defs, def);
pushint(st, def->flags);
pushint(st, def->slotcount);
pushint(st, def->arity);
@ -247,6 +273,8 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
pushint(st, def->environments_length);
if (def->flags & JANET_FUNCDEF_FLAG_HASDEFS)
pushint(st, def->defs_length);
if (def->flags & JANET_FUNCDEF_FLAG_HASSYMBOLMAP)
pushint(st, def->symbolmap_length);
if (def->flags & JANET_FUNCDEF_FLAG_HASNAME)
marshal_one(st, janet_wrap_string(def->name), flags);
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCE)
@ -254,7 +282,15 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
/* marshal constants */
for (int32_t i = 0; i < def->constants_length; i++)
marshal_one(st, def->constants[i], flags);
marshal_one(st, def->constants[i], flags + 1);
/* Marshal symbol map, if needed */
for (int32_t i = 0; i < def->symbolmap_length; i++) {
pushint(st, (int32_t) def->symbolmap[i].birth_pc);
pushint(st, (int32_t) def->symbolmap[i].death_pc);
pushint(st, (int32_t) def->symbolmap[i].slot_index);
marshal_one(st, janet_wrap_symbol(def->symbolmap[i].symbol), flags + 1);
}
/* marshal the bytecode */
janet_marshal_u32s(st, def->bytecode, def->bytecode_length);
@ -265,7 +301,7 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
/* marshal the sub funcdefs if needed */
for (int32_t i = 0; i < def->defs_length; i++)
marshal_one_def(st, def->defs[i], flags);
marshal_one_def(st, def->defs[i], flags + 1);
/* marshal source maps if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
@ -285,8 +321,8 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
}
#define JANET_FIBER_FLAG_HASCHILD (1 << 29)
#define JANET_FIBER_FLAG_HASENV (1 << 28)
#define JANET_STACKFRAME_HASENV (1 << 30)
#define JANET_FIBER_FLAG_HASENV (1 << 30)
#define JANET_STACKFRAME_HASENV (INT32_MIN)
/* Marshal a fiber */
static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
@ -307,7 +343,7 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
while (i > 0) {
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
if (frame->env) frame->flags |= JANET_STACKFRAME_HASENV;
if (!frame->func) janet_panic("cannot marshal fiber with c stackframe");
if (!frame->func) janet_panicf("cannot marshal fiber with c stackframe (%v)", janet_wrap_cfunction((JanetCFunction) frame->pc));
pushint(st, frame->flags);
pushint(st, frame->prevframe);
int32_t pcdiff = (int32_t)(frame->pc - frame->func->def->bytecode);
@ -325,6 +361,7 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
}
if (fiber->child)
marshal_one(st, janet_wrap_fiber(fiber->child), flags + 1);
marshal_one(st, fiber->last_value, flags + 1);
}
void janet_marshal_size(JanetMarshalContext *ctx, size_t value) {
@ -341,6 +378,15 @@ void janet_marshal_int(JanetMarshalContext *ctx, int32_t value) {
pushint(st, value);
}
/* Only use in unsafe - don't marshal pointers otherwise */
void janet_marshal_ptr(JanetMarshalContext *ctx, const void *ptr) {
if (!(ctx->flags & JANET_MARSHAL_UNSAFE)) {
janet_panic("can only marshal pointers in unsafe mode");
}
MarshalState *st = (MarshalState *)(ctx->m_state);
pushpointer(st, ptr);
}
void janet_marshal_byte(JanetMarshalContext *ctx, uint8_t value) {
MarshalState *st = (MarshalState *)(ctx->m_state);
pushbyte(st, value);
@ -357,26 +403,52 @@ void janet_marshal_janet(JanetMarshalContext *ctx, Janet x) {
marshal_one(st, x, ctx->flags + 1);
}
#ifdef JANET_MARSHAL_DEBUG
#define MARK_SEEN() \
do { if (st->maybe_cycles) { \
Janet _check = janet_table_get(&st->seen, x); \
if (!janet_checktype(_check, JANET_NIL)) janet_eprintf("double MARK_SEEN on %v\n", x); \
janet_eprintf("made reference %d (%t) to %v\n", st->nextid, x, x); \
janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++)); \
} } while (0)
#else
#define MARK_SEEN() \
do { if (st->maybe_cycles) { \
janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++)); \
} } while (0)
#endif
void janet_marshal_abstract(JanetMarshalContext *ctx, void *abstract) {
MarshalState *st = (MarshalState *)(ctx->m_state);
janet_table_put(&st->seen,
janet_wrap_abstract(abstract),
janet_wrap_integer(st->nextid++));
Janet x = janet_wrap_abstract(abstract);
MARK_SEEN();
}
#define MARK_SEEN() \
janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++))
static void marshal_one_abstract(MarshalState *st, Janet x, int flags) {
void *abstract = janet_unwrap_abstract(x);
#ifdef JANET_EV
/* Threaded abstract types get passed through as pointers in the unsafe mode */
if ((flags & JANET_MARSHAL_UNSAFE) &&
(JANET_MEMORY_THREADED_ABSTRACT == (janet_abstract_head(abstract)->gc.flags & JANET_MEM_TYPEBITS))) {
/* Increment refcount before sending message. This prevents a "death in transit" problem
* where a message is garbage collected while in transit between two threads - i.e., the sending threads
* loses the reference and runs a garbage collection before the receiving thread gets the message. */
janet_abstract_incref(abstract);
pushbyte(st, LB_THREADED_ABSTRACT);
pushbytes(st, (uint8_t *) &abstract, sizeof(abstract));
MARK_SEEN();
return;
}
#endif
const JanetAbstractType *at = janet_abstract_type(abstract);
if (at->marshal) {
pushbyte(st, LB_ABSTRACT);
marshal_one(st, janet_csymbolv(at->name), flags + 1);
JanetMarshalContext context = {st, NULL, flags, NULL, at};
JanetMarshalContext context = {st, NULL, flags + 1, NULL, at};
at->marshal(abstract, &context);
} else {
janet_panicf("try to marshal unregistered abstract type, cannot marshal %p", x);
janet_panicf("cannot marshal %p", x);
}
}
@ -408,11 +480,14 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
/* Check reference and registry value */
{
Janet check = janet_table_get(&st->seen, x);
if (janet_checkint(check)) {
pushbyte(st, LB_REFERENCE);
pushint(st, janet_unwrap_integer(check));
return;
Janet check;
if (st->maybe_cycles) {
check = janet_table_get(&st->seen, x);
if (janet_checkint(check)) {
pushbyte(st, LB_REFERENCE);
pushint(st, janet_unwrap_integer(check));
return;
}
}
if (st->rreg) {
check = janet_table_get(st->rreg, x);
@ -475,6 +550,16 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
JanetBuffer *buffer = janet_unwrap_buffer(x);
/* Record reference */
MARK_SEEN();
#ifdef JANET_EV
if ((flags & JANET_MARSHAL_UNSAFE) &&
(buffer->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC)) {
pushbyte(st, LB_POINTER_BUFFER);
pushint(st, buffer->count);
pushint(st, buffer->capacity);
pushpointer(st, buffer->data);
return;
}
#endif
pushbyte(st, LB_BUFFER);
pushint(st, buffer->count);
pushbytes(st, buffer->data, buffer->count);
@ -523,8 +608,10 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
int32_t count;
const JanetKV *struct_ = janet_unwrap_struct(x);
count = janet_struct_length(struct_);
pushbyte(st, LB_STRUCT);
pushbyte(st, janet_struct_proto(struct_) ? LB_STRUCT_PROTO : LB_STRUCT);
pushint(st, count);
if (janet_struct_proto(struct_))
marshal_one(st, janet_wrap_struct(janet_struct_proto(struct_)), flags + 1);
for (int32_t i = 0; i < janet_struct_capacity(struct_); i++) {
if (janet_checktype(struct_[i].key, JANET_NIL))
continue;
@ -542,9 +629,10 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
case JANET_FUNCTION: {
pushbyte(st, LB_FUNCTION);
JanetFunction *func = janet_unwrap_function(x);
marshal_one_def(st, func->def, flags);
/* Mark seen after reading def, but before envs */
pushint(st, func->def->environments_length);
/* Mark seen before reading def */
MARK_SEEN();
marshal_one_def(st, func->def, flags);
for (int32_t i = 0; i < func->def->environments_length; i++)
marshal_one_env(st, func->envs[i], flags + 1);
return;
@ -567,8 +655,7 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
if (!(flags & JANET_MARSHAL_UNSAFE)) goto no_registry;
MARK_SEEN();
pushbyte(st, LB_UNSAFE_POINTER);
void *ptr = janet_unwrap_pointer(x);
pushbytes(st, (uint8_t *) &ptr, sizeof(void *));
pushpointer(st, janet_unwrap_pointer(x));
return;
}
no_registry:
@ -590,6 +677,7 @@ void janet_marshal(
st.seen_defs = NULL;
st.seen_envs = NULL;
st.rreg = rreg;
st.maybe_cycles = !(flags & JANET_MARSHAL_NO_CYCLES);
janet_table_init(&st.seen, 0);
marshal_one(&st, x, flags);
janet_table_deinit(&st.seen);
@ -674,9 +762,22 @@ static uint64_t read64(UnmarshalState *st, const uint8_t **atdata) {
return ret;
}
#ifdef JANET_MARSHAL_DEBUG
static void dump_reference_table(UnmarshalState *st) {
for (int32_t i = 0; i < janet_v_count(st->lookup); i++) {
janet_eprintf(" reference %d (%t) = %v\n", i, st->lookup[i], st->lookup[i]);
}
}
#endif
/* Assert a janet type */
static void janet_asserttype(Janet x, JanetType t) {
static void janet_asserttype(Janet x, JanetType t, UnmarshalState *st) {
if (!janet_checktype(x, t)) {
#ifdef JANET_MARSHAL_DEBUG
dump_reference_table(st);
#else
(void) st;
#endif
janet_panicf("expected type %T, got %v", 1 << t, x);
}
}
@ -728,7 +829,7 @@ static const uint8_t *unmarshal_one_env(
Janet fiberv;
/* On stack variant */
data = unmarshal_one(st, data, &fiberv, flags);
janet_asserttype(fiberv, JANET_FIBER);
janet_asserttype(fiberv, JANET_FIBER, st);
env->as.fiber = janet_unwrap_fiber(fiberv);
/* Negative offset indicates untrusted input */
env->offset = -offset;
@ -737,7 +838,7 @@ static const uint8_t *unmarshal_one_env(
if (length == 0) {
janet_panic("invalid funcenv length");
}
env->as.values = malloc(sizeof(Janet) * (size_t) length);
env->as.values = janet_malloc(sizeof(Janet) * (size_t) length);
if (!env->as.values) {
JANET_OUT_OF_MEMORY;
}
@ -794,6 +895,8 @@ static const uint8_t *unmarshal_one_def(
def->constants = NULL;
def->bytecode = NULL;
def->sourcemap = NULL;
def->symbolmap = NULL;
def->symbolmap_length = 0;
janet_v_push(st->lookup_defs, def);
/* Set default lengths to zero */
@ -801,6 +904,7 @@ static const uint8_t *unmarshal_one_def(
int32_t constants_length = 0;
int32_t environments_length = 0;
int32_t defs_length = 0;
int32_t symbolmap_length = 0;
/* Read flags and other fixed values */
def->flags = readint(st, &data);
@ -816,24 +920,26 @@ static const uint8_t *unmarshal_one_def(
environments_length = readnat(st, &data);
if (def->flags & JANET_FUNCDEF_FLAG_HASDEFS)
defs_length = readnat(st, &data);
if (def->flags & JANET_FUNCDEF_FLAG_HASSYMBOLMAP)
symbolmap_length = readnat(st, &data);
/* Check name and source (optional) */
if (def->flags & JANET_FUNCDEF_FLAG_HASNAME) {
Janet x;
data = unmarshal_one(st, data, &x, flags + 1);
janet_asserttype(x, JANET_STRING);
janet_asserttype(x, JANET_STRING, st);
def->name = janet_unwrap_string(x);
}
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCE) {
Janet x;
data = unmarshal_one(st, data, &x, flags + 1);
janet_asserttype(x, JANET_STRING);
janet_asserttype(x, JANET_STRING, st);
def->source = janet_unwrap_string(x);
}
/* Unmarshal constants */
if (constants_length) {
def->constants = malloc(sizeof(Janet) * constants_length);
def->constants = janet_malloc(sizeof(Janet) * constants_length);
if (!def->constants) {
JANET_OUT_OF_MEMORY;
}
@ -844,8 +950,29 @@ static const uint8_t *unmarshal_one_def(
}
def->constants_length = constants_length;
/* Unmarshal symbol map, if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASSYMBOLMAP) {
size_t size = sizeof(JanetSymbolMap) * symbolmap_length;
def->symbolmap = janet_malloc(size);
if (def->symbolmap == NULL) {
JANET_OUT_OF_MEMORY;
}
for (int32_t i = 0; i < symbolmap_length; i++) {
def->symbolmap[i].birth_pc = (uint32_t) readint(st, &data);
def->symbolmap[i].death_pc = (uint32_t) readint(st, &data);
def->symbolmap[i].slot_index = (uint32_t) readint(st, &data);
Janet value;
data = unmarshal_one(st, data, &value, flags + 1);
if (!janet_checktype(value, JANET_SYMBOL)) {
janet_panicf("corrupted symbolmap when unmarshalling debug info, got %v", value);
}
def->symbolmap[i].symbol = janet_unwrap_symbol(value);
}
def->symbolmap_length = (uint32_t) symbolmap_length;
}
/* Unmarshal bytecode */
def->bytecode = malloc(sizeof(uint32_t) * bytecode_length);
def->bytecode = janet_malloc(sizeof(uint32_t) * bytecode_length);
if (!def->bytecode) {
JANET_OUT_OF_MEMORY;
}
@ -854,7 +981,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal environments */
if (def->flags & JANET_FUNCDEF_FLAG_HASENVS) {
def->environments = calloc(1, sizeof(int32_t) * (size_t) environments_length);
def->environments = janet_calloc(1, sizeof(int32_t) * (size_t) environments_length);
if (!def->environments) {
JANET_OUT_OF_MEMORY;
}
@ -868,7 +995,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal sub funcdefs */
if (def->flags & JANET_FUNCDEF_FLAG_HASDEFS) {
def->defs = calloc(1, sizeof(JanetFuncDef *) * (size_t) defs_length);
def->defs = janet_calloc(1, sizeof(JanetFuncDef *) * (size_t) defs_length);
if (!def->defs) {
JANET_OUT_OF_MEMORY;
}
@ -883,7 +1010,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal source maps if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
int32_t current = 0;
def->sourcemap = malloc(sizeof(JanetSourceMapping) * (size_t) bytecode_length);
def->sourcemap = janet_malloc(sizeof(JanetSourceMapping) * (size_t) bytecode_length);
if (!def->sourcemap) {
JANET_OUT_OF_MEMORY;
}
@ -899,7 +1026,7 @@ static const uint8_t *unmarshal_one_def(
/* Unmarshal closure bitset if needed */
if (def->flags & JANET_FUNCDEF_FLAG_HASCLOBITSET) {
int32_t n = (def->slotcount + 31) >> 5;
def->closure_bitset = malloc(sizeof(uint32_t) * (size_t) n);
def->closure_bitset = janet_malloc(sizeof(uint32_t) * (size_t) n);
if (NULL == def->closure_bitset) {
JANET_OUT_OF_MEMORY;
}
@ -934,6 +1061,14 @@ static const uint8_t *unmarshal_one_fiber(
fiber->data = NULL;
fiber->child = NULL;
fiber->env = NULL;
fiber->last_value = janet_wrap_nil();
#ifdef JANET_EV
fiber->sched_id = 0;
fiber->supervisor_channel = NULL;
fiber->ev_state = NULL;
fiber->ev_callback = NULL;
fiber->ev_stream = NULL;
#endif
/* Push fiber to seen stack */
janet_v_push(st->lookup, janet_wrap_fiber(fiber));
@ -955,7 +1090,7 @@ static const uint8_t *unmarshal_one_fiber(
/* Allocate stack memory */
fiber->capacity = fiber_stacktop + 10;
fiber->data = malloc(sizeof(Janet) * fiber->capacity);
fiber->data = janet_malloc(sizeof(Janet) * fiber->capacity);
if (!fiber->data) {
JANET_OUT_OF_MEMORY;
}
@ -981,7 +1116,7 @@ static const uint8_t *unmarshal_one_fiber(
/* Get function */
Janet funcv;
data = unmarshal_one(st, data, &funcv, flags + 1);
janet_asserttype(funcv, JANET_FUNCTION);
janet_asserttype(funcv, JANET_FUNCTION, st);
func = janet_unwrap_function(funcv);
def = func->def;
@ -1027,7 +1162,7 @@ static const uint8_t *unmarshal_one_fiber(
Janet envv;
fiber_flags &= ~JANET_FIBER_FLAG_HASENV;
data = unmarshal_one(st, data, &envv, flags + 1);
janet_asserttype(envv, JANET_TABLE);
janet_asserttype(envv, JANET_TABLE, st);
fiber_env = janet_unwrap_table(envv);
}
@ -1036,10 +1171,13 @@ static const uint8_t *unmarshal_one_fiber(
Janet fiberv;
fiber_flags &= ~JANET_FIBER_FLAG_HASCHILD;
data = unmarshal_one(st, data, &fiberv, flags + 1);
janet_asserttype(fiberv, JANET_FIBER);
janet_asserttype(fiberv, JANET_FIBER, st);
fiber->child = janet_unwrap_fiber(fiberv);
}
/* Get the fiber last value */
data = unmarshal_one(st, data, &fiber->last_value, flags + 1);
/* We have valid fiber, finally construct remaining fields. */
fiber->frame = frame;
fiber->flags = fiber_flags;
@ -1048,6 +1186,11 @@ static const uint8_t *unmarshal_one_fiber(
fiber->maxstack = fiber_maxstack;
fiber->env = fiber_env;
int status = janet_fiber_status(fiber);
if (status < 0 || status > JANET_STATUS_ALIVE) {
janet_panic("invalid fiber status");
}
/* Return data */
*out = fiber;
return data;
@ -1072,6 +1215,18 @@ int64_t janet_unmarshal_int64(JanetMarshalContext *ctx) {
return read64(st, &(ctx->data));
}
void *janet_unmarshal_ptr(JanetMarshalContext *ctx) {
if (!(ctx->flags & JANET_MARSHAL_UNSAFE)) {
janet_panic("can only unmarshal pointers in unsafe mode");
}
UnmarshalState *st = (UnmarshalState *)(ctx->u_state);
void *ptr;
MARSH_EOS(st, ctx->data + sizeof(void *) - 1);
memcpy((char *) &ptr, ctx->data, sizeof(void *));
ctx->data += sizeof(void *);
return ptr;
}
uint8_t janet_unmarshal_byte(JanetMarshalContext *ctx) {
UnmarshalState *st = (UnmarshalState *)(ctx->u_state);
MARSH_EOS(st, ctx->data);
@ -1092,32 +1247,49 @@ Janet janet_unmarshal_janet(JanetMarshalContext *ctx) {
return ret;
}
void *janet_unmarshal_abstract(JanetMarshalContext *ctx, size_t size) {
void janet_unmarshal_abstract_reuse(JanetMarshalContext *ctx, void *p) {
UnmarshalState *st = (UnmarshalState *)(ctx->u_state);
if (ctx->at == NULL) {
janet_panicf("janet_unmarshal_abstract called more than once");
}
void *p = janet_abstract(ctx->at, size);
janet_v_push(st->lookup, janet_wrap_abstract(p));
ctx->at = NULL;
}
void *janet_unmarshal_abstract(JanetMarshalContext *ctx, size_t size) {
void *p = janet_abstract(ctx->at, size);
janet_unmarshal_abstract_reuse(ctx, p);
return p;
}
void *janet_unmarshal_abstract_threaded(JanetMarshalContext *ctx, size_t size) {
#ifdef JANET_THREADS
void *p = janet_abstract_threaded(ctx->at, size);
janet_unmarshal_abstract_reuse(ctx, p);
return p;
#else
(void) ctx;
(void) size;
janet_panic("threaded abstracts not supported");
#endif
}
static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *data, Janet *out, int flags) {
Janet key;
data = unmarshal_one(st, data, &key, flags + 1);
const JanetAbstractType *at = janet_get_abstract_type(key);
if (at == NULL) goto oops;
if (at == NULL) janet_panic("unknown abstract type");
if (at->unmarshal) {
JanetMarshalContext context = {NULL, st, flags, data, at};
*out = janet_wrap_abstract(at->unmarshal(&context));
void *abst = at->unmarshal(&context);
janet_assert(abst != NULL, "null pointer abstract");
*out = janet_wrap_abstract(abst);
if (context.at != NULL) {
janet_panicf("janet_unmarshal_abstract not called");
janet_panic("janet_unmarshal_abstract not called");
}
return context.data;
}
oops:
janet_panic("invalid abstract type");
janet_panic("invalid abstract type - no unmarshal function pointer");
}
static const uint8_t *unmarshal_one(
@ -1212,20 +1384,29 @@ static const uint8_t *unmarshal_one(
}
case LB_FIBER: {
JanetFiber *fiber;
data = unmarshal_one_fiber(st, data + 1, &fiber, flags);
data = unmarshal_one_fiber(st, data + 1, &fiber, flags + 1);
*out = janet_wrap_fiber(fiber);
return data;
}
case LB_FUNCTION: {
JanetFunction *func;
JanetFuncDef *def;
data = unmarshal_one_def(st, data + 1, &def, flags + 1);
data++;
int32_t len = readnat(st, &data);
if (len > 255) {
janet_panicf("invalid function - too many environments (%d)", len);
}
func = janet_gcalloc(JANET_MEMORY_FUNCTION, sizeof(JanetFunction) +
def->environments_length * sizeof(JanetFuncEnv));
func->def = def;
len * sizeof(JanetFuncEnv));
func->def = NULL;
for (int32_t i = 0; i < len; i++) {
func->envs[i] = NULL;
}
*out = janet_wrap_function(func);
janet_v_push(st->lookup, *out);
for (int32_t i = 0; i < def->environments_length; i++) {
data = unmarshal_one_def(st, data, &def, flags + 1);
func->def = def;
for (int32_t i = 0; i < len; i++) {
data = unmarshal_one_env(st, data, &(func->envs[i]), flags + 1);
}
return data;
@ -1238,6 +1419,7 @@ static const uint8_t *unmarshal_one(
case LB_ARRAY:
case LB_TUPLE:
case LB_STRUCT:
case LB_STRUCT_PROTO:
case LB_TABLE:
case LB_TABLE_PROTO:
/* Things that open with integers */
@ -1267,9 +1449,15 @@ static const uint8_t *unmarshal_one(
}
*out = janet_wrap_tuple(janet_tuple_end(tup));
janet_v_push(st->lookup, *out);
} else if (lead == LB_STRUCT) {
} else if (lead == LB_STRUCT || lead == LB_STRUCT_PROTO) {
/* Struct */
JanetKV *struct_ = janet_struct_begin(len);
if (lead == LB_STRUCT_PROTO) {
Janet proto;
data = unmarshal_one(st, data, &proto, flags + 1);
janet_asserttype(proto, JANET_STRUCT, st);
janet_struct_proto(struct_) = janet_unwrap_struct(proto);
}
for (int32_t i = 0; i < len; i++) {
Janet key, value;
data = unmarshal_one(st, data, &key, flags + 1);
@ -1290,7 +1478,7 @@ static const uint8_t *unmarshal_one(
if (lead == LB_TABLE_PROTO) {
Janet proto;
data = unmarshal_one(st, data, &proto, flags + 1);
janet_asserttype(proto, JANET_TABLE);
janet_asserttype(proto, JANET_TABLE, st);
t->proto = janet_unwrap_table(proto);
}
for (int32_t i = 0; i < len; i++) {
@ -1320,6 +1508,29 @@ static const uint8_t *unmarshal_one(
janet_v_push(st->lookup, *out);
return data;
}
#ifdef JANET_EV
case LB_POINTER_BUFFER: {
data++;
int32_t count = readnat(st, &data);
int32_t capacity = readnat(st, &data);
MARSH_EOS(st, data + sizeof(void *));
union {
void *ptr;
uint8_t bytes[sizeof(void *)];
} u;
if (!(flags & JANET_MARSHAL_UNSAFE)) {
janet_panicf("unsafe flag not given, "
"will not unmarshal raw pointer at index %d",
(int)(data - st->start));
}
memcpy(u.bytes, data, sizeof(void *));
data += sizeof(void *);
JanetBuffer *buffer = janet_pointer_buffer_unsafe(u.ptr, capacity, count);
*out = janet_wrap_buffer(buffer);
janet_v_push(st->lookup, *out);
return data;
}
#endif
case LB_UNSAFE_CFUNCTION: {
MARSH_EOS(st, data + sizeof(JanetCFunction));
data++;
@ -1338,6 +1549,42 @@ static const uint8_t *unmarshal_one(
janet_v_push(st->lookup, *out);
return data;
}
#ifdef JANET_EV
case LB_THREADED_ABSTRACT: {
MARSH_EOS(st, data + sizeof(void *));
data++;
if (!(flags & JANET_MARSHAL_UNSAFE)) {
janet_panicf("unsafe flag not given, "
"will not unmarshal threaded abstract pointer at index %d",
(int)(data - st->start));
}
union {
void *ptr;
uint8_t bytes[sizeof(void *)];
} u;
memcpy(u.bytes, data, sizeof(void *));
data += sizeof(void *);
if (flags & JANET_MARSHAL_DECREF) {
/* Decrement immediately and don't bother putting into heap */
janet_abstract_decref(u.ptr);
*out = janet_wrap_nil();
} else {
*out = janet_wrap_abstract(u.ptr);
Janet check = janet_table_get(&janet_vm.threaded_abstracts, *out);
if (janet_checktype(check, JANET_NIL)) {
/* Transfers reference from threaded channel buffer to current heap */
janet_table_put(&janet_vm.threaded_abstracts, *out, janet_wrap_false());
} else {
/* Heap reference already accounted for, remove threaded channel reference. */
janet_abstract_decref(u.ptr);
}
}
janet_v_push(st->lookup, *out);
return data;
}
#endif
default: {
janet_panicf("unknown byte %x at index %d",
*data,
@ -1345,7 +1592,6 @@ static const uint8_t *unmarshal_one(
return NULL;
}
}
#undef EXTRA
}
Janet janet_unmarshal(
@ -1372,16 +1618,28 @@ Janet janet_unmarshal(
/* C functions */
static Janet cfun_env_lookup(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_env_lookup,
"(env-lookup env)",
"Creates a forward lookup table for unmarshalling from an environment. "
"To create a reverse lookup table, use the invert function to swap keys "
"and values in the returned table.") {
janet_fixarity(argc, 1);
JanetTable *env = janet_gettable(argv, 0);
return janet_wrap_table(janet_env_lookup(env));
}
static Janet cfun_marshal(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 3);
JANET_CORE_FN(cfun_marshal,
"(marshal x &opt reverse-lookup buffer no-cycles)",
"Marshal a value into a buffer and return the buffer. The buffer "
"can then later be unmarshalled to reconstruct the initial value. "
"Optionally, one can pass in a reverse lookup table to not marshal "
"aliased values that are found in the table. Then a forward "
"lookup table can be used to recover the original value when "
"unmarshalling.") {
janet_arity(argc, 1, 4);
JanetBuffer *buffer;
JanetTable *rreg = NULL;
uint32_t flags = 0;
if (argc > 1) {
rreg = janet_gettable(argv, 1);
}
@ -1390,11 +1648,18 @@ static Janet cfun_marshal(int32_t argc, Janet *argv) {
} else {
buffer = janet_buffer(10);
}
janet_marshal(buffer, argv[0], rreg, 0);
if (argc > 3 && janet_truthy(argv[3])) {
flags |= JANET_MARSHAL_NO_CYCLES;
}
janet_marshal(buffer, argv[0], rreg, flags);
return janet_wrap_buffer(buffer);
}
static Janet cfun_unmarshal(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_unmarshal,
"(unmarshal buffer &opt lookup)",
"Unmarshal a value from a buffer. An optional lookup table "
"can be provided to allow for aliases to be resolved. Returns the value "
"unmarshalled from the buffer.") {
janet_arity(argc, 1, 2);
JanetByteView view = janet_getbytes(argv, 0);
JanetTable *reg = NULL;
@ -1404,35 +1669,13 @@ static Janet cfun_unmarshal(int32_t argc, Janet *argv) {
return janet_unmarshal(view.bytes, (size_t) view.len, 0, reg, NULL);
}
static const JanetReg marsh_cfuns[] = {
{
"marshal", cfun_marshal,
JDOC("(marshal x &opt reverse-lookup buffer)\n\n"
"Marshal a value into a buffer and return the buffer. The buffer "
"can the later be unmarshalled to reconstruct the initial value. "
"Optionally, one can pass in a reverse lookup table to not marshal "
"aliased values that are found in the table. Then a forward"
"lookup table can be used to recover the original value when "
"unmarshalling.")
},
{
"unmarshal", cfun_unmarshal,
JDOC("(unmarshal buffer &opt lookup)\n\n"
"Unmarshal a value from a buffer. An optional lookup table "
"can be provided to allow for aliases to be resolved. Returns the value "
"unmarshalled from the buffer.")
},
{
"env-lookup", cfun_env_lookup,
JDOC("(env-lookup env)\n\n"
"Creates a forward lookup table for unmarshalling from an environment. "
"To create a reverse lookup table, use the invert function to swap keys "
"and values in the returned table.")
},
{NULL, NULL, NULL}
};
/* Module entry point */
void janet_lib_marsh(JanetTable *env) {
janet_core_cfuns(env, NULL, marsh_cfuns);
JanetRegExt marsh_cfuns[] = {
JANET_CORE_REG("marshal", cfun_marshal),
JANET_CORE_REG("unmarshal", cfun_unmarshal),
JANET_CORE_REG("env-lookup", cfun_env_lookup),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, marsh_cfuns);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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,14 +23,14 @@
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "state.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 Janet janet_rng_next(void *p, Janet key);
static void janet_rng_marshal(void *p, JanetMarshalContext *ctx) {
JanetRNG *rng = (JanetRNG *)p;
@ -60,11 +60,15 @@ const JanetAbstractType janet_rng_type = {
NULL,
janet_rng_marshal,
janet_rng_unmarshal,
JANET_ATEND_UNMARSHAL
NULL, /* tostring */
NULL, /* compare */
NULL, /* hash */
janet_rng_next,
JANET_ATEND_NEXT
};
JanetRNG *janet_default_rng(void) {
return &janet_vm_rng;
return &janet_vm.rng;
}
void janet_rng_seed(JanetRNG *rng, uint32_t seed) {
@ -113,7 +117,12 @@ double janet_rng_double(JanetRNG *rng) {
return ldexp((double)(big >> (64 - 52)), -52);
}
static Janet cfun_rng_make(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_rng_make,
"(math/rng &opt seed)",
"Creates a Pseudo-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."
) {
janet_arity(argc, 0, 1);
JanetRNG *rng = janet_abstract(&janet_rng_type, sizeof(JanetRNG));
if (argc == 1) {
@ -130,13 +139,20 @@ static Janet cfun_rng_make(int32_t argc, Janet *argv) {
return janet_wrap_abstract(rng);
}
static Janet cfun_rng_uniform(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_rng_uniform,
"(math/rng-uniform rng)",
"Extract a random number in the range [0, 1) from the RNG."
) {
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_CORE_FN(cfun_rng_int,
"(math/rng-int rng &opt max)",
"Extract a random integer in the range [0, max) for max > 0 from the RNG. "
"If max is 0, return 0. If no max is given, the default is 2^31 - 1."
) {
janet_arity(argc, 1, 2);
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
if (argc == 1) {
@ -164,7 +180,11 @@ static void rng_get_4bytes(JanetRNG *rng, uint8_t *buf) {
buf[3] = (word >> 24) & 0xFF;
}
static Janet cfun_rng_buffer(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_rng_buffer,
"(math/rng-buffer rng n &opt buf)",
"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."
) {
janet_arity(argc, 2, 3);
JanetRNG *rng = janet_getabstract(argv, 0, &janet_rng_type);
int32_t n = janet_getnat(argv, 1);
@ -203,315 +223,225 @@ static int janet_rng_get(void *p, Janet key, Janet *out) {
return janet_getmethod(janet_unwrap_keyword(key), rng_methods, out);
}
static Janet janet_rng_next(void *p, Janet key) {
(void) p;
return janet_nextmethod(rng_methods, key);
}
/* Get a random number */
static Janet janet_rand(int32_t argc, Janet *argv) {
JANET_CORE_FN(janet_rand,
"(math/random)",
"Returns a uniformly distributed random number between 0 and 1.") {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_number(janet_rng_double(&janet_vm_rng));
return janet_wrap_number(janet_rng_double(&janet_vm.rng));
}
/* Seed the random number generator */
static Janet janet_srand(int32_t argc, Janet *argv) {
JANET_CORE_FN(janet_srand,
"(math/seedrandom seed)",
"Set the seed for the random number generator. `seed` should be "
"an integer or a buffer."
) {
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);
janet_rng_seed(&janet_vm.rng, seed);
} else {
JanetByteView bytes = janet_getbytes(argv, 0);
janet_rng_longseed(&janet_vm_rng, bytes.bytes, bytes.len);
janet_rng_longseed(&janet_vm.rng, bytes.bytes, bytes.len);
}
return janet_wrap_nil();
}
#define JANET_DEFINE_MATHOP(name, fop)\
static Janet janet_##name(int32_t argc, Janet *argv) {\
#define JANET_DEFINE_NAMED_MATHOP(janet_name, fop, doc)\
JANET_CORE_FN(janet_##fop, "(math/" janet_name " x)", doc) {\
janet_fixarity(argc, 1); \
double x = janet_getnumber(argv, 0); \
return janet_wrap_number(fop(x)); \
}
JANET_DEFINE_MATHOP(acos, acos)
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_MATHOP(fop, doc) JANET_DEFINE_NAMED_MATHOP(#fop, fop, doc)
#define JANET_DEFINE_MATH2OP(name, fop)\
static Janet janet_##name(int32_t argc, Janet *argv) {\
JANET_DEFINE_MATHOP(acos, "Returns the arccosine of x.")
JANET_DEFINE_MATHOP(asin, "Returns the arcsin of x.")
JANET_DEFINE_MATHOP(atan, "Returns the arctangent of x.")
JANET_DEFINE_MATHOP(cos, "Returns the cosine of x.")
JANET_DEFINE_MATHOP(cosh, "Returns the hyperbolic cosine of x.")
JANET_DEFINE_MATHOP(acosh, "Returns the hyperbolic arccosine of x.")
JANET_DEFINE_MATHOP(sin, "Returns the sine of x.")
JANET_DEFINE_MATHOP(sinh, "Returns the hyperbolic sine of x.")
JANET_DEFINE_MATHOP(asinh, "Returns the hyperbolic arcsine of x.")
JANET_DEFINE_MATHOP(tan, "Returns the tangent of x.")
JANET_DEFINE_MATHOP(tanh, "Returns the hyperbolic tangent of x.")
JANET_DEFINE_MATHOP(atanh, "Returns the hyperbolic arctangent of x.")
JANET_DEFINE_MATHOP(exp, "Returns e to the power of x.")
JANET_DEFINE_MATHOP(exp2, "Returns 2 to the power of x.")
JANET_DEFINE_MATHOP(expm1, "Returns e to the power of x minus 1.")
JANET_DEFINE_MATHOP(log, "Returns the natural logarithm of x.")
JANET_DEFINE_MATHOP(log10, "Returns the log base 10 of x.")
JANET_DEFINE_MATHOP(log2, "Returns the log base 2 of x.")
JANET_DEFINE_MATHOP(sqrt, "Returns the square root of x.")
JANET_DEFINE_MATHOP(cbrt, "Returns the cube root of x.")
JANET_DEFINE_MATHOP(ceil, "Returns the smallest integer value number that is not less than x.")
JANET_DEFINE_MATHOP(floor, "Returns the largest integer value number that is not greater than x.")
JANET_DEFINE_MATHOP(trunc, "Returns the integer between x and 0 nearest to x.")
JANET_DEFINE_MATHOP(round, "Returns the integer nearest to x.")
JANET_DEFINE_MATHOP(log1p, "Returns (log base e of x) + 1 more accurately than (+ (math/log x) 1)")
JANET_DEFINE_MATHOP(erf, "Returns the error function of x.")
JANET_DEFINE_MATHOP(erfc, "Returns the complementary error function of x.")
JANET_DEFINE_NAMED_MATHOP("log-gamma", lgamma, "Returns log-gamma(x).")
JANET_DEFINE_NAMED_MATHOP("abs", fabs, "Return the absolute value of x.")
JANET_DEFINE_NAMED_MATHOP("gamma", tgamma, "Returns gamma(x).")
#define JANET_DEFINE_MATH2OP(name, fop, signature, doc)\
JANET_CORE_FN(janet_##name, signature, doc) {\
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)
JANET_DEFINE_MATH2OP(atan2, atan2, "(math/atan2 y x)", "Returns the arctangent of y/x. Works even when x is 0.")
JANET_DEFINE_MATH2OP(pow, pow, "(math/pow a x)", "Returns a to the power of x.")
JANET_DEFINE_MATH2OP(hypot, hypot, "(math/hypot a b)", "Returns c from the equation c^2 = a^2 + b^2.")
JANET_DEFINE_MATH2OP(nextafter, nextafter, "(math/next x y)", "Returns the next representable floating point value after x in the direction of y.")
static Janet janet_not(int32_t argc, Janet *argv) {
JANET_CORE_FN(janet_not, "(not x)", "Returns the boolean inverse of x.") {
janet_fixarity(argc, 1);
return janet_wrap_boolean(!janet_truthy(argv[0]));
}
static const JanetReg math_cfuns[] = {
{
"not", janet_not,
JDOC("(not x)\n\nReturns the boolean inverse of x.")
},
{
"math/random", janet_rand,
JDOC("(math/random)\n\n"
"Returns a uniformly distributed random number between 0 and 1.")
},
{
"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.")
},
{
"math/cos", janet_cos,
JDOC("(math/cos x)\n\n"
"Returns the cosine of x.")
},
{
"math/sin", janet_sin,
JDOC("(math/sin x)\n\n"
"Returns the sine of x.")
},
{
"math/tan", janet_tan,
JDOC("(math/tan x)\n\n"
"Returns the tangent of x.")
},
{
"math/acos", janet_acos,
JDOC("(math/acos x)\n\n"
"Returns the arccosine of x.")
},
{
"math/asin", janet_asin,
JDOC("(math/asin x)\n\n"
"Returns the arcsine of x.")
},
{
"math/atan", janet_atan,
JDOC("(math/atan x)\n\n"
"Returns the arctangent of x.")
},
{
"math/exp", janet_exp,
JDOC("(math/exp x)\n\n"
"Returns e to the power of x.")
},
{
"math/log", janet_log,
JDOC("(math/log x)\n\n"
"Returns log base natural number of x.")
},
{
"math/log10", janet_log10,
JDOC("(math/log10 x)\n\n"
"Returns log base 10 of x.")
},
{
"math/log2", janet_log2,
JDOC("(math/log2 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/cbrt", janet_cbrt,
JDOC("(math/cbrt x)\n\n"
"Returns the cube 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/ceil", janet_ceil,
JDOC("(math/ceil x)\n\n"
"Returns the smallest integer value 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/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}
};
static double janet_gcd(double x, double y) {
if (isnan(x) || isnan(y)) {
#ifdef NAN
return NAN;
#else
return 0.0 / 0.0;
#endif
}
if (isinf(x) || isinf(y)) return INFINITY;
while (y != 0) {
double temp = y;
y = fmod(x, y);
x = temp;
}
return x;
}
static double janet_lcm(double x, double y) {
return (x / janet_gcd(x, y)) * y;
}
JANET_CORE_FN(janet_cfun_gcd, "(math/gcd x y)",
"Returns the greatest common divisor between x and y.") {
janet_fixarity(argc, 2);
double x = janet_getnumber(argv, 0);
double y = janet_getnumber(argv, 1);
return janet_wrap_number(janet_gcd(x, y));
}
JANET_CORE_FN(janet_cfun_lcm, "(math/lcm x y)",
"Returns the least common multiple of x and y.") {
janet_fixarity(argc, 2);
double x = janet_getnumber(argv, 0);
double y = janet_getnumber(argv, 1);
return janet_wrap_number(janet_lcm(x, y));
}
JANET_CORE_FN(janet_cfun_frexp, "(math/frexp x)",
"Returns a tuple of (mantissa, exponent) from number.") {
janet_fixarity(argc, 1);
double x = janet_getnumber(argv, 0);
int exp;
x = frexp(x, &exp);
Janet *result = janet_tuple_begin(2);
result[0] = janet_wrap_number(x);
result[1] = janet_wrap_number((double) exp);
return janet_wrap_tuple(janet_tuple_end(result));
}
JANET_CORE_FN(janet_cfun_ldexp, "(math/ldexp m e)",
"Creates a new number from a mantissa and an exponent.") {
janet_fixarity(argc, 2);
double x = janet_getnumber(argv, 0);
int32_t y = janet_getinteger(argv, 1);
return janet_wrap_number(ldexp(x, y));
}
/* Module entry point */
void janet_lib_math(JanetTable *env) {
janet_core_cfuns(env, NULL, math_cfuns);
JanetRegExt math_cfuns[] = {
JANET_CORE_REG("not", janet_not),
JANET_CORE_REG("math/random", janet_rand),
JANET_CORE_REG("math/seedrandom", janet_srand),
JANET_CORE_REG("math/cos", janet_cos),
JANET_CORE_REG("math/sin", janet_sin),
JANET_CORE_REG("math/tan", janet_tan),
JANET_CORE_REG("math/acos", janet_acos),
JANET_CORE_REG("math/asin", janet_asin),
JANET_CORE_REG("math/atan", janet_atan),
JANET_CORE_REG("math/exp", janet_exp),
JANET_CORE_REG("math/log", janet_log),
JANET_CORE_REG("math/log10", janet_log10),
JANET_CORE_REG("math/log2", janet_log2),
JANET_CORE_REG("math/sqrt", janet_sqrt),
JANET_CORE_REG("math/cbrt", janet_cbrt),
JANET_CORE_REG("math/floor", janet_floor),
JANET_CORE_REG("math/ceil", janet_ceil),
JANET_CORE_REG("math/pow", janet_pow),
JANET_CORE_REG("math/abs", janet_fabs),
JANET_CORE_REG("math/sinh", janet_sinh),
JANET_CORE_REG("math/cosh", janet_cosh),
JANET_CORE_REG("math/tanh", janet_tanh),
JANET_CORE_REG("math/atanh", janet_atanh),
JANET_CORE_REG("math/asinh", janet_asinh),
JANET_CORE_REG("math/acosh", janet_acosh),
JANET_CORE_REG("math/atan2", janet_atan2),
JANET_CORE_REG("math/rng", cfun_rng_make),
JANET_CORE_REG("math/rng-uniform", cfun_rng_uniform),
JANET_CORE_REG("math/rng-int", cfun_rng_int),
JANET_CORE_REG("math/rng-buffer", cfun_rng_buffer),
JANET_CORE_REG("math/hypot", janet_hypot),
JANET_CORE_REG("math/exp2", janet_exp2),
JANET_CORE_REG("math/log1p", janet_log1p),
JANET_CORE_REG("math/gamma", janet_tgamma),
JANET_CORE_REG("math/log-gamma", janet_lgamma),
JANET_CORE_REG("math/erfc", janet_erfc),
JANET_CORE_REG("math/erf", janet_erf),
JANET_CORE_REG("math/expm1", janet_expm1),
JANET_CORE_REG("math/trunc", janet_trunc),
JANET_CORE_REG("math/round", janet_round),
JANET_CORE_REG("math/next", janet_nextafter),
JANET_CORE_REG("math/gcd", janet_cfun_gcd),
JANET_CORE_REG("math/lcm", janet_cfun_lcm),
JANET_CORE_REG("math/frexp", janet_cfun_frexp),
JANET_CORE_REG("math/ldexp", janet_cfun_ldexp),
JANET_REG_END
};
janet_core_cfuns_ext(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))"));
JANET_CORE_DEF(env, "math/pi", janet_wrap_number(3.1415926535897931),
"The value pi.");
JANET_CORE_DEF(env, "math/e", janet_wrap_number(2.7182818284590451),
"The base of the natural log.");
JANET_CORE_DEF(env, "math/inf", janet_wrap_number(INFINITY),
"The number representing positive infinity");
JANET_CORE_DEF(env, "math/-inf", janet_wrap_number(-INFINITY),
"The number representing negative infinity");
JANET_CORE_DEF(env, "math/int32-min", janet_wrap_number(INT32_MIN),
"The minimum contiguous integer representable by a 32 bit signed integer");
JANET_CORE_DEF(env, "math/int32-max", janet_wrap_number(INT32_MAX),
"The maximum contiguous integer representable by a 32 bit signed integer");
JANET_CORE_DEF(env, "math/int-min", janet_wrap_number(JANET_INTMIN_DOUBLE),
"The minimum contiguous integer representable by a double (2^53)");
JANET_CORE_DEF(env, "math/int-max", janet_wrap_number(JANET_INTMAX_DOUBLE),
"The maximum contiguous integer representable by a double (-(2^53))");
#ifdef NAN
janet_def(env, "math/nan", janet_wrap_number(NAN),
JANET_CORE_DEF(env, "math/nan", janet_wrap_number(NAN), "Not a number (IEEE-754 NaN)");
#else
janet_def(env, "math/nan", janet_wrap_number(0.0 / 0.0),
JANET_CORE_DEF(env, "math/nan", janet_wrap_number(0.0 / 0.0), "Not a number (IEEE-754 NaN)");
#endif
JDOC("Not a number (IEEE-754 NaN)"));
#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) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -51,15 +51,15 @@ static const uint32_t symchars[8] = {
};
/* Check if a character is a valid symbol character
* symbol chars are A-Z, a-z, 0-9, or one of !$&*+-./:<=>@\^_~| */
static int is_symbol_char(uint8_t c) {
* symbol chars are A-Z, a-z, 0-9, or one of !$&*+-./:<=>@\^_| */
int janet_is_symbol_char(uint8_t c) {
return symchars[c >> 5] & ((uint32_t)1 << (c & 0x1F));
}
/* Validate some utf8. Useful for identifiers. Only validates
* the encoding, does not check for valid code points (they
* are less well defined than the encoding). */
static int valid_utf8(const uint8_t *str, int32_t len) {
int janet_valid_utf8(const uint8_t *str, int32_t len) {
int32_t i = 0;
int32_t j;
while (i < len) {
@ -123,7 +123,7 @@ static void NAME(JanetParser *p, T x) { \
if (newcount > p->STACKCAP) { \
T *next; \
size_t newcap = 2 * newcount; \
next = realloc(p->STACK, sizeof(T) * newcap); \
next = janet_realloc(p->STACK, sizeof(T) * newcap); \
if (NULL == next) { \
JANET_OUT_OF_MEMORY; \
} \
@ -175,7 +175,14 @@ static void popstate(JanetParser *p, Janet val) {
if (newtop->flags & PFLAG_CONTAINER) {
newtop->argn++;
/* Keep track of number of values in the root state */
if (p->statecount == 1) p->pending++;
if (p->statecount == 1) {
p->pending++;
/* Root items are always wrapped in a tuple for source map info. */
const Janet *tup = janet_tuple_n(&val, 1);
janet_tuple_sm_line(tup) = (int32_t) top.line;
janet_tuple_sm_column(tup) = (int32_t) top.column;
val = janet_wrap_tuple(tup);
}
push_arg(p, val);
return;
} else if (newtop->flags & PFLAG_READERMAC) {
@ -199,6 +206,37 @@ static void popstate(JanetParser *p, Janet val) {
}
}
static void delim_error(JanetParser *parser, size_t stack_index, char c, const char *msg) {
JanetParseState *s = parser->states + stack_index;
JanetBuffer *buffer = janet_buffer(40);
if (msg) {
janet_buffer_push_cstring(buffer, msg);
}
if (c) {
janet_buffer_push_u8(buffer, c);
}
if (stack_index > 0) {
janet_buffer_push_cstring(buffer, ", ");
if (s->flags & PFLAG_PARENS) {
janet_buffer_push_u8(buffer, '(');
} else if (s->flags & PFLAG_SQRBRACKETS) {
janet_buffer_push_u8(buffer, '[');
} else if (s->flags & PFLAG_CURLYBRACKETS) {
janet_buffer_push_u8(buffer, '{');
} else if (s->flags & PFLAG_STRING) {
janet_buffer_push_u8(buffer, '"');
} else if (s->flags & PFLAG_LONGSTRING) {
int32_t i;
for (i = 0; i < s->argn; i++) {
janet_buffer_push_u8(buffer, '`');
}
}
janet_formatb(buffer, " opened at line %d, column %d", s->line, s->column);
}
parser->error = (const char *) janet_string(buffer->data, buffer->count);
parser->flag |= JANET_PARSER_GENERATED_ERROR;
}
static int checkescape(uint8_t c) {
switch (c) {
default:
@ -221,6 +259,14 @@ static int checkescape(uint8_t c) {
return '\f';
case 'v':
return '\v';
case 'a':
return '\a';
case 'b':
return '\b';
case '\'':
return '\'';
case '?':
return '?';
case 'e':
return 27;
case '"':
@ -313,11 +359,48 @@ static int stringend(JanetParser *p, JanetParseState *state) {
uint8_t *bufstart = p->buf;
int32_t buflen = (int32_t) p->bufcount;
if (state->flags & PFLAG_LONGSTRING) {
/* Check for leading newline character so we can remove it */
if (bufstart[0] == '\n') {
bufstart++;
buflen--;
/* Post process to remove leading whitespace */
JanetParseState top = p->states[p->statecount - 1];
int32_t indent_col = (int32_t) top.column - 1;
uint8_t *r = bufstart, *end = r + buflen;
/* Check if there are any characters before the start column -
* if so, do not reindent. */
int reindent = 1;
while (reindent && (r < end)) {
if (*r++ == '\n') {
for (int32_t j = 0; (r < end) && (*r != '\n') && (j < indent_col); j++, r++) {
if (*r != ' ') {
reindent = 0;
break;
}
}
}
}
/* Now reindent if able to, otherwise just drop leading newline. */
if (!reindent) {
if (buflen > 0 && bufstart[0] == '\n') {
buflen--;
bufstart++;
}
} else {
uint8_t *w = bufstart;
r = bufstart;
while (r < end) {
if (*r == '\n') {
if (r == bufstart) {
/* Skip leading newline */
r++;
} else {
*w++ = *r++;
}
for (int32_t j = 0; (r < end) && (*r != '\n') && (j < indent_col); j++, r++);
} else {
*w++ = *r++;
}
}
buflen = (int32_t)(w - bufstart);
}
/* Check for trailing newline character so we can remove it */
if (buflen > 0 && bufstart[buflen - 1] == '\n') {
buflen--;
}
@ -367,7 +450,7 @@ static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) {
Janet ret;
double numval;
int32_t blen;
if (is_symbol_char(c)) {
if (janet_is_symbol_char(c)) {
push_buf(p, (uint8_t) c);
if (c > 127) state->argn = 1; /* Use to indicate non ascii */
return 1;
@ -378,7 +461,7 @@ static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) {
int start_num = start_dig || p->buf[0] == '-' || p->buf[0] == '+' || p->buf[0] == '.';
if (p->buf[0] == ':') {
/* Don't do full utf-8 check unless we have seen non ascii characters. */
int valid = (!state->argn) || valid_utf8(p->buf + 1, blen - 1);
int valid = (!state->argn) || janet_valid_utf8(p->buf + 1, blen - 1);
if (!valid) {
p->error = "invalid utf-8 in keyword";
return 0;
@ -398,7 +481,7 @@ static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) {
return 0;
} else {
/* Don't do full utf-8 check unless we have seen non ascii characters. */
int valid = (!state->argn) || valid_utf8(p->buf, blen);
int valid = (!state->argn) || janet_valid_utf8(p->buf, blen);
if (!valid) {
p->error = "invalid utf-8 in symbol";
return 0;
@ -538,7 +621,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
switch (c) {
default:
if (is_whitespace(c)) return 1;
if (!is_symbol_char(c)) {
if (!janet_is_symbol_char(c)) {
p->error = "unexpected character";
return 1;
}
@ -568,7 +651,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
case '}': {
Janet ds;
if (p->statecount == 1) {
p->error = "unexpected delimiter";
delim_error(p, 0, c, "unexpected closing delimiter ");
return 1;
}
if ((c == ')' && (state->flags & PFLAG_PARENS)) ||
@ -589,7 +672,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
ds = close_struct(p, state);
}
} else {
p->error = "mismatched delimiter";
delim_error(p, p->statecount - 1, c, "mismatched delimiter ");
return 1;
}
popstate(p, ds);
@ -640,26 +723,7 @@ void janet_parser_eof(JanetParser *parser) {
size_t oldline = parser->line;
janet_parser_consume(parser, '\n');
if (parser->statecount > 1) {
JanetParseState *s = parser->states + (parser->statecount - 1);
JanetBuffer *buffer = janet_buffer(40);
janet_buffer_push_cstring(buffer, "unexpected end of source, ");
if (s->flags & PFLAG_PARENS) {
janet_buffer_push_u8(buffer, '(');
} else if (s->flags & PFLAG_SQRBRACKETS) {
janet_buffer_push_u8(buffer, '[');
} else if (s->flags & PFLAG_CURLYBRACKETS) {
janet_buffer_push_u8(buffer, '{');
} else if (s->flags & PFLAG_STRING) {
janet_buffer_push_u8(buffer, '"');
} else if (s->flags & PFLAG_LONGSTRING) {
int32_t i;
for (i = 0; i < s->argn; i++) {
janet_buffer_push_u8(buffer, '`');
}
}
janet_formatb(buffer, " opened at line %d, column %d", s->line, s->column);
parser->error = (const char *) janet_string(buffer->data, buffer->count);
parser->flag |= JANET_PARSER_GENERATED_ERROR;
delim_error(parser, parser->statecount - 1, 0, "unexpected end of source");
}
parser->line = oldline;
parser->column = oldcolumn;
@ -693,6 +757,20 @@ const char *janet_parser_error(JanetParser *parser) {
}
Janet janet_parser_produce(JanetParser *parser) {
Janet ret;
size_t i;
if (parser->pending == 0) return janet_wrap_nil();
ret = janet_unwrap_tuple(parser->args[0])[0];
for (i = 1; i < parser->argcount; i++) {
parser->args[i - 1] = parser->args[i];
}
parser->pending--;
parser->argcount--;
parser->states[0].argn--;
return ret;
}
Janet janet_parser_produce_wrapped(JanetParser *parser) {
Janet ret;
size_t i;
if (parser->pending == 0) return janet_wrap_nil();
@ -702,6 +780,7 @@ Janet janet_parser_produce(JanetParser *parser) {
}
parser->pending--;
parser->argcount--;
parser->states[0].argn--;
return ret;
}
@ -726,9 +805,9 @@ void janet_parser_init(JanetParser *parser) {
}
void janet_parser_deinit(JanetParser *parser) {
free(parser->args);
free(parser->buf);
free(parser->states);
janet_free(parser->args);
janet_free(parser->buf);
janet_free(parser->states);
}
void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
@ -755,17 +834,17 @@ void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
dest->states = NULL;
dest->buf = NULL;
if (dest->bufcap) {
dest->buf = malloc(dest->bufcap);
dest->buf = janet_malloc(dest->bufcap);
if (!dest->buf) goto nomem;
memcpy(dest->buf, src->buf, dest->bufcap);
}
if (dest->argcap) {
dest->args = malloc(sizeof(Janet) * dest->argcap);
dest->args = janet_malloc(sizeof(Janet) * dest->argcap);
if (!dest->args) goto nomem;
memcpy(dest->args, src->args, dest->argcap * sizeof(Janet));
}
if (dest->statecap) {
dest->states = malloc(sizeof(JanetParseState) * dest->statecap);
dest->states = janet_malloc(sizeof(JanetParseState) * dest->statecap);
if (!dest->states) goto nomem;
memcpy(dest->states, src->states, dest->statecap * sizeof(JanetParseState));
}
@ -803,17 +882,28 @@ static int parsergc(void *p, size_t size) {
}
static int parserget(void *p, Janet key, Janet *out);
static Janet parsernext(void *p, Janet key);
const JanetAbstractType janet_parser_type = {
"core/parser",
parsergc,
parsermark,
parserget,
JANET_ATEND_GET
NULL, /* put */
NULL, /* marshal */
NULL, /* unmarshal */
NULL, /* tostring */
NULL, /* compare */
NULL, /* hash */
parsernext,
JANET_ATEND_NEXT
};
/* C Function parser */
static Janet cfun_parse_parser(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_parser,
"(parser/new)",
"Creates and returns a new parser object. Parsers are state machines "
"that can receive bytes and generate a stream of values.") {
(void) argv;
janet_fixarity(argc, 0);
JanetParser *p = janet_abstract(&janet_parser_type, sizeof(JanetParser));
@ -821,7 +911,11 @@ static Janet cfun_parse_parser(int32_t argc, Janet *argv) {
return janet_wrap_abstract(p);
}
static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_consume,
"(parser/consume parser bytes &opt index)",
"Input bytes into the parser and parse them. Will not throw errors "
"if there is a parse error. Starts at the byte index given by `index`. Returns "
"the number of bytes read.") {
janet_arity(argc, 2, 3);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
JanetByteView view = janet_getbytes(argv, 1);
@ -846,14 +940,20 @@ static Janet cfun_parse_consume(int32_t argc, Janet *argv) {
return janet_wrap_integer(i);
}
static Janet cfun_parse_eof(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_eof,
"(parser/eof parser)",
"Indicate to the parser that the end of file was reached. This puts the parser in the :dead state.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
janet_parser_eof(p);
return argv[0];
}
static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_insert,
"(parser/insert parser value)",
"Insert a value into the parser. This means that the parser state can be manipulated "
"in between chunks of bytes. This would allow a user to add extra elements to arrays "
"and tuples, for example. Returns the parser.") {
janet_fixarity(argc, 2);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
JanetParseState *s = p->states + p->statecount - 1;
@ -865,15 +965,20 @@ static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
if (s->flags & PFLAG_COMMENT) s--;
if (s->flags & PFLAG_CONTAINER) {
s->argn++;
if (p->statecount == 1) p->pending++;
push_arg(p, argv[1]);
if (p->statecount == 1) {
p->pending++;
Janet tup = janet_wrap_tuple(janet_tuple_n(argv + 1, 1));
push_arg(p, tup);
} else {
push_arg(p, argv[1]);
}
} else if (s->flags & (PFLAG_STRING | PFLAG_LONGSTRING)) {
const uint8_t *str = janet_to_string(argv[1]);
int32_t slen = janet_string_length(str);
size_t newcount = p->bufcount + slen;
if (p->bufcap < newcount) {
size_t newcap = 2 * newcount;
p->buf = realloc(p->buf, newcap);
p->buf = janet_realloc(p->buf, newcap);
if (p->buf == NULL) {
JANET_OUT_OF_MEMORY;
}
@ -887,13 +992,17 @@ static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_parse_has_more(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_has_more,
"(parser/has-more parser)",
"Check if the parser has more values in the value queue.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
return janet_wrap_boolean(janet_parser_has_more(p));
}
static Janet cfun_parse_byte(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_byte,
"(parser/byte parser b)",
"Input a single byte `b` into the parser byte stream. Returns the parser.") {
janet_fixarity(argc, 2);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
int32_t i = janet_getinteger(argv, 1);
@ -901,7 +1010,13 @@ static Janet cfun_parse_byte(int32_t argc, Janet *argv) {
return argv[0];
}
static Janet cfun_parse_status(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_status,
"(parser/status parser)",
"Gets the current status of the parser state machine. The status will "
"be one of:\n\n"
"* :pending - a value is being parsed.\n\n"
"* :error - a parsing error was encountered.\n\n"
"* :root - the parser can either read more values or safely terminate.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
const char *stat = NULL;
@ -922,7 +1037,12 @@ static Janet cfun_parse_status(int32_t argc, Janet *argv) {
return janet_ckeywordv(stat);
}
static Janet cfun_parse_error(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_error,
"(parser/error parser)",
"If the parser is in the error state, returns the message associated with "
"that error. Otherwise, returns nil. Also flushes the parser state and parser "
"queue, so be sure to handle everything in the queue before calling "
"`parser/error`.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
const char *err = janet_parser_error(p);
@ -934,22 +1054,52 @@ static Janet cfun_parse_error(int32_t argc, Janet *argv) {
return janet_wrap_nil();
}
static Janet cfun_parse_produce(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JANET_CORE_FN(cfun_parse_produce,
"(parser/produce parser &opt wrap)",
"Dequeue the next value in the parse queue. Will return nil if "
"no parsed values are in the queue, otherwise will dequeue the "
"next value. If `wrap` is truthy, will return a 1-element tuple that "
"wraps the result. This tuple can be used for source-mapping "
"purposes.") {
janet_arity(argc, 1, 2);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
return janet_parser_produce(p);
if (argc == 2 && janet_truthy(argv[1])) {
return janet_parser_produce_wrapped(p);
} else {
return janet_parser_produce(p);
}
}
static Janet cfun_parse_flush(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_flush,
"(parser/flush parser)",
"Clears the parser state and parse queue. Can be used to reset the parser "
"if an error was encountered. Does not reset the line and column counter, so "
"to begin parsing in a new context, create a new parser.") {
janet_fixarity(argc, 1);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
janet_parser_flush(p);
return argv[0];
}
static Janet cfun_parse_where(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JANET_CORE_FN(cfun_parse_where,
"(parser/where parser &opt line col)",
"Returns the current line number and column of the parser's internal state. If line is "
"provided, the current line number of the parser is first set to that value. If column is "
"also provided, the current column number of the parser is also first set to that value.") {
janet_arity(argc, 1, 3);
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
if (argc > 1) {
int32_t line = janet_getinteger(argv, 1);
if (line < 1)
janet_panicf("invalid line number %d", line);
p->line = (size_t) line;
}
if (argc > 2) {
int32_t column = janet_getinteger(argv, 2);
if (column < 0)
janet_panicf("invalid column number %d", column);
p->column = (size_t) column;
}
Janet *tup = janet_tuple_begin(2);
tup[0] = janet_wrap_integer(p->line);
tup[1] = janet_wrap_integer(p->column);
@ -965,8 +1115,9 @@ static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args,
if (s->flags & PFLAG_CONTAINER) {
JanetArray *container_args = janet_array(s->argn);
container_args->count = s->argn;
safe_memcpy(container_args->data, args, sizeof(args[0])*s->argn);
for (int32_t i = 0; i < s->argn; i++) {
janet_array_push(container_args, args[i]);
}
janet_table_put(state, janet_ckeywordv("args"),
janet_wrap_array(container_args));
}
@ -1051,7 +1202,8 @@ static Janet parser_state_delimiters(const JanetParser *_p) {
}
}
}
str = janet_string(p->buf + oldcount, (int32_t)(p->bufcount - oldcount));
/* avoid ptr arithmetic on NULL */
str = janet_string(oldcount ? p->buf + oldcount : p->buf, (int32_t)(p->bufcount - oldcount));
p->bufcount = oldcount;
return janet_wrap_string(str);
}
@ -1061,11 +1213,15 @@ static Janet parser_state_frames(const JanetParser *p) {
JanetArray *states = janet_array(count);
states->count = count;
uint8_t *buf = p->buf;
Janet *args = p->args;
/* Iterate arg stack backwards */
Janet *args = p->argcount ? p->args + p->argcount : p->args; /* avoid ptr arithmetic on NULL */
for (int32_t i = count - 1; i >= 0; --i) {
JanetParseState *s = p->states + i;
/* avoid ptr arithmetic on args if NULL */
if ((s->flags & PFLAG_CONTAINER) && s->argn) {
args -= s->argn;
}
states->data[i] = janet_wrap_parse_state(s, args, buf, (uint32_t) p->bufcount);
args -= s->argn;
}
return janet_wrap_array(states);
}
@ -1076,7 +1232,16 @@ static const struct ParserStateGetter parser_state_getters[] = {
{NULL, NULL}
};
static Janet cfun_parse_state(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_state,
"(parser/state parser &opt key)",
"Returns a representation of the internal state of the parser. If a key is passed, "
"only that information about the state is returned. Allowed keys are:\n\n"
"* :delimiters - Each byte in the string represents a nested data structure. For example, "
"if the parser state is '([\"', then the parser is in the middle of parsing a "
"string inside of square brackets inside parentheses. Can be used to augment a REPL prompt.\n\n"
"* :frames - Each table in the array represents a 'frame' in the parser state. Frames "
"contain information about the start of the expression being parsed as well as the "
"type of that expression and some type-specific information.") {
janet_arity(argc, 1, 2);
const uint8_t *key = NULL;
JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
@ -1104,7 +1269,11 @@ static Janet cfun_parse_state(int32_t argc, Janet *argv) {
}
}
static Janet cfun_parse_clone(int32_t argc, Janet *argv) {
JANET_CORE_FN(cfun_parse_clone,
"(parser/clone p)",
"Creates a deep clone of a parser that is identical to the input parser. "
"This cloned parser can be used to continue parsing from a good checkpoint "
"if parsing later fails. Returns a new parser.") {
janet_fixarity(argc, 1);
JanetParser *src = janet_getabstract(argv, 0, &janet_parser_type);
JanetParser *dest = janet_abstract(&janet_parser_type, sizeof(JanetParser));
@ -1134,101 +1303,28 @@ static int parserget(void *p, Janet key, Janet *out) {
return janet_getmethod(janet_unwrap_keyword(key), parser_methods, out);
}
static const JanetReg parse_cfuns[] = {
{
"parser/new", cfun_parse_parser,
JDOC("(parser/new)\n\n"
"Creates and returns a new parser object. Parsers are state machines "
"that can receive bytes, and generate a stream of values.")
},
{
"parser/clone", cfun_parse_clone,
JDOC("(parser/clone p)\n\n"
"Creates a deep clone of a parser that is identical to the input parser. "
"This cloned parser can be used to continue parsing from a good checkpoint "
"if parsing later fails. Returns a new parser.")
},
{
"parser/has-more", cfun_parse_has_more,
JDOC("(parser/has-more parser)\n\n"
"Check if the parser has more values in the value queue.")
},
{
"parser/produce", cfun_parse_produce,
JDOC("(parser/produce parser)\n\n"
"Dequeue the next value in the parse queue. Will return nil if "
"no parsed values are in the queue, otherwise will dequeue the "
"next value.")
},
{
"parser/consume", cfun_parse_consume,
JDOC("(parser/consume parser bytes &opt index)\n\n"
"Input bytes into the parser and parse them. Will not throw errors "
"if there is a parse error. Starts at the byte index given by index. Returns "
"the number of bytes read.")
},
{
"parser/byte", cfun_parse_byte,
JDOC("(parser/byte parser b)\n\n"
"Input a single byte into the parser byte stream. Returns the parser.")
},
{
"parser/error", cfun_parse_error,
JDOC("(parser/error parser)\n\n"
"If the parser is in the error state, returns the message associated with "
"that error. Otherwise, returns nil. Also flushes the parser state and parser "
"queue, so be sure to handle everything in the queue before calling "
"parser/error.")
},
{
"parser/status", cfun_parse_status,
JDOC("(parser/status parser)\n\n"
"Gets the current status of the parser state machine. The status will "
"be one of:\n\n"
"\t:pending - a value is being parsed.\n"
"\t:error - a parsing error was encountered.\n"
"\t:root - the parser can either read more values or safely terminate.")
},
{
"parser/flush", cfun_parse_flush,
JDOC("(parser/flush parser)\n\n"
"Clears the parser state and parse queue. Can be used to reset the parser "
"if an error was encountered. Does not reset the line and column counter, so "
"to begin parsing in a new context, create a new parser.")
},
{
"parser/state", cfun_parse_state,
JDOC("(parser/state parser &opt key)\n\n"
"Returns a representation of the internal state of the parser. If a key is passed, "
"only that information about the state is returned. Allowed keys are:\n\n"
"\t:delimiters - Each byte in the string represents a nested data structure. For example, "
"if the parser state is '([\"', then the parser is in the middle of parsing a "
"string inside of square brackets inside parentheses. Can be used to augment a REPL prompt."
"\t:frames - Each table in the array represents a 'frame' in the parser state. Frames "
"contain information about the start of the expression being parsed as well as the "
"type of that expression and some type-specific information.")
},
{
"parser/where", cfun_parse_where,
JDOC("(parser/where parser)\n\n"
"Returns the current line number and column of the parser's internal state.")
},
{
"parser/eof", cfun_parse_eof,
JDOC("(parser/eof parser)\n\n"
"Indicate that the end of file was reached to the parser. This puts the parser in the :dead state.")
},
{
"parser/insert", cfun_parse_insert,
JDOC("(parser/insert parser value)\n\n"
"Insert a value into the parser. This means that the parser state can be manipulated "
"in between chunks of bytes. This would allow a user to add extra elements to arrays "
"and tuples, for example. Returns the parser.")
},
{NULL, NULL, NULL}
};
static Janet parsernext(void *p, Janet key) {
(void) p;
return janet_nextmethod(parser_methods, key);
}
/* Load the library */
void janet_lib_parse(JanetTable *env) {
janet_core_cfuns(env, NULL, parse_cfuns);
JanetRegExt parse_cfuns[] = {
JANET_CORE_REG("parser/new", cfun_parse_parser),
JANET_CORE_REG("parser/clone", cfun_parse_clone),
JANET_CORE_REG("parser/has-more", cfun_parse_has_more),
JANET_CORE_REG("parser/produce", cfun_parse_produce),
JANET_CORE_REG("parser/consume", cfun_parse_consume),
JANET_CORE_REG("parser/byte", cfun_parse_byte),
JANET_CORE_REG("parser/error", cfun_parse_error),
JANET_CORE_REG("parser/status", cfun_parse_status),
JANET_CORE_REG("parser/flush", cfun_parse_flush),
JANET_CORE_REG("parser/state", cfun_parse_state),
JANET_CORE_REG("parser/where", cfun_parse_where),
JANET_CORE_REG("parser/eof", cfun_parse_eof),
JANET_CORE_REG("parser/insert", cfun_parse_insert),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, parse_cfuns);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -30,6 +30,8 @@
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include <float.h>
/* Implements a pretty printer for Janet. The pretty printer
* is simple and not that flexible, but fast. */
@ -37,12 +39,23 @@
/* Temporary buffer size */
#define BUFSIZE 64
/* Preprocessor hacks */
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
static void number_to_string_b(JanetBuffer *buffer, double x) {
janet_buffer_ensure(buffer, buffer->count + BUFSIZE, 2);
const char *fmt = (x == floor(x) &&
x <= JANET_INTMAX_DOUBLE &&
x >= JANET_INTMIN_DOUBLE) ? "%.0f" : "%g";
int count = snprintf((char *) buffer->data + buffer->count, BUFSIZE, fmt, x);
x >= JANET_INTMIN_DOUBLE) ? "%.0f" : ("%." STR(DBL_DIG) "g");
int count;
if (x == 0.0) {
/* Prevent printing of '-0' */
count = 1;
buffer->data[buffer->count] = '0';
} else {
count = snprintf((char *) buffer->data + buffer->count, BUFSIZE, fmt, x);
}
buffer->count += count;
}
@ -101,7 +114,7 @@ static void string_description_b(JanetBuffer *buffer, const char *title, void *p
pbuf.p = pointer;
*c++ = '<';
/* Maximum of 32 bytes for abstract type name */
for (i = 0; title[i] && i < 32; ++i)
for (i = 0; i < 32 && title[i]; ++i)
*c++ = ((uint8_t *)title) [i];
*c++ = ' ';
*c++ = '0';
@ -144,6 +157,12 @@ static void janet_escape_string_impl(JanetBuffer *buffer, const uint8_t *str, in
case '\v':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\v", 2);
break;
case '\a':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\a", 2);
break;
case '\b':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\b", 2);
break;
case 27:
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\e", 2);
break;
@ -220,12 +239,14 @@ void janet_to_string_b(JanetBuffer *buffer, Janet x) {
}
return;
case JANET_CFUNCTION: {
Janet check = janet_table_get(janet_vm_registry, x);
if (janet_checktype(check, JANET_SYMBOL)) {
JanetCFunRegistry *reg = janet_registry_get(janet_unwrap_cfunction(x));
if (NULL != reg) {
janet_buffer_push_cstring(buffer, "<cfunction ");
janet_buffer_push_bytes(buffer,
janet_unwrap_symbol(check),
janet_string_length(janet_unwrap_symbol(check)));
if (NULL != reg->name_prefix) {
janet_buffer_push_cstring(buffer, reg->name_prefix);
janet_buffer_push_u8(buffer, '/');
}
janet_buffer_push_cstring(buffer, reg->name);
janet_buffer_push_u8(buffer, '>');
break;
}
@ -234,6 +255,10 @@ void janet_to_string_b(JanetBuffer *buffer, Janet x) {
case JANET_FUNCTION: {
JanetFunction *fun = janet_unwrap_function(x);
JanetFuncDef *def = fun->def;
if (def == NULL) {
janet_buffer_push_cstring(buffer, "<incomplete function>");
break;
}
if (def->name) {
const uint8_t *n = def->name;
janet_buffer_push_cstring(buffer, "<function ");
@ -252,21 +277,13 @@ void janet_to_string_b(JanetBuffer *buffer, Janet x) {
/* See parse.c for full table */
static const uint32_t pp_symchars[8] = {
0x00000000, 0xf7ffec72, 0xc7ffffff, 0x07fffffe,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
static int pp_is_symbol_char(uint8_t c) {
return pp_symchars[c >> 5] & ((uint32_t)1 << (c & 0x1F));
}
/* Check if a symbol or keyword contains no symbol characters */
static int contains_bad_chars(const uint8_t *sym, int issym) {
int32_t len = janet_string_length(sym);
if (len && issym && sym[0] >= '0' && sym[0] <= '9') return 1;
if (!janet_valid_utf8(sym, len)) return 1;
for (int32_t i = 0; i < len; i++) {
if (!pp_is_symbol_char(sym[i])) return 1;
if (!janet_is_symbol_char(sym[i])) return 1;
}
return 0;
}
@ -344,6 +361,9 @@ struct pretty {
int indent;
int flags;
int32_t bufstartlen;
int32_t *keysort_buffer;
int32_t keysort_capacity;
int32_t keysort_start;
JanetTable seen;
};
@ -359,8 +379,10 @@ static int print_jdn_one(struct pretty *S, Janet x, int depth) {
break;
case JANET_NUMBER:
janet_buffer_ensure(S->buffer, S->buffer->count + BUFSIZE, 2);
int count = snprintf((char *) S->buffer->data + S->buffer->count, BUFSIZE, "%.17g", janet_unwrap_number(x));
S->buffer->count += count;
double num = janet_unwrap_number(x);
if (isnan(num)) return 1;
if (isinf(num)) return 1;
janet_buffer_dtostr(S->buffer, num);
break;
case JANET_SYMBOL:
case JANET_KEYWORD:
@ -558,14 +580,31 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
case JANET_STRUCT:
case JANET_TABLE: {
int istable = janet_checktype(x, JANET_TABLE);
janet_buffer_push_cstring(S->buffer, istable ? "@" : "{");
/* For object-like tables, print class name */
if (istable) {
JanetTable *t = janet_unwrap_table(x);
JanetTable *proto = t->proto;
janet_buffer_push_cstring(S->buffer, "@");
if (NULL != proto) {
Janet name = janet_table_get(proto, janet_ckeywordv("name"));
Janet name = janet_table_get(proto, janet_ckeywordv("_name"));
const uint8_t *n;
int32_t len;
if (janet_bytes_view(name, &n, &len)) {
if (S->flags & JANET_PRETTY_COLOR) {
janet_buffer_push_cstring(S->buffer, janet_class_color);
}
janet_buffer_push_bytes(S->buffer, n, len);
if (S->flags & JANET_PRETTY_COLOR) {
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
}
}
}
} else {
JanetStruct st = janet_unwrap_struct(x);
JanetStruct proto = janet_struct_proto(st);
if (NULL != proto) {
Janet name = janet_struct_get(proto, janet_ckeywordv("_name"));
const uint8_t *n;
int32_t len;
if (janet_bytes_view(name, &n, &len)) {
@ -578,8 +617,8 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
}
}
}
janet_buffer_push_cstring(S->buffer, "{");
}
janet_buffer_push_cstring(S->buffer, "{");
S->depth--;
S->indent += 2;
@ -587,31 +626,55 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
janet_buffer_push_cstring(S->buffer, "...");
} else {
int32_t i = 0, len = 0, cap = 0;
int first_kv_pair = 1;
const JanetKV *kvs = NULL;
int counter = 0;
janet_dictionary_view(x, &kvs, &len, &cap);
if (!istable && !(S->flags & JANET_PRETTY_ONELINE) && len >= JANET_PRETTY_DICT_ONELINE)
janet_buffer_push_u8(S->buffer, ' ');
if (is_dict_value && len >= JANET_PRETTY_DICT_ONELINE) print_newline(S, 0);
for (i = 0; i < cap; i++) {
if (!janet_checktype(kvs[i].key, JANET_NIL)) {
if (counter == JANET_PRETTY_DICT_LIMIT && !(S->flags & JANET_PRETTY_NOTRUNC)) {
print_newline(S, 0);
janet_buffer_push_cstring(S->buffer, "...");
break;
}
if (first_kv_pair) {
first_kv_pair = 0;
} else {
print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
}
janet_pretty_one(S, kvs[i].key, 0);
janet_buffer_push_u8(S->buffer, ' ');
janet_pretty_one(S, kvs[i].value, 1);
counter++;
int32_t ks_start = S->keysort_start;
/* Ensure buffer is large enough to sort keys. */
int truncated = 0;
int64_t mincap = (int64_t) len + (int64_t) ks_start;
if (mincap > INT32_MAX) {
truncated = 1;
len = 0;
mincap = ks_start;
}
if (S->keysort_capacity < mincap) {
if (mincap >= INT32_MAX / 2) {
S->keysort_capacity = INT32_MAX;
} else {
S->keysort_capacity = (int32_t)(mincap * 2);
}
S->keysort_buffer = janet_srealloc(S->keysort_buffer, sizeof(int32_t) * S->keysort_capacity);
if (NULL == S->keysort_buffer) {
JANET_OUT_OF_MEMORY;
}
}
janet_sorted_keys(kvs, cap, S->keysort_buffer == NULL ? NULL : S->keysort_buffer + ks_start);
S->keysort_start += len;
if (!(S->flags & JANET_PRETTY_NOTRUNC) && (len > JANET_PRETTY_DICT_LIMIT)) {
len = JANET_PRETTY_DICT_LIMIT;
truncated = 1;
}
for (i = 0; i < len; i++) {
if (i) print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
int32_t j = S->keysort_buffer[i + ks_start];
janet_pretty_one(S, kvs[j].key, 0);
janet_buffer_push_u8(S->buffer, ' ');
janet_pretty_one(S, kvs[j].value, 1);
}
if (truncated) {
print_newline(S, 0);
janet_buffer_push_cstring(S->buffer, "...");
}
S->keysort_start = ks_start;
}
S->indent -= 2;
S->depth++;
@ -634,6 +697,9 @@ static JanetBuffer *janet_pretty_(JanetBuffer *buffer, int depth, int flags, Jan
S.indent = 0;
S.flags = flags;
S.bufstartlen = startlen;
S.keysort_capacity = 0;
S.keysort_buffer = NULL;
S.keysort_start = 0;
janet_table_init(&S.seen, 10);
janet_pretty_one(&S, x, 0);
janet_table_deinit(&S.seen);
@ -656,6 +722,9 @@ static JanetBuffer *janet_jdn_(JanetBuffer *buffer, int depth, Janet x, int32_t
S.indent = 0;
S.flags = 0;
S.bufstartlen = startlen;
S.keysort_capacity = 0;
S.keysort_buffer = NULL;
S.keysort_start = 0;
janet_table_init(&S.seen, 10);
int res = print_jdn_one(&S, x, depth);
janet_table_deinit(&S.seen);
@ -684,7 +753,7 @@ static void pushtypes(JanetBuffer *buffer, int types) {
if (first) {
first = 0;
} else {
janet_buffer_push_u8(buffer, '|');
janet_buffer_push_cstring(buffer, (types == 1) ? " or " : ", ");
}
janet_buffer_push_cstring(buffer, janet_type_names[i]);
}
@ -699,20 +768,48 @@ static void pushtypes(JanetBuffer *buffer, int types) {
#define MAX_ITEM 256
#define FMT_FLAGS "-+ #0"
#define FMT_REPLACE_INTTYPES "diouxX"
#define MAX_FORMAT 32
struct FmtMapping {
char c;
const char *mapping;
};
/* Janet uses fixed width integer types for most things, so map
* format specifiers to these fixed sizes */
static const struct FmtMapping format_mappings[] = {
{'D', PRId64},
{'I', PRIi64},
{'d', PRId64},
{'i', PRIi64},
{'o', PRIo64},
{'u', PRIu64},
{'x', PRIx64},
{'X', PRIX64},
};
static const char *get_fmt_mapping(char c) {
for (size_t i = 0; i < (sizeof(format_mappings) / sizeof(struct FmtMapping)); i++) {
if (format_mappings[i].c == c)
return format_mappings[i].mapping;
}
janet_assert(0, "bad format mapping");
}
static const char *scanformat(
const char *strfrmt,
char *form,
char width[3],
char precision[3]) {
const char *p = strfrmt;
/* Parse strfrmt */
memset(width, '\0', 3);
memset(precision, '\0', 3);
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL)
p++; /* skip flags */
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS) / sizeof(char))
janet_panic("invalid format (repeated flags)");
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS)) janet_panic("invalid format (repeated flags)");
if (isdigit((int)(*p)))
width[0] = *p++; /* skip width */
if (isdigit((int)(*p)))
@ -726,10 +823,23 @@ static const char *scanformat(
}
if (isdigit((int)(*p)))
janet_panic("invalid format (width or precision too long)");
/* Write to form - replace characters with fixed size stuff */
*(form++) = '%';
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
form += (p - strfrmt) + 1;
const char *p2 = strfrmt;
while (p2 <= p) {
char *loc = strchr(FMT_REPLACE_INTTYPES, *p2);
if (loc != NULL && *loc != '\0') {
const char *mapping = get_fmt_mapping(*p2++);
size_t len = strlen(mapping);
memcpy(form, mapping, len);
form += len;
} else {
*(form++) = *(p2++);
}
}
*form = '\0';
return p;
}
@ -749,16 +859,27 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
c = scanformat(c, form, width, precision);
switch (*c++) {
case 'c': {
int n = va_arg(args, long);
int n = va_arg(args, int);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
case 'd':
case 'i':
case 'o':
case 'i': {
int64_t n = (int64_t) va_arg(args, int32_t);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
case 'D':
case 'I': {
int64_t n = va_arg(args, int64_t);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
case 'x':
case 'X': {
int32_t n = va_arg(args, long);
case 'X':
case 'o':
case 'u': {
uint64_t n = va_arg(args, uint64_t);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
@ -802,7 +923,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
janet_buffer_push_cstring(b, typestr(va_arg(args, Janet)));
break;
case 'T': {
int types = va_arg(args, long);
int types = va_arg(args, int);
pushtypes(b, types);
break;
}
@ -815,7 +936,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
case 'P':
case 'p': { /* janet pretty , precision = depth */
int depth = atoi(precision);
if (depth < 1) depth = 4;
if (depth < 1) depth = JANET_RECURSION_GUARD;
char d = c[-1];
int has_color = (d == 'P') || (d == 'Q') || (d == 'M') || (d == 'N');
int has_oneline = (d == 'Q') || (d == 'q') || (d == 'N') || (d == 'n');
@ -841,7 +962,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
}
}
if (nb >= MAX_ITEM)
janet_panicf("format buffer overflow", form);
janet_panic("format buffer overflow");
if (nb > 0)
janet_buffer_push_bytes(b, (uint8_t *) item, nb);
}
@ -911,12 +1032,19 @@ void janet_buffer_format(
janet_getinteger(argv, arg));
break;
}
case 'D':
case 'I':
case 'd':
case 'i':
case 'o':
case 'i': {
int64_t n = janet_getinteger64(argv, arg);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
case 'x':
case 'X': {
int32_t n = janet_getinteger(argv, arg);
case 'X':
case 'o':
case 'u': {
uint64_t n = janet_getuinteger64(argv, arg);
nb = snprintf(item, MAX_ITEM, form, n);
break;
}
@ -932,8 +1060,9 @@ void janet_buffer_format(
break;
}
case 's': {
const uint8_t *s = janet_getstring(argv, arg);
int32_t l = janet_string_length(s);
JanetByteView bytes = janet_getbytes(argv, arg);
const uint8_t *s = bytes.bytes;
int32_t l = bytes.len;
if (form[2] == '\0')
janet_buffer_push_bytes(b, s, l);
else {
@ -967,7 +1096,7 @@ void janet_buffer_format(
case 'P':
case 'p': { /* janet pretty , precision = depth */
int depth = atoi(precision);
if (depth < 1) depth = 4;
if (depth < 1) depth = JANET_RECURSION_GUARD;
char d = strfrmt[-1];
int has_color = (d == 'P') || (d == 'Q') || (d == 'M') || (d == 'N');
int has_oneline = (d == 'Q') || (d == 'q') || (d == 'N') || (d == 'n');
@ -993,7 +1122,7 @@ void janet_buffer_format(
}
}
if (nb >= MAX_ITEM)
janet_panicf("format buffer overflow", form);
janet_panic("format buffer overflow");
if (nb > 0)
janet_buffer_push_bytes(b, (uint8_t *) item, nb);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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,6 +27,8 @@
#include "util.h"
#endif
/* The JanetRegisterAllocator is really just a bitset. */
void janetc_regalloc_init(JanetcRegisterAllocator *ra) {
ra->chunks = NULL;
ra->count = 0;
@ -36,7 +38,7 @@ void janetc_regalloc_init(JanetcRegisterAllocator *ra) {
}
void janetc_regalloc_deinit(JanetcRegisterAllocator *ra) {
free(ra->chunks);
janet_free(ra->chunks);
}
/* Fallbacks for when ctz not available */
@ -70,7 +72,7 @@ void janetc_regalloc_clone(JanetcRegisterAllocator *dest, JanetcRegisterAllocato
size = sizeof(uint32_t) * (size_t) dest->capacity;
dest->regtemps = 0;
if (size) {
dest->chunks = malloc(size);
dest->chunks = janet_malloc(size);
if (!dest->chunks) {
JANET_OUT_OF_MEMORY;
}
@ -87,7 +89,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, (size_t) newcapacity * sizeof(uint32_t));
ra->chunks = janet_realloc(ra->chunks, (size_t) newcapacity * sizeof(uint32_t));
if (!ra->chunks) {
JANET_OUT_OF_MEMORY;
}
@ -139,6 +141,14 @@ void janetc_regalloc_free(JanetcRegisterAllocator *ra, int32_t reg) {
ra->chunks[chunk] &= ~ithbit(bit);
}
/* Check if a register is set. */
int janetc_regalloc_check(JanetcRegisterAllocator *ra, int32_t reg) {
int32_t chunk = reg >> 5;
int32_t bit = reg & 0x1F;
while (chunk >= ra->count) pushchunk(ra);
return !!(ra->chunks[chunk] & ithbit(bit));
}
/* Get a register that will fit in 8 bits (< 256). Do not call this
* twice with the same value of nth without calling janetc_regalloc_free
* on the returned register before. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -56,5 +56,6 @@ int32_t janetc_regalloc_temp(JanetcRegisterAllocator *ra, JanetcRegisterTemp nth
void janetc_regalloc_freetemp(JanetcRegisterAllocator *ra, int32_t reg, JanetcRegisterTemp nth);
void janetc_regalloc_clone(JanetcRegisterAllocator *dest, JanetcRegisterAllocator *src);
void janetc_regalloc_touch(JanetcRegisterAllocator *ra, int32_t reg);
int janetc_regalloc_check(JanetcRegisterAllocator *ra, int32_t reg);
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -23,6 +23,7 @@
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "state.h"
#endif
/* Run a string */
@ -31,6 +32,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
int errflags = 0, done = 0;
int32_t index = 0;
Janet ret = janet_wrap_nil();
JanetFiber *fiber = NULL;
const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
if (where) janet_gcroot(janet_wrap_string(where));
@ -46,22 +48,30 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
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 = 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);
janet_stacktrace_ext(fiber, ret, "");
errflags |= 0x01;
done = 1;
}
} else {
ret = janet_wrap_string(cres.error);
int32_t line = (int32_t) parser.line;
int32_t col = (int32_t) parser.column;
if ((cres.error_mapping.line > 0) &&
(cres.error_mapping.column > 0)) {
line = cres.error_mapping.line;
col = cres.error_mapping.column;
}
if (cres.macrofiber) {
janet_eprintf("compile error in %s: ", sourcePath);
janet_stacktrace(cres.macrofiber, ret);
janet_eprintf("%s:%d:%d: compile error", sourcePath,
line, col);
janet_stacktrace_ext(cres.macrofiber, ret, "");
} else {
janet_eprintf("compile error in %s: %s\n", sourcePath,
(const char *)cres.error);
janet_eprintf("%s:%d:%d: compile error: %s\n", sourcePath,
line, col, (const char *)cres.error);
}
errflags |= 0x02;
done = 1;
@ -79,7 +89,9 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
const char *e = janet_parser_error(&parser);
errflags |= 0x04;
ret = janet_cstringv(e);
janet_eprintf("parse error in %s: %s\n", sourcePath, e);
int32_t line = (int32_t) parser.line;
int32_t col = (int32_t) parser.column;
janet_eprintf("%s:%d:%d: parse error: %s\n", sourcePath, line, col, e);
done = 1;
break;
}
@ -98,6 +110,19 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
/* Clean up and return errors */
janet_parser_deinit(&parser);
if (where) janet_gcunroot(janet_wrap_string(where));
#ifdef JANET_EV
/* Enter the event loop if we are not already in it */
if (janet_vm.stackn == 0) {
if (fiber) {
janet_gcroot(janet_wrap_fiber(fiber));
}
janet_loop();
if (fiber) {
janet_gcunroot(janet_wrap_fiber(fiber));
ret = fiber->last_value;
}
}
#endif
if (out) *out = ret;
return errflags;
}
@ -108,3 +133,19 @@ int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Jan
return janet_dobytes(env, (const uint8_t *)str, len, sourcePath, out);
}
/* Run a fiber to completion (use event loop if enabled). Return the status. */
int janet_loop_fiber(JanetFiber *fiber) {
int status;
#ifdef JANET_EV
janet_schedule(fiber, janet_wrap_nil());
janet_loop();
status = janet_fiber_status(fiber);
#else
Janet out;
status = janet_continue(fiber, janet_wrap_nil(), &out);
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
janet_stacktrace_ext(fiber, out, "");
}
#endif
return status;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2023 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
@ -31,7 +31,7 @@
static JanetSlot janetc_quote(JanetFopts opts, int32_t argn, const Janet *argv) {
if (argn != 1) {
janetc_cerror(opts.compiler, "expected 1 argument");
janetc_cerror(opts.compiler, "expected 1 argument to quote");
return janetc_cslot(janet_wrap_nil());
}
return janetc_cslot(argv[0]);
@ -39,8 +39,12 @@ static JanetSlot janetc_quote(JanetFopts opts, int32_t argn, const Janet *argv)
static JanetSlot janetc_splice(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetSlot ret;
if (!(opts.flags & JANET_FOPTS_ACCEPT_SPLICE)) {
janetc_cerror(opts.compiler, "splice can only be used in function parameters and data constructors, it has no effect here");
return janetc_cslot(janet_wrap_nil());
}
if (argn != 1) {
janetc_cerror(opts.compiler, "expected 1 argument");
janetc_cerror(opts.compiler, "expected 1 argument to splice");
return janetc_cslot(janet_wrap_nil());
}
ret = janetc_value(opts, argv[0]);
@ -62,6 +66,8 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
return janetc_cslot(janet_wrap_nil());
}
JanetSlot *slots = NULL;
JanetFopts subopts = opts;
subopts.flags &= ~JANET_FOPTS_HINT;
switch (janet_type(x)) {
default:
return janetc_cslot(x);
@ -73,7 +79,9 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
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]);
JanetFopts subopts = janetc_fopts_default(opts.compiler);
subopts.flags |= JANET_FOPTS_ACCEPT_SPLICE;
return janetc_value(subopts, tup[1]);
} else {
level--;
}
@ -82,7 +90,7 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
}
}
for (i = 0; i < len; i++)
janet_v_push(slots, quasiquote(opts, tup[i], depth - 1, level));
janet_v_push(slots, quasiquote(subopts, tup[i], depth - 1, level));
return qq_slots(opts, slots, (janet_tuple_flag(tup) & JANET_TUPLE_FLAG_BRACKETCTOR)
? JOP_MAKE_BRACKET_TUPLE
: JOP_MAKE_TUPLE);
@ -91,7 +99,7 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
int32_t i;
JanetArray *array = janet_unwrap_array(x);
for (i = 0; i < array->count; i++)
janet_v_push(slots, quasiquote(opts, array->data[i], depth - 1, level));
janet_v_push(slots, quasiquote(subopts, array->data[i], depth - 1, level));
return qq_slots(opts, slots, JOP_MAKE_ARRAY);
}
case JANET_TABLE:
@ -100,8 +108,8 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
int32_t len, cap = 0;
janet_dictionary_view(x, &kvs, &len, &cap);
while ((kv = janet_dictionary_next(kvs, cap, kv))) {
JanetSlot key = quasiquote(opts, kv->key, depth - 1, level);
JanetSlot value = quasiquote(opts, kv->value, depth - 1, level);
JanetSlot key = quasiquote(subopts, kv->key, depth - 1, level);
JanetSlot value = quasiquote(subopts, kv->value, depth - 1, level);
key.flags &= ~JANET_SLOT_SPLICED;
value.flags &= ~JANET_SLOT_SPLICED;
janet_v_push(slots, key);
@ -115,7 +123,7 @@ static JanetSlot quasiquote(JanetFopts opts, Janet x, int depth, int level) {
static JanetSlot janetc_quasiquote(JanetFopts opts, int32_t argn, const Janet *argv) {
if (argn != 1) {
janetc_cerror(opts.compiler, "expected 1 argument");
janetc_cerror(opts.compiler, "expected 1 argument to quasiquote");
return janetc_cslot(janet_wrap_nil());
}
return quasiquote(opts, argv[0], JANET_RECURSION_GUARD, 0);
@ -141,7 +149,7 @@ static int destructure(JanetCompiler *c,
JanetTable *attr) {
switch (janet_type(left)) {
default:
janetc_cerror(c, "unexpected type in destructuring");
janetc_error(c, janet_formatc("unexpected type in destructuring, got %v", left));
return 1;
case JANET_SYMBOL:
/* Leaf, assign right to left */
@ -154,6 +162,67 @@ static int destructure(JanetCompiler *c,
for (int32_t i = 0; i < len; i++) {
JanetSlot nextright = janetc_farslot(c);
Janet subval = values[i];
if (janet_checktype(subval, JANET_SYMBOL) && !janet_cstrcmp(janet_unwrap_symbol(subval), "&")) {
if (i + 1 >= len) {
janetc_cerror(c, "expected symbol following '& in destructuring pattern");
return 1;
}
if (i + 2 < len) {
int32_t num_extra = len - i - 1;
Janet *extra = janet_tuple_begin(num_extra);
janet_tuple_flag(extra) |= JANET_TUPLE_FLAG_BRACKETCTOR;
for (int32_t j = 0; j < num_extra; ++j) {
extra[j] = values[j + i + 1];
}
janetc_error(c, janet_formatc("expected a single symbol follow '& in destructuring pattern, found %q", janet_wrap_tuple(janet_tuple_end(extra))));
return 1;
}
if (!janet_checktype(values[i + 1], JANET_SYMBOL)) {
janetc_error(c, janet_formatc("expected symbol following '& in destructuring pattern, found %q", values[i + 1]));
return 1;
}
JanetSlot argi = janetc_farslot(c);
JanetSlot arg = janetc_farslot(c);
JanetSlot len = janetc_farslot(c);
janetc_emit_si(c, JOP_LOAD_INTEGER, argi, i, 0);
janetc_emit_ss(c, JOP_LENGTH, len, right, 0);
/* loop condition - reuse arg slot for the condition result */
int32_t label_loop_start = janetc_emit_sss(c, JOP_LESS_THAN, arg, argi, len, 0);
int32_t label_loop_cond_jump = janetc_emit_si(c, JOP_JUMP_IF_NOT, arg, 0, 0);
/* loop body */
janetc_emit_sss(c, JOP_GET, arg, right, argi, 0);
janetc_emit_s(c, JOP_PUSH, arg, 0);
janetc_emit_ssi(c, JOP_ADD_IMMEDIATE, argi, argi, 1, 0);
/* loop - jump back to the start of the loop */
int32_t label_loop_loop = janet_v_count(c->buffer);
janetc_emit(c, JOP_JUMP);
int32_t label_loop_exit = janet_v_count(c->buffer);
/* avoid shifting negative numbers */
c->buffer[label_loop_cond_jump] |= (uint32_t)(label_loop_exit - label_loop_cond_jump) << 16;
c->buffer[label_loop_loop] |= (uint32_t)(label_loop_start - label_loop_loop) << 8;
janetc_freeslot(c, argi);
janetc_freeslot(c, arg);
janetc_freeslot(c, len);
janetc_emit_s(c, JOP_MAKE_TUPLE, nextright, 1);
leaf(c, janet_unwrap_symbol(values[i + 1]), nextright, attr);
janetc_freeslot(c, nextright);
break;
}
if (i < 0x100) {
janetc_emit_ssu(c, JOP_GET_INDEX, nextright, right, (uint8_t) i, 1);
} else {
@ -194,7 +263,7 @@ static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv) {
if (argn != 2) {
janetc_cerror(opts.compiler, "expected 2 arguments");
janetc_cerror(opts.compiler, "expected 2 arguments to set");
return janetc_cslot(janet_wrap_nil());
}
JanetFopts subopts = janetc_fopts_default(opts.compiler);
@ -236,14 +305,24 @@ static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv)
}
/* Add attributes to a global def or var table */
static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv) {
static JanetTable *handleattr(JanetCompiler *c, const char *kind, int32_t argn, const Janet *argv) {
int32_t i;
JanetTable *tab = janet_table(2);
const char *binding_name = janet_type(argv[0]) == JANET_SYMBOL
? ((const char *)janet_unwrap_symbol(argv[0]))
: "<multiple bindings>";
if (argn < 2) {
janetc_error(c, janet_formatc("expected at least 2 arguments to %s", kind));
return NULL;
}
for (i = 1; i < argn - 1; i++) {
Janet attr = argv[i];
switch (janet_type(attr)) {
case JANET_TUPLE:
janetc_cerror(c, "unexpected form - did you intend to use defn?");
break;
default:
janetc_cerror(c, "could not add metadata to binding");
janetc_error(c, janet_formatc("cannot add metadata %v to binding %s", attr, binding_name));
break;
case JANET_KEYWORD:
janet_table_put(tab, attr, janet_wrap_true());
@ -251,23 +330,60 @@ static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv)
case JANET_STRING:
janet_table_put(tab, janet_ckeywordv("doc"), attr);
break;
case JANET_STRUCT:
janet_table_merge_struct(tab, janet_unwrap_struct(attr));
break;
}
}
return tab;
}
static JanetSlot dohead(JanetCompiler *c, JanetFopts opts, Janet *head, int32_t argn, const Janet *argv) {
typedef struct SlotHeadPair {
Janet lhs;
JanetSlot rhs;
} SlotHeadPair;
SlotHeadPair *dohead_destructure(JanetCompiler *c, SlotHeadPair *into, JanetFopts opts, Janet lhs, Janet rhs) {
/* Detect if we can do an optimization to avoid some allocations */
int can_destructure_lhs = janet_checktype(lhs, JANET_TUPLE)
|| janet_checktype(lhs, JANET_ARRAY);
int rhs_is_indexed = janet_checktype(rhs, JANET_ARRAY)
|| (janet_checktype(rhs, JANET_TUPLE) && (janet_tuple_flag(janet_unwrap_tuple(rhs)) & JANET_TUPLE_FLAG_BRACKETCTOR));
uint32_t has_drop = opts.flags & JANET_FOPTS_DROP;
JanetFopts subopts = janetc_fopts_default(c);
JanetSlot ret;
if (argn < 2) {
janetc_cerror(c, "expected at least 2 arguments");
return janetc_cslot(janet_wrap_nil());
}
*head = argv[0];
subopts.flags = opts.flags & ~(JANET_FOPTS_TAIL | JANET_FOPTS_DROP);
if (has_drop && can_destructure_lhs && rhs_is_indexed) {
/* Code is of the form (def [a b] [1 2]), avoid the allocation of two tuples */
JanetView view_lhs = {0};
JanetView view_rhs = {0};
janet_indexed_view(lhs, &view_lhs.items, &view_lhs.len);
janet_indexed_view(rhs, &view_rhs.items, &view_rhs.len);
int found_amp = 0;
for (int32_t i = 0; i < view_lhs.len; i++) {
if (janet_symeq(view_lhs.items[i], "&")) {
found_amp = 1;
/* Good error will be generated later. */
break;
}
}
if (!found_amp) {
for (int32_t i = 0; i < view_lhs.len; i++) {
Janet sub_rhs = view_rhs.len <= i ? janet_wrap_nil() : view_rhs.items[i];
into = dohead_destructure(c, into, subopts, view_lhs.items[i], sub_rhs);
}
return into;
}
}
/* No optimization, do the simple way */
subopts.hint = opts.hint;
ret = janetc_value(subopts, argv[argn - 1]);
return ret;
JanetSlot ret = janetc_value(subopts, rhs);
SlotHeadPair shp = {lhs, ret};
janet_v_push(into, shp);
return into;
}
/* Def or var a symbol in a local scope */
@ -275,7 +391,17 @@ static int namelocal(JanetCompiler *c, const uint8_t *head, int32_t flags, Janet
int isUnnamedRegister = !(ret.flags & JANET_SLOT_NAMED) &&
ret.index > 0 &&
ret.envindex >= 0;
if (!isUnnamedRegister) {
/* optimization for `(def x my-def)` - don't emit a movn/movf instruction, we can just alias my-def */
/* TODO - implement optimization for `(def x my-var)` correctly as well w/ de-aliasing */
int canAlias = !(flags & JANET_SLOT_MUTABLE) &&
!(ret.flags & JANET_SLOT_MUTABLE) &&
(ret.flags & JANET_SLOT_NAMED) &&
(ret.index >= 0) &&
(ret.envindex == -1);
if (canAlias) {
ret.flags &= ~JANET_SLOT_MUTABLE;
isUnnamedRegister = 1; /* don't free slot after use - is an alias for another slot */
} else if (!isUnnamedRegister) {
/* Slot is not able to be named */
JanetSlot localslot = janetc_farslot(c);
janetc_copy(c, localslot, ret);
@ -295,8 +421,20 @@ static int varleaf(
/* Global var, generate var */
JanetSlot refslot;
JanetTable *entry = janet_table_clone(reftab);
JanetArray *ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
Janet redef_kw = janet_ckeywordv("redef");
int is_redef = janet_truthy(janet_table_get(c->env, redef_kw));
JanetArray *ref;
JanetBinding old_binding;
if (is_redef && (old_binding = janet_resolve_ext(c->env, sym),
old_binding.type == JANET_BINDING_VAR)) {
ref = janet_unwrap_array(old_binding.value);
} else {
ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
}
janet_table_put(entry, janet_ckeywordv("ref"), janet_wrap_array(ref));
janet_table_put(entry, janet_ckeywordv("source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
@ -311,11 +449,23 @@ static int varleaf(
static JanetSlot janetc_var(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
Janet head;
JanetSlot ret = dohead(c, opts, &head, argn, argv);
if (c->result.status == JANET_COMPILE_ERROR)
JanetTable *attr_table = handleattr(c, "var", argn, argv);
if (c->result.status == JANET_COMPILE_ERROR) {
return janetc_cslot(janet_wrap_nil());
destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv));
}
SlotHeadPair *into = NULL;
into = dohead_destructure(c, into, opts, argv[0], argv[argn - 1]);
if (c->result.status == JANET_COMPILE_ERROR) {
janet_v_free(into);
return janetc_cslot(janet_wrap_nil());
}
JanetSlot ret;
janet_assert(janet_v_count(into) > 0, "bad destructure");
for (int32_t i = 0; i < janet_v_count(into); i++) {
destructure(c, into[i].lhs, into[i].rhs, varleaf, attr_table);
ret = into[i].rhs;
}
janet_v_free(into);
return ret;
}
@ -328,31 +478,78 @@ static int defleaf(
JanetTable *entry = janet_table_clone(tab);
janet_table_put(entry, janet_ckeywordv("source-map"),
janet_wrap_tuple(janetc_make_sourcemap(c)));
JanetSlot valsym = janetc_cslot(janet_ckeywordv("value"));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(entry));
Janet redef_kw = janet_ckeywordv("redef");
int is_redef = janet_truthy(janet_table_get(c->env, redef_kw));
if (is_redef) janet_table_put(entry, redef_kw, janet_wrap_true());
if (is_redef) {
JanetBinding binding = janet_resolve_ext(c->env, sym);
JanetArray *ref;
if (binding.type == JANET_BINDING_DYNAMIC_DEF || binding.type == JANET_BINDING_DYNAMIC_MACRO) {
ref = janet_unwrap_array(binding.value);
} else {
ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
}
janet_table_put(entry, janet_ckeywordv("ref"), janet_wrap_array(ref));
JanetSlot refslot = janetc_cslot(janet_wrap_array(ref));
janetc_emit_ssu(c, JOP_PUT_INDEX, refslot, s, 0, 0);
} else {
JanetSlot valsym = janetc_cslot(janet_ckeywordv("value"));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(entry));
janetc_emit_sss(c, JOP_PUT, tabslot, valsym, s, 0);
}
/* Add env entry to env */
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(entry));
/* Put value in table when evaulated */
janetc_emit_sss(c, JOP_PUT, tabslot, valsym, s, 0);
return 1;
} else {
return namelocal(c, sym, 0, s);
}
return namelocal(c, sym, 0, s);
}
static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetCompiler *c = opts.compiler;
Janet head;
opts.flags &= ~JANET_FOPTS_HINT;
JanetSlot ret = dohead(c, opts, &head, argn, argv);
if (c->result.status == JANET_COMPILE_ERROR)
JanetTable *attr_table = handleattr(c, "def", argn, argv);
if (c->result.status == JANET_COMPILE_ERROR) {
return janetc_cslot(janet_wrap_nil());
destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv));
}
opts.flags &= ~JANET_FOPTS_HINT;
SlotHeadPair *into = NULL;
into = dohead_destructure(c, into, opts, argv[0], argv[argn - 1]);
if (c->result.status == JANET_COMPILE_ERROR) {
janet_v_free(into);
return janetc_cslot(janet_wrap_nil());
}
JanetSlot ret;
janet_assert(janet_v_count(into) > 0, "bad destructure");
for (int32_t i = 0; i < janet_v_count(into); i++) {
destructure(c, into[i].lhs, into[i].rhs, defleaf, attr_table);
ret = into[i].rhs;
}
janet_v_free(into);
return ret;
}
/* Check if a form matches the pattern (= nil _) or (not= nil _) */
static int janetc_check_nil_form(Janet x, Janet *capture, uint32_t fun_tag) {
if (!janet_checktype(x, JANET_TUPLE)) return 0;
JanetTuple tup = janet_unwrap_tuple(x);
if (3 != janet_tuple_length(tup)) return 0;
Janet op1 = tup[0];
if (!janet_checktype(op1, JANET_FUNCTION)) return 0;
JanetFunction *fun = janet_unwrap_function(op1);
uint32_t tag = fun->def->flags & JANET_FUNCDEF_FLAG_TAG;
if (tag != fun_tag) return 0;
if (janet_checktype(tup[1], JANET_NIL)) {
*capture = tup[2];
return 1;
} else if (janet_checktype(tup[2], JANET_NIL)) {
*capture = tup[1];
return 1;
}
return 0;
}
/*
* :condition
* ...
@ -373,6 +570,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetScope condscope, tempscope;
const int tail = opts.flags & JANET_FOPTS_TAIL;
const int drop = opts.flags & JANET_FOPTS_DROP;
uint8_t ifnjmp = JOP_JUMP_IF_NOT;
if (argn < 2 || argn > 3) {
janetc_cerror(c, "expected 2 or 3 arguments to if");
@ -386,6 +584,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Get options */
condopts = janetc_fopts_default(c);
bodyopts = opts;
bodyopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
/* Set target for compilation */
target = (drop || tail)
@ -394,12 +593,24 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Compile condition */
janetc_scope(&condscope, c, 0, "if");
cond = janetc_value(condopts, argv[0]);
Janet condform = argv[0];
if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
ifnjmp = JOP_JUMP_IF_NOT_NIL;
} else if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
ifnjmp = JOP_JUMP_IF_NIL;
}
cond = janetc_value(condopts, condform);
/* Check constant condition. */
/* TODO: Use type info for more short circuits */
if (cond.flags & JANET_SLOT_CONSTANT) {
if (!janet_truthy(cond.constant)) {
int swap_condition = 0;
if (ifnjmp == JOP_JUMP_IF_NOT && !janet_truthy(cond.constant)) swap_condition = 1;
if (ifnjmp == JOP_JUMP_IF_NIL && janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
if (ifnjmp == JOP_JUMP_IF_NOT_NIL && !janet_checktype(cond.constant, JANET_NIL)) swap_condition = 1;
if (swap_condition) {
/* Swap the true and false bodies */
Janet temp = falsebody;
falsebody = truebody;
@ -409,13 +620,15 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
right = janetc_value(bodyopts, truebody);
if (!drop && !tail) janetc_copy(c, target, right);
janetc_popscope(c);
janetc_throwaway(bodyopts, falsebody);
if (!janet_checktype(falsebody, JANET_NIL)) {
janetc_throwaway(bodyopts, falsebody);
}
janetc_popscope(c);
return target;
}
/* Compile jump to right */
labeljr = janetc_emit_si(c, JOP_JUMP_IF_NOT, cond, 0, 0);
labeljr = janetc_emit_si(c, ifnjmp, cond, 0, 0);
/* Condition left body */
janetc_scope(&tempscope, c, 0, "if-true");
@ -425,7 +638,7 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Compile jump to done */
labeljd = janet_v_count(c->buffer);
if (!tail) janetc_emit(c, JOP_JUMP);
if (!tail && !(drop && janet_checktype(falsebody, JANET_NIL))) janetc_emit(c, JOP_JUMP);
/* Compile right body */
labelr = janet_v_count(c->buffer);
@ -460,6 +673,7 @@ static JanetSlot janetc_do(JanetFopts opts, int32_t argn, const Janet *argv) {
subopts.flags = JANET_FOPTS_DROP;
} else {
subopts = opts;
subopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
}
ret = janetc_value(subopts, argv[i]);
if (i != argn - 1) {
@ -470,6 +684,28 @@ static JanetSlot janetc_do(JanetFopts opts, int32_t argn, const Janet *argv) {
return ret;
}
/* Compile an upscope form. Upscope forms execute their body sequentially and
* evaluate to the last expression in the body, but without lexical scope. */
static JanetSlot janetc_upscope(JanetFopts opts, int32_t argn, const Janet *argv) {
int32_t i;
JanetSlot ret = janetc_cslot(janet_wrap_nil());
JanetCompiler *c = opts.compiler;
JanetFopts subopts = janetc_fopts_default(c);
for (i = 0; i < argn; i++) {
if (i != argn - 1) {
subopts.flags = JANET_FOPTS_DROP;
} else {
subopts = opts;
subopts.flags &= ~JANET_FOPTS_ACCEPT_SPLICE;
}
ret = janetc_value(subopts, argv[i]);
if (i != argn - 1) {
janetc_freeslot(c, ret);
}
}
return ret;
}
/* Add a funcdef to the top most function scope */
static int32_t janetc_addfuncdef(JanetCompiler *c, JanetFuncDef *def) {
JanetScope *scope = c->scope;
@ -513,9 +749,8 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
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;
janetc_value(subopts, argv[0]);
return janetc_cslot(janet_wrap_nil());
} else {
/* while loop IIFE or no argument */
if (argn) {
@ -523,9 +758,7 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
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;
return janetc_cslot(janet_wrap_nil());
}
} else {
if (argn) {
@ -538,20 +771,6 @@ static JanetSlot janetc_break(JanetFopts opts, int32_t argn, const Janet *argv)
}
}
/* 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
* ...
@ -568,12 +787,13 @@ 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_nil_form = 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");
if (argn < 1) {
janetc_cerror(c, "expected at least 1 argument to while");
return janetc_cslot(janet_wrap_nil());
}
@ -581,11 +801,16 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
janetc_scope(&tempscope, c, JANET_SCOPE_WHILE, "while");
/* Check for `(not= nil _)` in condition, and if so, use the
/* Check for `(= nil _)` or `(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)) {
if (janetc_check_nil_form(condform, &condform, JANET_FUN_EQ)) {
is_nil_form = 1;
ifjmp = JOP_JUMP_IF_NIL;
ifnjmp = JOP_JUMP_IF_NOT_NIL;
}
if (janetc_check_nil_form(condform, &condform, JANET_FUN_NEQ)) {
is_notnil_form = 1;
ifjmp = JOP_JUMP_IF_NOT_NIL;
ifnjmp = JOP_JUMP_IF_NIL;
@ -597,7 +822,9 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
/* Check for constant condition */
if (cond.flags & JANET_SLOT_CONSTANT) {
/* Loop never executes */
int never_executes = is_notnil_form
int never_executes = is_nil_form
? !janet_checktype(cond.constant, JANET_NIL)
: is_notnil_form
? janet_checktype(cond.constant, JANET_NIL)
: !janet_truthy(cond.constant);
if (never_executes) {
@ -688,7 +915,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
JanetSlot ret;
Janet head;
JanetScope fnscope;
int32_t paramcount, argi, parami, arity, min_arity, max_arity, defindex, i;
int32_t paramcount, argi, parami, arity, min_arity = 0, max_arity, defindex, i;
JanetFopts subopts = janetc_fopts_default(c);
const Janet *params;
const char *errmsg = NULL;
@ -698,8 +925,10 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
int structarg = 0;
int allow_extra = 0;
int selfref = 0;
int hasname = 0;
int seenamp = 0;
int seenopt = 0;
int namedargs = 0;
/* Begin function */
c->scope->flags |= JANET_SCOPE_CLOSURE;
@ -715,6 +944,10 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
head = argv[0];
if (janet_checktype(head, JANET_SYMBOL)) {
selfref = 1;
hasname = 1;
parami = 1;
} else if (janet_checktype(head, JANET_KEYWORD)) {
hasname = 1;
parami = 1;
}
if (parami >= argn || !janet_checktype(argv[parami], JANET_TUPLE)) {
@ -724,6 +957,9 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
/* Keep track of destructured parameters */
JanetSlot *destructed_params = NULL;
JanetSlot *named_params = NULL;
JanetTable *named_table = NULL;
JanetSlot named_slot;
/* Compile function parameters */
params = janet_unwrap_tuple(argv[parami]);
@ -731,49 +967,75 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
arity = paramcount;
for (i = 0; i < paramcount; i++) {
Janet param = params[i];
if (janet_checktype(param, JANET_SYMBOL)) {
if (namedargs) {
arity--;
if (!janet_checktype(param, JANET_SYMBOL)) {
errmsg = "only named arguments can follow &named";
goto error;
}
Janet key = janet_wrap_keyword(janet_unwrap_symbol(param));
janet_table_put(named_table, key, param);
janet_v_push(named_params, janetc_farslot(c));
} else if (janet_checktype(param, JANET_SYMBOL)) {
/* Check for varargs and unfixed arity */
if (!janet_cstrcmp(janet_unwrap_symbol(param), "&")) {
if (seenamp) {
errmsg = "& in unexpected location";
goto error;
} else if (i == paramcount - 1) {
allow_extra = 1;
const uint8_t *sym = janet_unwrap_symbol(param);
if (sym[0] == '&') {
if (!janet_cstrcmp(sym, "&")) {
if (seenamp) {
errmsg = "& in unexpected location";
goto error;
} else if (i == paramcount - 1) {
allow_extra = 1;
arity--;
} else if (i == paramcount - 2) {
vararg = 1;
arity -= 2;
} else {
errmsg = "& in unexpected location";
goto error;
}
seenamp = 1;
} else if (!janet_cstrcmp(sym, "&opt")) {
if (seenopt) {
errmsg = "only one &opt allowed";
goto error;
} else if (i == paramcount - 1) {
errmsg = "&opt cannot be last item in parameter list";
goto error;
}
min_arity = i;
arity--;
} else if (i == paramcount - 2) {
vararg = 1;
arity -= 2;
} else {
errmsg = "& in unexpected location";
goto error;
}
seenamp = 1;
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&opt")) {
if (seenopt) {
errmsg = "only one &opt allowed";
goto error;
} else if (i == paramcount - 1) {
errmsg = "&opt cannot be last item in parameter list";
goto error;
}
min_arity = i;
arity--;
seenopt = 1;
} else if (!janet_cstrcmp(janet_unwrap_symbol(param), "&keys")) {
if (seenamp) {
errmsg = "&keys in unexpected location";
goto error;
} else if (i == paramcount - 2) {
seenopt = 1;
} else if (!janet_cstrcmp(sym, "&keys")) {
if (seenamp) {
errmsg = "&keys in unexpected location";
goto error;
} else if (i == paramcount - 2) {
vararg = 1;
structarg = 1;
arity -= 2;
} else {
errmsg = "&keys in unexpected location";
goto error;
}
seenamp = 1;
} else if (!janet_cstrcmp(sym, "&named")) {
if (seenamp) {
errmsg = "&named in unexpected location";
goto error;
}
vararg = 1;
structarg = 1;
arity -= 2;
arity--;
seenamp = 1;
namedargs = 1;
named_table = janet_table(10);
named_slot = janetc_farslot(c);
} else {
errmsg = "&keys in unexpected location";
goto error;
janetc_nameslot(c, sym, janetc_farslot(c));
}
seenamp = 1;
} else {
janetc_nameslot(c, janet_unwrap_symbol(param), janetc_farslot(c));
janetc_nameslot(c, sym, janetc_farslot(c));
}
} else {
janet_v_push(destructed_params, janetc_farslot(c));
@ -785,6 +1047,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
for (i = 0; i < paramcount; i++) {
Janet param = params[i];
if (!janet_checktype(param, JANET_SYMBOL)) {
janet_assert(janet_v_count(destructed_params) > j, "out of bounds");
JanetSlot reg = destructed_params[j++];
destructure(c, param, reg, defleaf, NULL);
janetc_freeslot(c, reg);
@ -792,15 +1055,37 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
}
janet_v_free(destructed_params);
/* Compile named arguments */
if (namedargs) {
Janet param = janet_wrap_table(named_table);
destructure(c, param, named_slot, defleaf, NULL);
janetc_freeslot(c, named_slot);
janet_v_free(named_params);
}
max_arity = (vararg || allow_extra) ? INT32_MAX : arity;
if (!seenopt) min_arity = arity;
/* Check for self ref */
/* Check for self ref (also avoid if arguments shadow own name) */
if (selfref) {
JanetSlot slot = janetc_farslot(c);
slot.flags = JANET_SLOT_NAMED | JANET_FUNCTION;
janetc_emit_s(c, JOP_LOAD_SELF, slot, 1);
janetc_nameslot(c, janet_unwrap_symbol(head), slot);
/* Check if the parameters shadow the function name. If so, don't
* emit JOP_LOAD_SELF and add a binding since that most users
* seem to expect that function parameters take precedence over the
* function name */
const uint8_t *sym = janet_unwrap_symbol(head);
int32_t len = janet_v_count(c->scope->syms);
int found = 0;
for (int32_t i = 0; i < len; i++) {
if (c->scope->syms[i].sym == sym) {
found = 1;
}
}
if (!found) {
JanetSlot slot = janetc_farslot(c);
slot.flags = JANET_SLOT_NAMED | JANET_FUNCTION;
janetc_emit_s(c, JOP_LOAD_SELF, slot, 1);
janetc_nameslot(c, sym, slot);
}
}
/* Compile function body */
@ -823,7 +1108,7 @@ static JanetSlot janetc_fn(JanetFopts opts, int32_t argn, const Janet *argv) {
if (vararg) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
if (structarg) def->flags |= JANET_FUNCDEF_FLAG_STRUCTARG;
if (selfref) def->name = janet_unwrap_symbol(head);
if (hasname) def->name = janet_unwrap_symbol(head); /* Also correctly unwraps keyword */
janet_def_addflags(def);
defindex = janetc_addfuncdef(c, def);
@ -854,6 +1139,7 @@ static const JanetSpecial janetc_specials[] = {
{"set", janetc_varset},
{"splice", janetc_splice},
{"unquote", janetc_unquote},
{"upscope", janetc_upscope},
{"var", janetc_var},
{"while", janetc_while}
};
@ -866,4 +1152,3 @@ const JanetSpecial *janetc_special(const uint8_t *name) {
sizeof(JanetSpecial),
name);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose and contributors
* Copyright (c) 2023 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,52 @@
* IN THE SOFTWARE.
*/
/* A very simple native module */
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h>
#include "state.h"
#include "util.h"
#endif
static Janet cfun_get_six(int32_t argc, Janet *argv) {
(void) argv;
janet_fixarity(argc, 0);
return janet_wrap_number(6.0);
#ifdef JANET_WINDOWS
#include <windows.h>
#endif
JANET_THREAD_LOCAL JanetVM janet_vm;
JanetVM *janet_local_vm(void) {
return &janet_vm;
}
static const JanetReg array_cfuns[] = {
{"get6", cfun_get_six, NULL},
{NULL, NULL, NULL}
};
JANET_MODULE_ENTRY(JanetTable *env) {
janet_cfuns(env, NULL, array_cfuns);
JanetVM *janet_vm_alloc(void) {
JanetVM *mem = janet_malloc(sizeof(JanetVM));
if (NULL == mem) {
JANET_OUT_OF_MEMORY;
}
return mem;
}
void janet_vm_free(JanetVM *vm) {
janet_free(vm);
}
void janet_vm_save(JanetVM *into) {
*into = janet_vm;
}
void janet_vm_load(JanetVM *from) {
janet_vm = *from;
}
/* Trigger suspension of the Janet vm by trying to
* exit the interpeter loop when convenient. You can optionally
* use NULL to interrupt the current VM when convenient */
void janet_interpreter_interrupt(JanetVM *vm) {
vm = vm ? vm : &janet_vm;
janet_atomic_inc(&vm->auto_suspend);
}
void janet_interpreter_interrupt_handled(JanetVM *vm) {
vm = vm ? vm : &janet_vm;
janet_atomic_dec(&vm->auto_suspend);
}

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