Compare commits

..

1135 commits
0.8 ... master

Author SHA1 Message Date
Alex Shinn
af1bc5806d
Merge pull request #1022 from MikeSS8/typo
fix typo
2025-04-01 13:08:07 +09:00
Mike S. Stevenson
3c228ac0aa fix typo 2025-03-31 22:03:00 -06:00
Alex Shinn
6891ba1a33 add failing non-greedy test example
Issue #1020.
2025-04-01 10:36:06 +09:00
Alex Shinn
f8600d444f Don't consume the delimiter in read-float-tail.
Closes #1019.
2025-03-23 05:21:28 +09:00
Alex Shinn
ed37af2dfd Remove double read-char in scribble parser.
Closes #1018.
2025-03-22 11:20:04 +09:00
Alex Shinn
72ec53ca26 More thorough checks for SEXP_MIN_FIXNUM/-1.
Closes #1006.
2025-01-30 11:44:23 +09:00
Alex Shinn
558e1a895f Bind stack result to local var before casting.
Issue #1006.
2025-01-29 13:12:00 +09:00
Alex Shinn
a844854536 Don't allow mixing rational and floating point syntax.
Closes #1014.
2025-01-03 23:07:18 +09:00
Alex Shinn
1368a748a5 Patch from Vasil Sarafov clarifying DragonFlyBSD support. 2024-12-24 21:47:05 +09:00
Vasil Sarafov
68383d6359 doc: chibi runs flawlessly on OpenBSD
The README.md already includes information that chibi runs without any
issues on OpenBSD. However, the manual does not.

Furthermore, chibi builds & runs fine on OpenBSD, and is even packaged
in the ports.

Signed-off-by: Vasil Sarafov <contact@sarafov.net>
2024-12-24 21:42:08 +09:00
Alex Shinn
c437ede235 Guard against ill-formed responses in snow remote-command. 2024-12-02 11:43:36 +09:00
Alex Shinn
3716d99a02 fast-path vector-map on two vectors 2024-11-13 17:42:36 +09:00
Alex Shinn
49072ebbf4 Need to apply eof-object. 2024-11-13 15:57:26 +09:00
Alex Shinn
28676fcba9 fix csv-num-rows when last row doesn't end in nl 2024-11-08 17:00:16 +09:00
Alex Shinn
bf7187f324 add csv-num-rows 2024-11-08 16:25:13 +09:00
Alex Shinn
f28168a2a6 Adding csv-writer support. 2024-11-02 23:10:49 +09:00
Alex Shinn
8e67defd71 Add quote-doubling-escapes? and quote-non-numeric?. 2024-11-02 18:15:05 +09:00
Alex Shinn
679875d850
Merge pull request #1008 from dpk/srfi-35
Add SRFI 35 support
2024-11-02 09:36:25 +09:00
Daphne Preston-Kendal
2781739291 Move REPL condition printing into the SRFI 35 implementation 2024-11-02 01:03:27 +01:00
Daphne Preston-Kendal
76f35bc733 Define define-condition-type/constructor with syntax-rules 2024-11-02 00:49:31 +01:00
Daphne Preston-Kendal
3777c1b935 Add SRFI 35 support 2024-11-02 00:49:31 +01:00
Alex Shinn
416da21528 Add repl-print-exception. 2024-10-29 21:45:00 +09:00
Alex Shinn
f4e3c0fd0b Defining and using a repl-print generic to allow customizing REPL output. 2024-10-28 09:16:30 +09:00
Alex Shinn
4f3a98b2b3 Improving csv docs. 2024-10-25 18:44:30 +09:00
Alex Shinn
0976d04b21 Adding initial CSV library. 2024-10-23 23:17:03 +09:00
Alex Shinn
be31278685 Clarify there is no special meaning to else in match.
Closes #1005.
2024-10-09 07:16:41 +09:00
Alex Shinn
25a5534584
Merge pull request #1004 from ekaitz-zarraga/doc-formattinga
Fix typo in doc
2024-10-08 09:19:07 +09:00
Ekaitz Zarraga
c288520ca5 Fix typo in doc 2024-10-07 23:17:21 +02:00
Alex Shinn
702e881289 Add error advise when forgetting to import a language.
Closes #1001.
2024-09-20 09:13:16 +09:00
Alex Shinn
d677a135f1 Add current-test-value-formatter. 2024-09-17 18:37:40 +09:00
Alex Shinn
dce487fa3a c64/128 default values should be complex 2024-09-11 22:40:46 +09:00
Alex Shinn
2acef43da7 array-freeze! also makes the underlying storage immutable 2024-09-11 10:14:37 +09:00
Alex Shinn
0516e62b0b f*-storage-class defaults should be inexact 2024-09-11 10:14:37 +09:00
Alex Shinn
491cf324ec
Merge pull request #998 from dpk/test-error-predicate
(chibi test): add a type test for exceptions in test-error
2024-08-28 10:30:30 +09:00
Daphne Preston-Kendal
5bc498b32a (chibi test): add a type test for exceptions in test-error 2024-08-25 21:28:28 +01:00
Alex Shinn
24b5837562 Fix help output for nested command-specific options.
Closes #997.
2024-08-19 22:24:03 +09:00
Alex Shinn
e09fdb7e31 Fix attribute skipping for chibi-doc text rendering.
Closes #996.

Also guard against bad input with proper-list?.
2024-08-15 12:09:46 +09:00
Alex Shinn
020469bdbd
Merge pull request #993 from il-k/manual
README: add link to online manual
2024-06-17 09:19:49 +09:00
ilk
16b11f57b8
README: add link to online manual
It is not uncommon that the git repo is the first encounter with a
project. Having the manual available in the repo makes it easier to
discover.
2024-06-16 13:42:32 +03:00
Alex Shinn
3733b63d5f
Merge pull request #990 from welcome-linja/master
Fix SEXP_USE_ALIGNED_BYTECODE
2024-06-03 10:55:55 +09:00
Eleanor Bartle
243fd41aad Conform to 1/0 style 2024-06-03 11:43:32 +10:00
Alex Shinn
d4028f953b Tentatively manually encoding non-finite f16 values.
Issue #988.
2024-06-02 22:31:25 +09:00
Alex Shinn
3be1603f45 fix srfi 159 loading
Closes #905.
2024-06-02 17:51:34 +09:00
Alex Shinn
b1a370b218 add link to paper for single/half float conversions 2024-06-01 22:18:16 +09:00
Alex Shinn
f1df493c32 Upgrading to Unicode 15.1.0. 2024-05-31 23:57:18 +09:00
Alex Shinn
01d5dd2d55 add missing string-trim in extract-char-set-property 2024-05-31 23:52:54 +09:00
Alex Shinn
f53c642e74 bumping version 2024-05-31 23:04:40 +09:00
Alex Shinn
1bd81c1cb5 updating recent contributors 2024-05-31 22:56:40 +09:00
Alex Shinn
925c044eef Updating AUTHORS. 2024-05-31 19:25:48 +09:00
Alex Shinn
0bbb60060a Fix getgrnam_r error handling.
Closes #884.
2024-05-31 19:05:43 +09:00
Alex Shinn
7885db95cf Use github for homepage.
Closes #906.
2024-05-31 18:51:13 +09:00
Alex Shinn
193424f74d Add assertion for copy-on-failure? type.
Closes #987.
2024-05-31 18:46:39 +09:00
Alex Shinn
0b55c0b718 Fix copying reshape.
Closes #986.
2024-05-31 09:50:07 +09:00
Alex Shinn
4b5ab838e2 record the start dir when loading SRFI 193
Closes #922
2024-05-30 23:09:37 +09:00
Alex Shinn
bfb6b4bf82 updating doc links for new libs
Closes #923
2024-05-30 22:55:26 +09:00
Alex Shinn
414a23139f Fix reshape zero-dimensional and empty arrays.
Issue #986.
2024-05-30 22:37:06 +09:00
Alex Shinn
5e74c5ff54 add data domain checks for generic-storage-class
Closes #985.
2024-05-30 19:09:54 +09:00
Alex Shinn
3558c0f4a6 Add tests and documentation for define-binary-record-type. 2024-05-30 19:08:09 +09:00
Alex Shinn
8e3fd8f00c Add error checking for storage class data.
Closes #981.
2024-05-30 09:28:38 +09:00
Alex Shinn
390122a7bc accept a --quiet option to disable full request logging in http-server
Closes #926
2024-05-29 22:46:52 +09:00
Alex Shinn
5350d0429c export http-send-file
Closes #927
2024-05-29 22:37:43 +09:00
Alex Shinn
26a4ce94a7 Implement look-around assertions for SRFI 115. 2024-05-29 22:30:46 +09:00
Alex Shinn
832d82c494 Fix array-inner-product, fail fast for empty arrays.
Closes #982.
2024-05-29 21:42:20 +09:00
Alex Shinn
648f6b9de6 Fix error reporting for complex inequality comparisons.
Closes #934.
2024-05-29 21:36:30 +09:00
Alex Shinn
045bb1813c reduce bound on equal?/bounded 2024-05-29 14:10:42 +09:00
Alex Shinn
580aaf35ff match sexp_gc_releaseN count in sexp_add_import_binding
The count is not actually used but could be in the future.
2024-05-29 09:26:40 +09:00
Alex Shinn
b5de5eca92 interval-cartesian-product should accept zero args
Closes #983.
2024-05-29 09:08:26 +09:00
Alex Shinn
e737e48955 Fix interval-intersect for degenerate axes.
Closes #984.
2024-05-29 09:04:46 +09:00
Alex Shinn
609c78c0ca Forgot to add file for (srfi 160 mini). 2024-05-28 23:13:18 +09:00
Alex Shinn
2161f0df6e escape backslash 2024-05-28 23:12:09 +09:00
Alex Shinn
9010b2c5be provide a simpler (chibi app) example 2024-05-28 23:11:27 +09:00
Alex Shinn
36d7881763 Update to n-ary array-fold-* with correct arg order.
Closes #973.
2024-05-28 22:35:31 +09:00
Alex Shinn
96f17293f2 install (chibi text) 2024-05-28 22:14:07 +09:00
Alex Shinn
c966dfa7a8 suppress output of ldconfig
Closes #979.
2024-05-28 22:12:32 +09:00
Alex Shinn
c3c65b0309
Merge pull request #978 from arthurgleckler/master
Fix typo in (chibi app) example.
2024-05-28 22:09:56 +09:00
Arthur A. Gleckler
619f63fb5e Fix typo in (chibi app) example.
Backslash needed escaping.
2024-05-27 19:16:36 -07:00
Alex Shinn
78a990c73b Don't pre-filter empty arrays in array-append.
Closes #977.
2024-05-28 09:35:39 +09:00
Alex Shinn
11984c6eb3 Fix flatten-vector->list on empty vectors.
Closes #976.

Complements of Bradley Lucier.
2024-05-27 23:05:15 +09:00
Alex Shinn
2b1d2d99a8 Fix array-append for non-zero based intervals.
Closes #972.
2024-05-27 23:01:34 +09:00
Alex Shinn
a8939fecd0 array-stack should use the specified storage-class
The original code was based on (chibi math linalg)
which preferred the domain of the stacked arrays.
2024-05-27 18:33:24 +09:00
Alex Shinn
07f3301cc8 interval-contains-multi-index? should handle 0 dimensions
Closes #974.

Commit on behalf of Bradley Lucier.
2024-05-27 18:28:41 +09:00
Alex Shinn
4396e8dd4e Handle empty vector. 2024-05-27 13:21:24 +09:00
Alex Shinn
418d5c8a8c Build up empty arrays of higher dimensions for list/vector*->array
Issue #962.
2024-05-27 12:40:13 +09:00
Alex Shinn
f9e3ed1639 guard against mutation in make-interval
Closes #971
2024-05-27 09:29:37 +09:00
Alex Shinn
7923b1c46d Add array-empty?
Closes #969.
2024-05-27 09:27:42 +09:00
Alex Shinn
2f32ec6ba1 vector->array fix for optional args
Closes #968

Thanks Bradley Lucier!
2024-05-27 09:25:39 +09:00
Alex Shinn
db53df7df4 Fix some array-tile domain assertions.
Closes #966.

Fix complements of Bradley Lucier.
2024-05-26 22:04:22 +09:00
Alex Shinn
953f3ada23 allow noop (index-rotate n n)
Closes #965.
2024-05-26 22:00:43 +09:00
Alex Shinn
c96b0123a0 array-reduce should fail for empty arrays
Closes #964.
2024-05-26 21:58:00 +09:00
Alex Shinn
f4add6d188 Fix list/vector*->array for 0 dimensions.
Closes #962.
2024-05-26 21:54:28 +09:00
Alex Shinn
c200ecb21c
Merge pull request #940 from raviqqe/chore/unwind-on-exit
Unwind on exit
2024-05-26 21:51:17 +09:00
Yota Toyama
587f739f76 Import call/cc 2024-05-26 13:10:28 +09:00
Yota Toyama
0673eae46d Fix 2024-05-26 13:06:58 +09:00
Alex Shinn
698dcb2bfb Fix list/vector*->array for list elements.
Issue #962.
2024-05-25 22:41:45 +09:00
Alex Shinn
6c49071833 Factor out (srfi 160 mini) for f8/f16 base.
Closes #961.

Import this instead of the full vector libs for (srfi 231).

Also fix install of full vector libs for (srfi 160).
2024-05-25 22:15:10 +09:00
Alex Shinn
afda4ab979 Fix array-any.
Closes #963.
2024-05-25 22:06:23 +09:00
Alex Shinn
e492e4002f
Merge pull request #932 from aisk/master-1
improve readme for mac users
2024-05-25 21:57:03 +09:00
Alex Shinn
89dd02d55e Fix interval iteration for empty intervals.
Closes #959.
2024-05-24 22:29:44 +09:00
Alex Shinn
0ce4614457 Add array-packed? tests on empty arrays.
Issue #959.
2024-05-24 19:42:00 +09:00
Alex Shinn
09a5c431a2 array-tile widths can exceed the axis width
Closes #958.
2024-05-24 19:35:33 +09:00
Alex Shinn
33a59952a8 Implement and use array-freeze!
Fixes #960.
2024-05-24 19:20:14 +09:00
Alex Shinn
f60298b707 Initial half and quarter precision uniform vectors.
Quarter precision is 1.5.2 format.
Used to implement f16-storage-class and f8-storage-class.
Can be disabled at compile time.
2024-05-24 19:04:44 +09:00
Alex Shinn
e4568bd419 Use #\null as the default for char-storage-class 2024-05-23 21:37:12 +09:00
Alex Shinn
ef4e450af7 Fix element initialization for char arrays.
Closes #957.
2024-05-23 10:47:36 +09:00
Alex Shinn
4677cfb85b fix vector*->array 2024-05-23 10:38:16 +09:00
Alex Shinn
37dda638c3 Implement array-block. 2024-05-22 23:15:43 +09:00
Alex Shinn
65589e3e26 Fix default coeffs for the degenerate dimension case. 2024-05-22 22:02:27 +09:00
Alex Shinn
0d8e91e96c
Merge pull request #956 from 0xJonas/fix_sexp_string_cursor_set_args
Added missing argument to `sexp_string_cursor_set`
2024-05-22 22:01:28 +09:00
Jonas Rinke
ce7d4e1e3a Added missing argument to sexp_string_cursor_set 2024-05-21 21:22:17 +02:00
Alex Shinn
720ec69489 Adding a chibi-<version> feature.
Issue #955.
2024-05-20 22:03:41 +09:00
Alex Shinn
86ef8f5f1d
Merge pull request #954 from petteripiiroinen/fix-unintialised-stack-top-issue
Fix: segmentation fault during GC marking
2024-05-19 22:08:38 +09:00
Alex Shinn
3b6be9d60c Fix cmake build. 2024-05-18 05:45:45 +09:00
Petteri Piiroinen
f3b957c57f Fix: segmentation fault during GC marking
The stack top needs to be initialised before a potential garbage
collection after sexp_apply, SEXP_OP_APPLY1 and SEXP_OP_TAIL_CALL, since
stack top can otherwise be pointing to a stale pointer. This restores
the make_call invariant.
2024-05-17 06:52:02 +03:00
Alex Shinn
017e4b6990 Add feature for architecture.
Issue #955.
2024-05-16 23:28:29 +09:00
Alex Shinn
47f7ab01cf Show source for failed expected value. 2024-05-16 23:27:57 +09:00
Alex Shinn
7ac3cfebe1 Update to new make-specialized-array signature. 2024-05-14 21:46:25 +09:00
Alex Shinn
2e09a082c8 Fix SRFI 231 tests. 2024-05-13 22:10:49 +09:00
Alex Shinn
6ae3a43ee7 Adding memoize-file-loader test. 2024-05-13 22:06:19 +09:00
Alex Shinn
f25329b5aa Adding initial text type. 2024-03-19 23:03:21 +09:00
Alex Shinn
c4611cc33f Add some extended utf8 IO utilities. 2024-03-18 22:47:40 +09:00
Alex Shinn
5b19aab107
Merge pull request #950 from wasamasa/optimize-read-bytevector
Avoid needless allocation in read-bytevector!
2024-03-18 11:56:21 +09:00
Vasilij Schneidermann
0fd351e0b5 Fix read-bytevector logic 2024-03-18 03:15:39 +01:00
Vasilij Schneidermann
c837c7110f Correct let to let* 2024-03-18 02:48:48 +01:00
Vasilij Schneidermann
1b1e8b311b Correct read-bytevector logic for small reads 2024-03-18 02:06:27 +01:00
Vasilij Schneidermann
d0e6dc7556 Avoid needless allocation in read-bytevector!
This change switches the implementation strategy to basing
read-bytevector on top of read-bytevector! rather than the other way
around.
2024-03-18 01:13:57 +01:00
Alex Shinn
b303bf3611 Allow for a chunked regexp API by exposing low-level tools. 2024-03-17 22:21:23 +09:00
Alex Shinn
5b27b01f91 Fix line wrapping in chibi test 2024-03-17 10:39:27 +09:00
Alex Shinn
19c7d4fec2 user/group-information should return #f for unknown users 2024-02-23 15:16:22 +09:00
Alex Shinn
56ef426dfa Catch division edge case of (/ fx-least -1).
Thanks for Jim Rees for reporting.
2024-02-22 16:32:20 +09:00
Alex Shinn
29dd1a3b81 Add more specific warning for error on no import, clarify docs. 2024-01-30 12:31:06 +09:00
Alex Shinn
97a04bd2fc
Merge pull request #946 from ekaitz-zarraga/faster-concatenate!
Reduce iterations in concatenate!
2024-01-10 23:45:28 +09:00
Ekaitz Zarraga
967b888d8c Reduce iterations in concatenate!
This commit should reduce the amount of iterations in concatenate to N
where N is the sum of the lengths of the input lists.

The previous implementation iterated from the beginning in each
concatenation because of `last-pair`.

This implementation is significantly faster in this extreme case:

(concatenate! `(,(iota 50000) ,@(map list (iota 500))))

>> Previous implementation:
real	0m0.671s
user	0m0.658s
sys	0m0.013s

>> This implementation:
real	0m0.175s
user	0m0.174s
sys	0m0.001s

The tests is done using `time`, which is not reliable at all, but using
`(trace last-pair)` shows accurately what happens with the iterations.
2024-01-09 17:18:41 +01:00
Alex Shinn
a67e75926d
Merge pull request #943 from ekaitz-zarraga/master
Add srfi-64
2024-01-09 11:14:49 +09:00
Alex Shinn
cc6a3d10e5
Merge pull request #945 from ekaitz-zarraga/concatenate!
Fix #944: concatenate! work with empty lists in any position
2024-01-09 09:42:27 +09:00
Ekaitz Zarraga
70989e0cef srfi: 1: add tests for append! (and concatenate!) 2024-01-09 01:04:34 +01:00
Ekaitz Zarraga
7bf376b7fb Fix: concatenate! work with empty lists 2024-01-08 22:56:07 +01:00
Ekaitz Zarraga
bd01401a24 doc: add srfi-64 2024-01-07 21:05:25 +01:00
Ekaitz Zarraga
43bfac5884 Add srfi-64 2024-01-07 20:58:46 +01:00
Alex Shinn
af41e2b01d
Merge pull request #942 from dpk/newlines-in-verbose-test-output
`(chibi test)`: Put newlines after test results etc in verbose mode
2023-11-07 14:17:17 +09:00
Daphne Preston-Kendal
a277a5dffc (chibi test): Put newlines after test results etc in verbose mode 2023-11-06 20:59:10 +01:00
Yota Toyama
f41a61f748 Fix windows import 2023-10-13 17:21:11 +11:00
Yota Toyama
77dc8c3524 Refactor 2023-10-13 17:19:36 +11:00
Yota Toyama
70e5aa14a3 Unwind before exit 2023-10-13 16:37:43 +11:00
Alex Shinn
fe93067553
Merge pull request #939 from raviqqe/bug/write-char
Handle basic special characters in `write`
2023-09-29 10:46:02 +09:00
Yota Toyama
4a4a1553f5 Fix 2023-09-27 19:13:57 +10:00
Yota Toyama
0e009d6045 Fix bug 2023-09-27 19:11:41 +10:00
Alex Shinn
f9908f19ee
Merge pull request #937 from gambiteer/231-checks
SRFI 231: Declare char-storage-class, fix interval-projections
2023-08-29 20:54:13 +09:00
Bradley Lucier
e390668961 SRFI 231: Declare char-storage-class, fix interval-projections 2023-08-27 23:22:14 -04:00
AN Long
27ca614b42
improve readme for mac users 2023-08-08 17:51:44 +08:00
Alex Shinn
67fdb283b6 fix init value for make-specialized-array 2023-06-20 22:19:19 +09:00
Alex Shinn
44f8c91931 Fix zero-dimensional array indexing. 2023-06-20 22:16:18 +09:00
Alex Shinn
b06c4cca9d Merge branch 'master' of github.com:ashinn/chibi-scheme 2023-06-04 06:06:47 +09:00
Alex Shinn
4b5e885f31 Fix coeffs in trivial dimensions to work with BLAS. 2023-06-04 06:05:29 +09:00
Alex Shinn
13812f8749
Merge pull request #920 from gambiteer/231-test
SRFI 231: Add index-* tests
2023-06-03 10:43:38 +09:00
Bradley Lucier
7420ba9315 SRFI 231: Add index-* tests
lib/srfi/231/base.scm:

1.  Add argument checks for index-first, index-last, index-rotate, and index-swap.

lib/srfi/231/test.sld:

1.  1,$s/179/231/g (in vim notation)

2.  Add tests for index-first, index-last, index-rotate, and index-swap.

3.  Remove trailing spaces.
2023-05-30 13:08:25 -04:00
Alex Shinn
6ea80c5ea4 add srfi 231 to lib tests 2023-05-30 11:36:36 +09:00
Alex Shinn
8e1ea89ce6
Merge pull request #919 from gambiteer/231-install
Fix SRFI 231 install
2023-05-29 18:34:24 +09:00
Bradley Lucier
732078cde4 Fix SRFI 231 install
Makefile:

When installing chibi, make installation directory and install files for SRFI 231.
When uninstalling chibi, remove installation directory and files for SRFI 231.

lib/srfi/231/transforms.scm:

Move definition of vector-iota from here to ...

lib/srfi/231/base.scm:

Here.

lib/srfi/231/base.sld:

Export vector-iota to use in both base.scm and transforms.scm.
2023-05-28 17:48:32 -04:00
Alex Shinn
ef554024ec
Merge pull request #918 from gambiteer/231-changes
Add index-swap, fix assert in array-append
2023-05-24 09:22:50 +09:00
Bradley Lucier
27ea774e2e Add index-swap, fix assert in array-append 2023-05-23 15:09:25 -04:00
Alex Shinn
06f0cc0225 Add iset-rank/select. 2023-05-23 22:03:19 +09:00
Alex Shinn
d6c58a7e11 Fix array-append signature. 2023-05-20 16:31:23 +09:00
Alex Shinn
870e484b50 provide initial raw-script-file definition in meta-7.scm
Closes #916
2023-05-09 06:50:03 +09:00
Alex Shinn
58a79b09d0
Merge pull request #915 from lassik/srfi-193
Fix broken import in (srfi 193)
2023-05-05 05:28:06 +09:00
Lassi Kortela
be22930896 Fix broken import in (srfi 193)
Fixes #914
2023-05-04 18:35:59 +03:00
Alex Shinn
971f546833
Merge pull request #913 from lassik/patches
Drop (chibi sxml) dependency on let-optionals
2023-04-22 14:17:00 +09:00
Lassi Kortela
561fc1bae0 Drop (chibi sxml) dependency on let-optionals
let-optionals can be provided by the (chibi optional) library or by
SRFI 227. Either dependency is non-trivial and makes it tricky to
incorporate (chibi sxml) into outside projects. Since (chibi sxml)
only makes trivial use of let-optionals, expand the macro by hand.
2023-04-21 16:42:03 +03:00
Alex Shinn
2dc7dd5b68
Merge pull request #912 from lassik/patches
Update .gitignore
2023-04-21 09:07:35 +09:00
Lassi Kortela
18920a9160 Update .gitignore 2023-04-20 14:37:21 +03:00
Alex Shinn
1ba5df1fdf Adding missing length<=? (closes #909). 2023-04-02 22:48:51 +09:00
Alex Shinn
7e511ef8e4 typo s!fx+*/carry!fx*/carry!g (issue #908) 2023-04-02 22:39:25 +09:00
Alex Shinn
5826023de1
Merge pull request #907 from rgherdt/feature/add-guile-support-for-snow
add support for Guile [snow-chibi]
2023-04-02 22:26:29 +09:00
Ricardo G. Herdt
ffe1ae4452 add support for Guile [snow-chibi]
Two recent changes to Guile improved its R7RS support:

- 3.0.7 fixed a bug regarding cond-expand in a define-library form.
- 3.0.8 added support for R7RS' srfi library names, e.g. (srfi 69) instead of
  (srfi srfi-69) used by Guile.

These changes open the possibility for using snow libraries in R7RS Guile
programs. This commit adds support for installing/removing snow libraries for
Guile.
2023-03-31 20:29:35 +02:00
Alex Shinn
d5e85874b3 Merge branch 'master' of github.com:ashinn/chibi-scheme 2023-03-19 23:57:10 +09:00
Alex Shinn
3b8f07b12e Fix array-stack, interval folds and list*->array.
Issue #900.
2023-03-19 23:56:01 +09:00
Alex Shinn
8ea99a9e40
Merge pull request #903 from adamfeuer/feature/httpd-client-server-examples
add simple http client and server examples
2023-03-15 22:51:12 +09:00
Adam Feuer
eecf561e62 add simple http client and server examples 2023-03-14 20:40:37 -07:00
Alex Shinn
e6d7e4fffb sexp_poll_port needs a timeout 2023-03-15 10:18:37 +09:00
Alex Shinn
82dfe95468
Merge pull request #898 from nkoguro/fix-read-number
Fix bug: sexp_read_number can't parse a/b@c-style number correctly.
2023-02-26 21:28:28 +09:00
KOGURO, Naoki
35281cf28e Fix bug: sexp_read_number can't parse a/b@c-style number correctly. 2023-02-25 11:26:51 +09:00
Alex Shinn
dde5f6c88d
Merge pull request #896 from chk-jxcn/chk-jxcn-patch-1
Fix #880
2023-02-20 10:40:09 +09:00
chk-jxcn
767bb8a5f9
Fix #880
Fix issue of can't load symbol when load from image, which cause by add extra "(sexp_proc1)" before function name.
Error message: "dynamic function lookup failure: <static> (sexp_proc1)sexp_get_sha_stub"
2023-02-20 02:53:56 +08:00
Alex Shinn
c026c0884d Encode JSON null as the symbol 'null.
Closes #893.
2023-02-16 21:32:35 +09:00
Alex Shinn
4dab8b81d4 Implementing array-decurry. 2023-02-16 21:20:37 +09:00
Alex Shinn
18c958e836
Merge pull request #887 from mnieper/srfi-211
Provide identifier-syntax and make-variable-transformer through standardized SRFI libraries.
2023-02-08 21:38:00 +09:00
Alex Shinn
b22bcc1fcc don't assume git for building clibs.c (issue #891) 2023-02-08 09:55:54 +09:00
Alex Shinn
8e9b15eda8 Merge branch 'master' of github.com:ashinn/chibi-scheme 2023-02-08 09:38:17 +09:00
Alex Shinn
875cefc686 clarify chibi-scheme-static docs 2023-02-08 09:37:39 +09:00
Alex Shinn
b297e7272b
Merge pull request #888 from smazga/9front-exit
Fix exit call on plan9/9front
2023-02-05 09:48:29 +09:00
McKay Marston
27071e6c8f ifdef the return status so that non-plan9 systems get the real value 2023-02-04 16:36:49 -08:00
McKay Marston
0aa515730f Fix exit call on plan9/9front
* make sure exits is passed a nil on success
* make sure main exits with a proper exits call
2023-02-03 17:19:46 -08:00
Marc Nieper-Wißkirchen
c5615c9b24 Install the new libraries. 2023-02-01 12:58:21 +01:00
Marc Nieper-Wißkirchen
c6db239882 Provide identifier-syntax and make-variable-transformer through standardized SRFI libraries. 2023-02-01 10:33:09 +01:00
Alex Shinn
598dcad547 Error on using only to import an unexported binding.
Closes #865.
2023-01-28 15:47:37 +09:00
Alex Shinn
e93b71990c Cast to int before comparing with EOF (#745). 2022-12-11 22:56:45 +09:00
Alex Shinn
da53f46c93 Merge branch 'master' of github.com:ashinn/chibi-scheme 2022-12-04 23:32:54 +09:00
Alex Shinn
cadae49fec Fix sexp_contains_syntax_p_bound for synclos in dotted rest position.
Closes #464.
2022-12-04 23:31:25 +09:00
Alex Shinn
8653dddeb3
Merge pull request #856 from dpapavas/static-user-libs
Add support for exporting statically compiled libraries from C
2022-10-31 18:54:40 +09:00
Dimitris Papavasiliou
310a04f701 Add support for user exported C libraries
This uses the existing mechanism for statically compiled C libraries,
to allow the user to export their own C libraries in a similar way.
User exported libraries can be added on top of statically compiled C
libraries or exist on their own (by setting SEXP_USE_STATIC_LIBS_EMPTY).
2022-10-30 14:06:18 +02:00
Alex Shinn
4185012205
Merge pull request #870 from dpk/safe-syntax-case-macro-aux
Make macro-aux safe for other things together with syntax-case
2022-10-30 13:43:28 +09:00
Alex Shinn
d29657811c
Merge pull request #871 from dpk/fix-syntax-tests
Fix syntax-tests to use mutable-environment
2022-10-30 13:40:54 +09:00
Daphne Preston-Kendal
dcd2ce9054 Add syntax-tests to test-all 2022-10-28 11:10:51 +02:00
Daphne Preston-Kendal
e4d53fe533 Fix syntax-tests to use mutable-environment 2022-10-28 11:06:21 +02:00
Daphne Preston-Kendal
97adffc8b5 Make macro-aux safe for other things together with syntax-case
If you set the macro-aux of a macro outside of (chibi syntax-case), it
would previously case `syntax` to think that it was a pattern variable
and try to substitute it, even if the macro-aux was being used for
something else.

This patch fixes that by wrapping pattern variable values in an extra
typed box and checking that it has the right type before deciding that
it’s actually a pattern variable.
2022-10-26 11:04:23 +02:00
Alex Shinn
d67fa42d0c
Merge pull request #793 from dpk/string-ref-cache
Add a feature to cache the most recent string index->cursor result
2022-10-19 17:59:08 +09:00
Alex Shinn
ad4dfcb77b add package-page snow-fort utility 2022-10-19 17:53:59 +09:00
Alex Shinn
cee932d2dc add ffi support for movable parameters 2022-10-19 17:53:01 +09:00
Alex Shinn
b1750cee57
Merge pull request #868 from arthurgleckler/master
Fix bug: attributes without values didn't work.
2022-10-12 16:44:55 +09:00
Arthur A. Gleckler
73875cbaf7 Fix bug: attributes without values didn't work.
Before, it was necessary to do something like this:

  (option (@ (selected . #false) (value "any")) "any")

instead of:

  (option (@ (selected) (value "any")) "any")

Only the former is valid SXML, as far as I can tell from the SXML
specification:

  <https://dl.acm.org/doi/pdf/10.1145/571727.571736>
2022-10-11 21:22:39 -07:00
Alex Shinn
6d58f9e3f6
Merge pull request #867 from arthurgleckler/master
Add support for SXML indentation on output.
2022-10-11 23:19:52 +09:00
Arthur A. Gleckler
24339e51e7 Update variable name per Alex's suggestion. 2022-10-11 07:17:31 -07:00
Alex Shinn
fa6d4f7a4f Adding sxml tests. 2022-10-11 22:42:54 +09:00
Alex Shinn
0a050a524a Improve let-keywords docs and add unit tests (issue #866). 2022-10-11 22:32:32 +09:00
Arthur A. Gleckler
4e24ad01e0 Add support for SXML indentation on output. 2022-10-10 13:34:27 -07:00
Alex Shinn
49f95dc107 Fix bug in procedure-flags in (chibi ast) (issue #864)
We were incorrectly boxing an already boxed value.
2022-10-05 09:06:51 +09:00
Alex Shinn
0eeeac7650 Make environment immutable and add mutable-environment alternative (issue #863). 2022-10-04 16:07:36 +09:00
Alex Shinn
e88374aae1 typo s/df/fd (fixes #861) 2022-09-26 22:37:51 +09:00
Alex Shinn
95827a44ed Add immutable-string with copy-on-write semantics (issue #860). 2022-09-16 18:18:20 +09:00
Alex Shinn
1e47c78b8a Fix reversal of results in rounding all leading 9's (issue #859). 2022-09-15 21:24:00 +09:00
Alex Shinn
fa8a506ed5
Merge pull request #858 from okuoku/win32-test-fix
cmake: Exclude `(chibi shell)` test on Win32
2022-09-11 20:02:26 +09:00
okuoku
f887003c30 cmake: Exclude (chibi shell) test on Win32
Exclude `(chibi shell)` test on Win32 since it's not compatible.
2022-09-11 13:40:50 +09:00
Alex Shinn
0a50b305bc string-set! should respect immutability (issue #857) 2022-09-04 16:28:04 +09:00
Alex Shinn
2aa6dc829e
Merge pull request #854 from lockywolf/chibi-shell-return-value-exit-status
Make (shell) in (chibi shell) return exit status of last command.
2022-08-24 14:37:14 +09:00
Lockywolf
6bb62979fd Make (shell) in (chibi shell) return exit status of last command. 2022-08-24 13:17:37 +08:00
Alex Shinn
f367cb86e2 signal an error when we can't change-directory in with-directory (issue #850) 2022-08-11 21:56:35 +09:00
Alex Shinn
7e0b2730f4 snow-post should quote values 2022-08-09 18:43:51 +09:00
Alex Shinn
9993b27486 make-request path should be a string even in failure case 2022-08-09 14:02:19 +09:00
Alex Shinn
51beea2bb6 adding more warnings for bad repos (issue #846) 2022-08-08 18:59:50 +09:00
Alex Shinn
1f1b361010 Using Makefile-configured snow install directories. 2022-08-08 18:43:30 +09:00
Alex Shinn
eac4adc272
Merge pull request #849 from lockywolf/shell.scm-scribble-fixes
Fix scribble documentation for shell.scm
2022-08-04 20:45:39 +09:00
Lockywolf
bf1703e511 Fix scribble documentation for shell.scm 2022-08-03 23:21:50 +08:00
Alex Shinn
c9344debfb Revert "Install manpages in man/man1, not man"
This reverts commit c5446df854.

MANDIR is already defined to include man1.
2022-08-03 22:55:30 +09:00
Alex Shinn
46c4a0cd7c
Merge pull request #847 from lockywolf/master
Install manpages in man/man1, not man
2022-08-03 22:48:09 +09:00
Alex Shinn
70acbf5a08 fix indentation 2022-08-03 22:44:28 +09:00
Alex Shinn
a2daa155e8 comment out failing chicken tests 2022-08-03 22:43:40 +09:00
Alex Shinn
2f50a6cf74
Merge pull request #848 from lockywolf/crutch-for-relative-install-lib-dir
Add a crutch to better detect snow binary extension dir.
2022-08-03 22:42:40 +09:00
Lockywolf
ac5c10c114 Add a crutch to better detect snow binary extension dir. 2022-08-03 21:40:48 +08:00
Alex Shinn
873e1c490f wrap tests in groups 2022-08-03 22:38:39 +09:00
Alex Shinn
97ca7e1799 don't build images by default when DESTDIR is specified 2022-08-03 22:38:27 +09:00
Alex Shinn
66deb6fe3b install-data-file should return the installed path 2022-08-03 22:38:07 +09:00
Alex Shinn
dea22a424b use chroot to install images (issue #844) 2022-08-02 15:00:56 +09:00
Lockywolf
c5446df854 Install manpages in man/man1, not man 2022-08-02 13:10:02 +08:00
Alex Shinn
805fcc7d30 fix (chibi shell) summary 2022-07-30 07:02:37 +09:00
Alex Shinn
b677b287ec
Merge pull request #843 from lockywolf/master
Add (chibi shell) to the documentation.
2022-07-30 07:00:32 +09:00
Lockywolf
b89545df48 Add (chibi shell) to the documentation.
1. Add "shell" to the list of html_docs
2. Add a reference to (chibi shell) to chibi.scribl
2022-07-29 22:25:56 +08:00
Alex Shinn
568519bf6b fleshing out I/O redirection and adding docs 2022-07-29 18:50:42 +09:00
Alex Shinn
1b0566b759 add io redirection to syntax 2022-07-29 07:30:35 +09:00
Alex Shinn
1bea865ec2 more shell utilities 2022-07-16 21:55:59 +09:00
Alex Shinn
bc18b0cc30 allow custom option types for (chibi app) 2022-07-09 14:59:34 +09:00
Alex Shinn
d03202407b fix pipe example 2022-07-09 14:59:17 +09:00
Alex Shinn
701cf1d169 no more flexible arrays (issue #842) 2022-07-04 22:30:49 +09:00
Alex Shinn
658244d64e Add WIP shell library. 2022-07-01 22:39:27 +09:00
Alex Shinn
f5d96939b6 adding optional child-prod arg to call-with-process-io 2022-06-19 08:30:45 +09:00
Alex Shinn
54d3aafc7b update test 2022-06-12 16:11:16 +09:00
Alex Shinn
38fc7e0932 Initial SRFI 231 implementation. 2022-06-12 16:04:38 +09:00
Alex Shinn
4d0ae090b7 http-send-file default mime type should be application/octet-stream 2022-06-12 10:02:38 +09:00
Alex Shinn
566d9a47cf
Merge pull request #839 from rschifflin/rs-bignum-fix-to-sint
Fix SEXP_CUSTOM_LONG_LONGS lsint_to_sint
2022-06-11 08:16:39 +09:00
Mark Schifflin
2f524c59f7 Fix lsint_to_sint 2022-06-08 20:43:44 -07:00
Alex Shinn
35eed62160 the top-level of a macro expansion should preserve the call site source (issue #835) 2022-06-03 13:36:56 +09:00
Alex Shinn
05ee42804a Merge branch 'master' of github.com:ashinn/chibi-scheme 2022-05-29 08:03:48 +09:00
Alex Shinn
3c4ace142c propagate source info manually in let (issue #835) 2022-05-29 08:03:32 +09:00
Alex Shinn
bf225edc8e
Merge pull request #832 from jpellegrini/srfi-144
SRFI-144: accept zero arguments for flmax/flmin
2022-05-15 22:21:56 +09:00
Jeronimo Pellegrini
32ce583927 Add some more unit tests to SRFI-144
Tests for flmin, flmax, fl-least, fl-epsilon, fl-greatest are
included.
2022-05-15 08:30:27 -03:00
Jeronimo Pellegrini
1ecf7f9c8a SRFI-144: accept zero arguments for flmax/flmin
SRFI-144 requires that (flmin) returns +inf.0 and that
(flmax) returns -inf.0, so these procedures can't really
be aliases to the Chibi implementation of R7RS max and min.
2022-05-14 08:14:08 -03:00
Alex Shinn
42332bb04f compute least double properly (issue #831) 2022-05-14 16:30:27 +09:00
Alex Shinn
09200ae13c fix locale-dependent decimal separators (issue #829) 2022-05-12 18:10:38 +09:00
Alex Shinn
b0735b3ca7
Merge pull request #828 from dpk/better-case-lambda-tests
Better case-lambda tests
2022-04-20 21:10:55 +09:00
Daphne Preston-Kendal
92fa73ecab Better case-lambda tests
The problem with the original `case-lambda` tests is that they could
actually pass if the `+` and `*` procedures were implemented correctly
but `case-lambda` itself wasn’t.

Specifically, an attempted optimized `case-lambda` implementation
which looked at the length of its arguments list and subsequently
erroneously always chose the variadic clause of the `plus` procedure
would still pass the test, because `plus` in this case recreated the
behaviour of the `+` procedure used for the test; it was never
actually observable whether the `args` clause or one of the more
specific clauses had been used to generate the result. Similar applies
to the `mult` test: although in that case an implementation could only
have erroneously chosen the `(x y . z)` clause in the two-argument
case, it would still have been an error invisible to the test cases.

I’ve also added a test which attempts to ensure that a redundant
clause will never match. This may cause a warning on Schemes which
detect such clauses at compile time, but R7RS does not explicitly
define such `case-lambda` expressions as erroneous in any way, so it
would be wrong (and non-conformant) for it to stop the tests running
altogether.

(This patch mainly useful because Chibi’s R7RS tests are sometimes
used by other implementations to ensure conformance. Chibi passed
these tests in any case.)
2022-04-18 10:05:40 +02:00
Alex Shinn
d4eb32f8b1 bounds check for parse-stream-debug-info on empty input (fixes issue #826) 2022-04-18 08:55:06 +09:00
Alex Shinn
899a6bace3
Merge pull request #824 from nmeum/parse-commit-fk
`(chibi parse)`: allow (optionally) passing custom fk to parse-commit
2022-04-14 10:16:33 +09:00
Sören Tempel
5fe400c688 (chibi parse): allow (optionally) passing custom fk to parse-commit
Without this patch, parse-commit will unconditionally use a faillure
continuation which simply returns `#f`. This may be undesirable in
some situations. As such, this commit allows (optionally) passing
a custom failure continuation as a second argument. If none is passed
the old behavior is used, hence this commit doesn't cause any backwards
incompatible API changes.

See #822
2022-04-11 18:03:24 +02:00
Alex Shinn
b4471ad6fd
Merge pull request #823 from ztzg/diff-term-ansi-call
lib/chibi/diff.scm: Fix string ANSI coloring call
2022-04-11 11:24:23 +09:00
Damien Diederen
1702162e1f lib/chibi/diff.scm: Fix string ANSI coloring call 2022-04-10 22:44:24 +02:00
Alex Shinn
79abb960a4
Merge pull request #821 from nmeum/parse-string-failure-reason
(chibi parse): Ensure reason is always a string
2022-04-10 10:16:47 +09:00
Sören Tempel
1503217e86 (chibi parse): Ensure reason is always a string
While testing a `(chibi parser)`-based parser I noticed that
`parse-string` is the only provided parser combinator which uses a list,
instead of a string, as a failure reason. It is not explicitly
documented but since all other standard parser combinator use a string
for the error reason I assume this to be a bug and have adjusted the
`parse-string` combinator accordingly in this commit.
2022-04-09 10:55:20 +02:00
Alex Shinn
e7486dd7df allow -S<standard> (issue #819) 2022-03-20 10:02:06 +09:00
Alex Shinn
1d8bd4abdb
Merge pull request #818 from dpk/fix-identifier-syntax
Fix definition of full-match? (Proposed fix for #816)
2022-03-17 11:28:54 +09:00
Daphne Preston-Kendal
c28bbbaa98 Fix definition of full-match?
Fixes #816
2022-03-16 09:16:19 +01:00
Alex Shinn
9fe1e69c23 partial fix for issue #816 2022-03-15 23:45:59 +09:00
Alex Shinn
452b9a528d
Merge pull request #805 from dpk/identifier-macros
Identifier macros
2022-03-15 19:48:49 +09:00
Alex Shinn
9d2875b05e
Merge branch 'master' into identifier-macros 2022-03-15 19:47:40 +09:00
Alex Shinn
4382b9d3fd allow syntax-rules to work with reference patterns 2022-03-15 19:06:49 +09:00
Daphne Preston-Kendal
a4ecace600 Revert "Document the addition of identifier macros"
This reverts commit 83f61aecd2.

[skip ci]
2022-03-15 10:33:07 +01:00
Daphne Preston-Kendal
9a0212efff Move identifier-syntax to (chibi ast) 2022-03-15 10:27:56 +01:00
Daphne Preston-Kendal
86e8b56289 Nix er-macro-transformer*, extend syntax-rules for identifier macros 2022-03-15 09:37:52 +01:00
Daphne Preston-Kendal
7a4e793e49 Move make-variable-transformer to (chibi ast) 2022-03-15 09:25:21 +01:00
Daphne Preston-Kendal
01bd50b6f1 Revert "Document the addition of identifier-syntax to core"
This reverts commit 920ba20a8c.
2022-03-15 09:07:17 +01:00
Daphne Preston-Kendal
70455ed3f8 Revert "Implement identifier-syntax in init-7.scm"
This reverts commit d55d6c619c.
2022-03-15 09:07:11 +01:00
Alex Shinn
b32e6e15d0
Merge pull request #806 from dpapavas/make-opcode-procedure
Expose construction of foreign procedures.
2022-03-13 17:12:55 +09:00
Alex Shinn
18e8575358
Merge pull request #813 from dpapavas/export-get-stack
Export sexp_get_stack_trace
2022-03-13 17:10:05 +09:00
Daphne Preston-Kendal
476ae194a3 Indentation fix
[skip ci]
2022-03-03 18:59:04 +01:00
Alex Shinn
c5cfc5cded fix missing newline in test line wrapping output 2022-02-24 22:43:49 +09:00
Alex Shinn
e587881c2c only add a dummy script name argument for the -R usage, not -r (fixes #814) 2022-02-23 07:44:48 +09:00
Alex Shinn
940f315b67 adding missing commit (issue #815) 2022-02-22 20:25:31 +09:00
Alex Shinn
fae48a3790 properly handling negation of complex numbers with ratio parts (fixes issue #815) 2022-02-22 17:55:54 +09:00
Dimitris Papavasiliou
9c5745b7f3 Export sexp_get_stack_trace 2022-02-16 21:59:52 +02:00
Alex Shinn
82d61b3d8e make mixed inexact/exact ordering consistent, converting to exact for fixnums and ratios instead of just bignums (issue #812) 2022-02-12 07:50:58 +09:00
Alex Shinn
eb6a2eeb78 fix integer type in object-cmp 2022-02-12 07:48:14 +09:00
Daphne Preston-Kendal
abda243d21 Add identifier macro tests to syntax-test.scm 2022-02-04 11:28:31 +01:00
Daphne Preston-Kendal
920ba20a8c Document the addition of identifier-syntax to core
[skip ci]
2022-02-04 11:00:27 +01:00
Daphne Preston-Kendal
51b0203dc5 Ditch the syntax-case version of identifier-syntax now it’s in core 2022-02-04 10:40:21 +01:00
Daphne Preston-Kendal
d6b13db503 Attempt to improve readability of syntax-template-transformer uses
Lipstick on a pig, but seems to be the best option available
2022-02-04 10:40:21 +01:00
Daphne Preston-Kendal
aef1a1b358 Use a less confusing term in the error message for invalid clauses
Since ‘template’ is technically the second part
2022-02-04 10:40:21 +01:00
Daphne Preston-Kendal
bddbdc801d Use the exact set! syntactic-closure from the identifier-syntax form
Without this, set! isn’t recognized correctly as a literal and the
set! form erroneously matches any application form with two arguments
2022-02-04 10:39:34 +01:00
Alex Shinn
e4766f8cac Merge branch 'master' of github.com:ashinn/chibi-scheme 2022-02-04 12:35:14 +09:00
Alex Shinn
07358ff8b7 don't allow trailing data after the number in string->number, even if a valid delimiter (fixes issue #811) 2022-02-04 12:34:55 +09:00
Daphne Preston-Kendal
d55d6c619c Implement identifier-syntax in init-7.scm 2022-02-01 11:57:59 +01:00
Alex Shinn
f126c47c3e
Merge pull request #809 from dpapavas/use-malloc
Build fails with SEXP_USE_MALLOC
2022-01-10 08:01:45 +09:00
Dimitris Papavasiliou
c2a0bdb2c6 Partially fix SEXP_USE_MALLOC. 2022-01-09 14:44:02 +02:00
Alex Shinn
a127a332ac use 0 (configurable) for the C++ size of flexible arrays (fixes #808) 2022-01-09 21:29:00 +09:00
Alex Shinn
4d45583637 removing unused sexp_cpointer_body 2022-01-09 21:19:57 +09:00
Alex Shinn
d642f34f25
Merge pull request #807 from lubgr/docs/small-fixes
Minor documentation improvements (C API)
2022-01-07 00:04:53 +09:00
Lukas Böger
1f2b534be9 Small documentation improvements 2022-01-05 12:19:32 +00:00
Daphne Preston-Kendal
d769a7970c Wrap identifier-syntax output in make-transformer 2022-01-03 09:50:07 +01:00
Daphne Preston-Kendal
eb8582f5b1 Use sexp_make_procedure to sexp_make_variable_transformer_op 2022-01-03 08:28:40 +01:00
Dimitris Papavasiliou
87637c0a0b Expose construction of foreign procedures. 2022-01-02 20:45:39 +02:00
Daphne Preston-Kendal
f32d89175c Typo fix.
[skip ci]
2022-01-02 09:37:37 +01:00
Daphne Preston-Kendal
f63348a4d1 Iteratively expand variable-transformer set! 2022-01-02 08:06:38 +01:00
Daphne Preston-Kendal
83f61aecd2 Document the addition of identifier macros 2021-12-30 11:18:39 +01:00
Daphne Preston-Kendal
4a3c7eaf1f Support identifier-syntax in (chibi syntax-case) 2021-12-30 10:58:26 +01:00
Daphne Preston-Kendal
d17764be29 Add variable transformers 2021-12-30 10:34:54 +01:00
Daphne Preston-Kendal
e97a2debe1 Friendlier error message for misuse of standard macros 2021-12-30 00:12:18 +01:00
Daphne Preston-Kendal
770b4d367b Add basic support for identifier macros 2021-12-29 23:52:46 +01:00
Alex Shinn
6615a74609 undoing unintended commit 2021-12-29 14:27:49 +09:00
Alex Shinn
b769a318ef use unsigned char* in sexp_update_string_index_lookup (fixes issue #804) 2021-12-29 11:55:58 +09:00
Alex Shinn
ab29a2b973 skip common prefix/suffix in diff 2021-12-28 16:07:43 +09:00
Alex Shinn
9cd9ec1cda fix mapn error message 2021-12-28 15:19:10 +09:00
Alex Shinn
92499731bc show procedure arity in primitive write 2021-12-28 08:26:20 +09:00
Alex Shinn
fc9cf93796 type checks on identifier=? 2021-12-28 08:19:05 +09:00
Daphne Preston-Kendal
9dcda90e2e Merge branch 'string-ref-cache' into string-ref-cache-backwards 2021-12-27 19:24:20 +01:00
Daphne Preston-Kendal
9419fb19ed Merge branch 'master' into string-ref-cache 2021-12-27 19:13:39 +01:00
Alex Shinn
f6e8e71c41 Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-12-25 10:56:10 +09:00
Alex Shinn
58e9715c2b handle non-positive numbers in numeric/si (fixes issue #801) 2021-12-25 10:55:58 +09:00
Alex Shinn
f812bbc96b
Merge pull request #797 from dpk/reference-barrier
Fix SRFI 124 imports for reference-barrier
2021-12-15 07:01:43 +09:00
Daphne Preston-Kendal
f9f384c45b Fix SRFI 124 imports for reference-barrier 2021-12-14 15:45:12 +01:00
Alex Shinn
50188a6668
Merge pull request #796 from dpk/reference-barrier
Add reference-barrier to (srfi 124)
2021-12-14 21:36:53 +09:00
Daphne Preston-Kendal
2d8ce631c7 Add reference-barrier to (srfi 124) 2021-12-14 13:04:21 +01:00
Alex Shinn
f51f61098c
Merge pull request #795 from ashinn/srfi-227
Fix SRFI 227 exports
2021-12-11 22:42:14 +09:00
Marc Nieper-Wißkirchen
232dc6ef20 Fix SRFI 227 exports 2021-12-11 14:27:20 +01:00
Daphne Preston-Kendal
a746370431 Make the string cursor able to run backwards as well as forwards 2021-12-11 11:43:23 +01:00
Daphne Preston-Kendal
4e0f10ad21 Use the cursor cache to speed up string-cursor->index as well 2021-12-11 10:44:26 +01:00
Daphne Preston-Kendal
c09897c449 Add a feature to cache the most recent string index->cursor result
This is lighter-weight than building a full index->cursor table for
the string, adding a constant two words to the memory required to
store a string, as opposed to one word for every n characters. The
cached cursor is used for any string-ref operation requesting an index
after the most-recently-requested index, making potentially quadratic
repeated string-ref procedures run in linear time. In theory, it could
also use a heuristic to speed up moving backwards through the string
when it thinks that moving the old cursor backwards would be faster
than starting again at the start of the string. In practice, my
logging of when the cached cursor is actually reused during the Chibi
compilation and startup process shows that the most common case of
moving backwards is going back to the start of the string anyway.

Benchmarks to follow.
2021-12-10 21:24:05 +01:00
Alex Shinn
3080087d8c stop after first compile error in an if (fixes #792) 2021-12-05 09:18:54 +09:00
Alex Shinn
9a17254536 guard against opcodes 2021-12-03 08:33:28 +09:00
Alex Shinn
9a48a110b8 add bounds check 2021-12-02 22:07:57 +09:00
Alex Shinn
0da288d053 implement (srfi 229) 2021-12-02 22:03:58 +09:00
Alex Shinn
71cc9b0d3c add make-procedure to (chibi ast) 2021-12-02 22:02:03 +09:00
Alex Shinn
6e636594a5 simplify opt-lambda def; copy list tail for rest arguments 2021-11-25 22:01:59 +09:00
Alex Shinn
f29af14e2e Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-11-25 00:16:56 +09:00
Alex Shinn
1eee928e67 allow non-optional bindings in let-optionals[*] 2021-11-25 00:14:15 +09:00
Alex Shinn
2820aab6e5
Merge pull request #788 from dpk/srfi-227
Add support for SRFI 227
2021-11-24 18:36:58 +09:00
Daphne Preston-Kendal
427629a43e Add support for SRFI 227 2021-11-24 10:24:21 +01:00
Alex Shinn
7a6aae39a0
Merge pull request #787 from arthurgleckler/master
Fix disconnects.  Support more MIME types.  Fix comment.
2021-11-19 16:17:30 +09:00
Arthur A. Gleckler
9b6099ca87 Support more MIME types for common file types.
In `servlet-respond', the server defaults to Content-Type "text/html;
charset=UTF-8" for extensions that don't appear in
`mime-type-from-extension'.  This meant that CSS files, JavaScript
files, and various types of image files were getting the wrong
Content-Type, which was fine when they were served directly, but
caused clients to close the connection when they were loaded over
HTTP/1.1, which can deliver back-to-back resources on the same
connection.

Sort the types in the `mime-type-from-extension' list now that it is
longer.  It's still not long enough for the order to be material for
performance.
2021-11-18 22:09:47 -08:00
Arthur A. Gleckler
153b4d894a Fix typo in comment. 2021-11-18 18:06:40 -08:00
Alex Shinn
4dde693435 http servers should ignore SIGPIPE by default 2021-11-19 10:49:04 +09:00
Alex Shinn
182048ed9a adjust for rounding up converting from fixnum to double in exact-integer-sqrt (fixes #786) 2021-11-08 09:27:50 +09:00
Alex Shinn
a92289ceb9 use return code from main in SRFI 22 usage (fixes #783) 2021-11-07 10:13:49 +09:00
Alex Shinn
7be38e044a
Merge pull request #780 from jpellegrini/srfi-144-fix
Add missing constants to SRFI-144
2021-11-07 09:56:24 +09:00
Alex Shinn
1f0f07114b fix sqrt of complex negative zero (issue #785) 2021-11-07 09:55:24 +09:00
Jeronimo Pellegrini
ce97808201 Add missing constants to SRFI-144
The following constants were missing from Chibi's SRFI-144
implementation:

 fl-1/e
 fl-e-pi/4
 fl-1/log-2
 fl-log-3
 fl-log-pi
 fl-1/log-10
 fl-2pi
 fl-pi-squared
 fl-degree
 fl-gamma-1/2
 fl-gamma-1/3
 fl-gamma-2/3
2021-09-29 00:57:31 -03:00
Lukas Böger
bf881b3e61 Explicitly add -lm and conditionally -lutil/-ldl on linux 2021-09-19 22:18:12 +09:00
Alex Shinn
9e523b6832
Merge pull request #764 from jgesswein/fix-test-runner-indentation
Fix indentation of test runner output
2021-09-06 14:11:54 +09:00
Jürgen Geßwein
e2c8619a21 Implement review comments
Add comment to procedure indent-string to indicate need for a reset for
a second report.

Correct import of (chibi optional).
2021-09-05 13:15:00 +02:00
Alex Shinn
1881116804 enforce order of let-optionals* val/rest binding in non-chibi impl (issue 778) 2021-09-02 12:58:41 +09:00
Alex Shinn
6be3784db0 nitpick (issue #778) 2021-08-30 17:27:33 +09:00
Alex Shinn
08d2847767 explicitly state that it is an error if the default values mutate the let-optionals list (issue #778) 2021-08-30 16:15:57 +09:00
Alex Shinn
22e89b168a fix array-tile 2021-08-19 19:22:29 +09:00
Alex Shinn
57e4652ea6 Assert same domains in array-for-each, as per the spec and implicitly
depended on by the implementation.
2021-08-16 20:28:03 +09:00
Alex Shinn
a14f2d179a rename bare let in case expansion (issue #772) 2021-08-14 00:03:01 +09:00
Alex Shinn
6cafda8916 Decouple syntax-case from the Chibi core.
This restores third-party (ab)users of the Chibi macro system such
as in https://gist.github.com/baguette/2632464, while allowing us
to break those uses in more interesting ways.

It also keeps the core slightly smaller (both in C and Scheme)
and speeds up the macro expansion process.
2021-08-10 23:19:35 +09:00
Alex Shinn
d10ea607e2
Merge pull request #770 from lassik/snprintf
Simplify snprintf usage
2021-08-10 14:19:23 +09:00
Lassi Kortela
3a5f884144 Simplify snprintf usage
snprintf(buf, sizeof(buf), ...) is the canonical idiom.
2021-08-07 23:17:38 +03:00
Jürgen Geßwein
e0497b3084 Implement review comments
Add some newlines and a comment to improve readability.

Use local string port instead of parameterizing current-output-port.

Pass symbol 'BEGIN to tell test reporter that evaluation of a test
starts.  Adapt documentation of current-test-reporter accordingly.

Use define-opt instead of case-lambda.
2021-08-07 21:14:11 +02:00
Alex Shinn
4907d53922 make pid_t and some other POSIX integer types signed (issue #769) 2021-08-04 16:26:11 +09:00
Alex Shinn
f1b8a5bce9
Merge pull request #768 from ashinn/syntax-rules-parser
Parse syntax-rules more strictly
2021-08-04 00:11:58 +09:00
Marc Nieper-Wißkirchen
1f9b4796d6 Parse syntax-rules more strictly
See issue #767.
2021-08-03 17:05:37 +02:00
Alex Shinn
1f508fbdb5 Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-07-28 17:04:36 +09:00
Alex Shinn
18d0adf13b signal error on improper lists passed to map/for-each 2021-07-28 17:00:40 +09:00
okuoku
5de159a72a
Merge pull request #761 from lubgr/cmake-install-target
CMake update 3/3: provide install target
2021-07-28 10:46:45 +09:00
Alex Shinn
9710962cd2 don't assume map works on improper lists in cpp-define 2021-07-28 10:35:05 +09:00
Alex Shinn
7854371728 ensure ffi assertions are a proper list 2021-07-28 10:25:18 +09:00
Alex Shinn
dd05444d91
Merge pull request #763 from lubgr/fix-unused-variable-warning
Triviality: silence an unused variable warning in compiled test
2021-07-25 22:24:24 +09:00
Jürgen Geßwein
b23db00aed Fix indentation of test runner output
Fix standard test runner so that its output is properly indented and
lines are properly terminated.

Refactor standard test runner so that it is possible to plug in another
runner with different output.
2021-07-25 13:21:34 +02:00
Lukas Böger
2e41cf06b2 don't dump images in static library configurations 2021-07-23 22:47:41 +01:00
Lukas Böger
cbf8cfb392 remove unused variable 2021-07-23 22:19:27 +01:00
Lukas Böger
b827cfb429 Build images and .meta lists with ALL target 2021-07-23 22:13:46 +01:00
Lukas Böger
fe953319ff fix dependencies of package list generation command 2021-07-22 21:08:41 +01:00
Alex Shinn
24fb7585c7 set! should guard against exceptions in the var ref lookup (fixes issue #762) 2021-07-22 21:43:50 +09:00
Lukas Böger
cba39c2ede install an EXPORT set and cooperate with find_package 2021-07-21 21:01:33 +01:00
Lukas Böger
7015657c42 add missing template/helper files for install targets 2021-07-21 21:01:33 +01:00
Lukas Böger
2508c61174 install pkgconfig file, too 2021-07-21 21:01:31 +01:00
Lukas Böger
4c1f10e79e don't manually specify default behaviour for file permissions 2021-07-21 21:00:45 +01:00
Lukas Böger
3b5f08c1da install main targets, images and meta lists 2021-07-21 21:00:45 +01:00
Lukas Böger
8eb0961b40 build images and meta package lists 2021-07-21 21:00:45 +01:00
okuoku
879c16c3d9
Merge pull request #758 from lubgr/cmake-lift-platform-restrictions
CMake update 2/3: lift platform restriction
2021-07-22 02:56:00 +09:00
Lukas Böger
527101a1c2 leave the default module path empty on windows 2021-07-21 18:32:23 +01:00
Lukas Böger
47a6e7fd3c streamline library alias name 2021-07-21 18:29:17 +01:00
Lukas Böger
32e7f0bf7e remove unnecessary left-over flags 2021-07-21 18:29:15 +01:00
Lukas Böger
5fcbb7c15c prefer consistent low caps command names 2021-07-20 22:49:30 +01:00
Lukas Böger
a4a8ba0038 remove outdated platform restriction notice 2021-07-20 22:48:37 +01:00
Lukas Böger
287014e3d6 remove exclusion of weak-test, which works on unix 2021-07-20 22:47:03 +01:00
Lukas Böger
0ae8069a07 fix repeated liblib prefix in library output name 2021-07-20 15:37:56 +01:00
Lukas Böger
699ffe18e9 mostly revert module path handling introduced in 27c421e3
chibi/install.h is included in C source files, and providing a different
install.h upon actual installation is inconsistent and dangerous. When
working with a chibi executable within the build tree (i.e., not an
installed executable), the CHIBI_MODULE_PATH environment tweak can be
used to not always specify -I paths on the command line.
2021-07-20 15:37:56 +01:00
Lukas Böger
16b97a6e26 reduce scope of clib.c within the chibi library 2021-07-20 15:37:56 +01:00
Lukas Böger
e2555e5fed fix paths of includes in clib.c
With the module search path cleverly handled with different install.h
configurations, the genstatic script inserted absolute paths into the
generated clib.c file. This didn't fail on Windows CI as this is an
in-source build. For out-of-source builds, it's crucial that clib.c can
refer to both .c files in the source directory and those generated in
the build directory. As a fix, the genstatic invocation now uses the -I
flag.

This patch also improves the handling of include paths to find the .c.
files mentioned above by trimming down the scope of this property to
clib.c only. Also, there is no need to manually tell the preprocessor
where to look for generated .c, as they live relative to clib.c anyhow.
2021-07-20 15:37:56 +01:00
Lukas Böger
7de835bad8 improve module path handling and provide basic installation 2021-07-20 15:37:56 +01:00
Lukas Böger
86c439a4bb enable more tetst on unix builds 2021-07-20 15:37:56 +01:00
Lukas Böger
fcfd518a0d leave selected zero feature macros undefined 2021-07-20 15:37:56 +01:00
Lukas Böger
9c22b7d1c2 comply with older CMake versions (dependency graph) 2021-07-20 15:37:56 +01:00
Lukas Böger
de4fa6439a use bootstrap exec only for static builds 2021-07-20 15:37:56 +01:00
Lukas Böger
f58dfdb67d shorten sanitizer configuration 2021-07-20 15:37:56 +01:00
Lukas Böger
57410deca9 fix string stream config on windows 2021-07-20 15:37:56 +01:00
Lukas Böger
15be953446 fix missing variable dereferencing syntax 2021-07-20 15:37:56 +01:00
Lukas Böger
46fbc423d3 shorten preprocessor configuration 2021-07-20 15:37:56 +01:00
Lukas Böger
9652d08ae3 reorganize linking of common configuration library 2021-07-20 15:37:56 +01:00
Lukas Böger
1b960f949f add module search path to test runs 2021-07-20 15:37:56 +01:00
Lukas Böger
d06d56154e replace custom function with target_link_libraries 2021-07-20 15:37:56 +01:00
Lukas Böger
82aa16a3f1 compile shared libraries for non-static configurations 2021-07-20 15:37:56 +01:00
Lukas Böger
17ffa4b36c use sensible default module paths for Linux/Unix 2021-07-20 15:37:56 +01:00
Lukas Böger
0bade8de2f refactor library generation from stubs 2021-07-20 15:37:56 +01:00
Lukas Böger
2efcc53098 compile shared libraries for non-static builds 2021-07-20 15:37:56 +01:00
Lukas Böger
3b33a9561a add SEXP_USE_BOEHM configuration option 2021-07-20 15:37:56 +01:00
Lukas Böger
584bfa225c mimic Makefile's option for cygwin build 2021-07-20 15:37:56 +01:00
Lukas Böger
b8a3500222 build with -Wall when using clang or gcc 2021-07-20 15:37:56 +01:00
Lukas Böger
36f7d86cad fix CMake 3.12 list(REMOVE ...) invocation 2021-07-20 15:37:56 +01:00
Lukas Böger
d7c28021c8 set default build type, add sanitizer build support 2021-07-20 15:37:56 +01:00
Lukas Böger
e9391c93fb mimic Makefile's ntp and stdint conditional compilation 2021-07-20 15:37:56 +01:00
Lukas Böger
434a36f0b9 remove error on apple/unix and set platform string 2021-07-20 15:37:56 +01:00
Alex Shinn
83aefd12d0 Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-07-19 21:49:57 +09:00
Alex Shinn
5b8e196e0f parse-seq should check for ignored value in fast paths as well (issue #757) 2021-07-19 21:49:39 +09:00
Alex Shinn
2d21500185 updating copyright year 2021-07-19 21:48:47 +09:00
Alex Shinn
31921b4553
Merge pull request #755 from lubgr/cmake-modernization
CMake update 1/3: basic modernization (preserving all current functionality)
2021-07-19 09:48:38 +09:00
Lukas Böger
92d5f8eae1 apply static flag for bootstrap exec, too
This is required for the Windows configuration to succeed at all. It
should also be beneficial when we start sharing object code between
bootstrap and actual executable.
2021-07-13 14:03:24 +01:00
Lukas Böger
0f1dfad91c eliminate last global flag, move library definition 2021-07-13 14:03:24 +01:00
Lukas Böger
b0c0afcb73 prefer configure_file over manual file(WRITE ...) 2021-07-13 14:03:24 +01:00
Lukas Böger
514d58264f Use builtin variable for shared object suffix 2021-07-13 14:03:24 +01:00
Lukas Böger
2f663dff33 fix repeated target_link_libraries on bootstrap target 2021-07-13 14:03:24 +01:00
Lukas Böger
7595ecbc09 replace more global commands by target-based ones 2021-07-13 14:03:24 +01:00
Lukas Böger
4b5ebffa5b build static libs by default on windows 2021-07-13 14:03:24 +01:00
Lukas Böger
9fab5cf4dd generate and add clibs.c only for static builds 2021-07-13 14:03:24 +01:00
Lukas Böger
5402d86323 remove trailing whitespace 2021-07-13 14:03:24 +01:00
Lukas Böger
7c46c618d0 don't build bootstrap exec by default
This doesn't necessarily have an effect though, as we need the
bootstrapping executable anyhow for building other targets.
2021-07-13 14:03:24 +01:00
Lukas Böger
f6e67edf01 export compilation database 2021-07-13 14:03:24 +01:00
Lukas Böger
4cc384ecac use VERSION file for project settings and lib output 2021-07-13 14:03:24 +01:00
Lukas Böger
b603e04d9e align library name with build artifact 2021-07-13 14:03:24 +01:00
Lukas Böger
76bce1ce1c prefer CMake's builtin BUILD_SHARED_LIBS option 2021-07-13 14:03:23 +01:00
Lukas Böger
eb6c9db857 use unversioned library basename 2021-07-13 14:03:23 +01:00
Lukas Böger
c79145b051 require CMake version >= 3.12 2021-07-13 14:03:23 +01:00
Lukas Böger
3c6ce4e23b don't ignore CMakeLists.txt 2021-07-13 14:03:23 +01:00
Alex Shinn
c05e820d71 adding contributing file 2021-06-30 18:35:24 +09:00
Alex Shinn
77365ccc6f
Merge pull request #752 from wrog/math_prime_fixes
(chibi math prime) fix miller-rabin-composite?, factor, etc (issue #751), add factor-alist
2021-06-30 18:25:30 +09:00
Roger Crew
3337049811 shorter factor (issue #751 cont.) 2021-06-30 00:29:54 -07:00
Roger Crew
2759aaa306 add factor-alist and export it (chibi math prime)
a more useful version of factor
2021-06-29 23:48:12 -07:00
Roger Crew
680aede9ae totient and aliquot rewrite + corrected tests for n=1 (issue #751 cont.) 2021-06-29 23:48:12 -07:00
Roger Crew
b89bd9f889 faster factor, (factor 1) = () (issue #751 cont.)
no need to go up to sqrt(n), Instead track i^2 and quit when that gets
larger than the (remaining) n (i.e., not the original n)
2021-06-29 23:48:12 -07:00
Roger Crew
41aa1a918e miller-rabin-composite? rewrite (issue #751)
modular-root-of-one? is replaced with the correct witness tester
2021-06-29 23:48:09 -07:00
Roger Crew
7d39108e72 factor-twos cps version using first-bit-set
first-bit-set is way faster than looping
2021-06-29 23:43:53 -07:00
Alex Shinn
73da0a88d4 scan for appropriate 2nd element to take the mean with when calling vector-find-median on an even length vector (issue #754) 2021-06-29 21:09:41 +09:00
Alex Shinn
f3bccf1f7b removing unintended export 2021-06-28 17:31:14 +09:00
Alex Shinn
378b56a0c3 adding opt-lambda* and define-opt* 2021-06-28 17:27:22 +09:00
Alex Shinn
0fbd89dd00 ignore keywords in non-keyword positions (issue #753) 2021-06-28 16:19:43 +09:00
Alex Shinn
05c546e38d match fix for (a ...) patterns where a was already bound - thanks to Andy Wingo 2021-06-21 16:44:02 +09:00
Alex Shinn
5207bdfde2 Defining list->u8vector (issue #749). 2021-06-18 13:04:20 +09:00
Alex Shinn
ead366870b
Merge pull request #747 from ilammy/sign-bit
Fix usage of signbit() in SRFI 144
2021-06-06 13:59:13 +09:00
Alexei Lozovsky
6f35aa75f4
Fix usage of signbit() in SRFI 144
C standard defines signbit() as a macro returning "non-zero value" for
negative arguments (see 7.12.3.6 of C11 standard). SRFI 144's flsign-bit
is defined to return exactly 1.

Make sure to convert the result of signbit() call into "boolean int"
which is either 0 or 1.

This is not a theoretical issue. This causes SRFI 144 test suite to fail
on many architectures that are not x86_64.

GCC on x86_64 compiles signbit() as

        movmskpd %xmm0, %eax
        andl     $1, %eax

which indeed returns either 0 or 1. movmskpd extracts 2-bit sign mask
from the FP value in src register and stores that in low-order bits of
the dst register. Then the unneded extra bit is masked out, leaving only
the lowest bit set or unset.

However, other architectures don't have such conveniences and go with
more direct approach. For example, GCC on ARMv7 produces this:

        sub     sp, sp, #8
        vstr.64 d0, [sp]
        ldr     r0, [sp, #4]
        and     r0, r0, #0x80000000
        add     sp, sp, #8
        bx      lr

which effectively returns either 0 or -1. Generated code masks out
everything but the sign bit and returns the result as is. The value
0x80000000 is the representation of -1.

Even on i386 signbit() is compiled as

        fldl    4(%esp)
        fxam
        fnstsw  %ax
        fstp    %st(0)
        andl    $512, %eax
        ret

which effectively returns either 0 or 512: fxam sets C1 bit FPU status
word to the sign of FP value, then the status word is extracted, the
"sign bit" is masked out, and left as is.
2021-06-06 13:49:44 +09:00
Alex Shinn
d9f5eaac61
Merge pull request #748 from ilammy/ffi-failures
Initialize variables in FFI tests
2021-06-06 13:43:09 +09:00
Alexei Lozovsky
cc23efac16
Initialize variables in FFI tests
These ones are used to compute averages. If they are not initialized to
zero, they might contain some garbage. In fact, they almost always do
on platforms other that x86_64, failing the FFI tests. If optimizations
are enabled, these tests usually fail on x86_64 too. The reason this
went unnoticed is contrived set of coincidences.
2021-06-06 11:19:52 +09:00
Alex Shinn
5610653c20 servlets should assume html if no Content-Type is specified 2021-05-28 12:07:23 +09:00
Alex Shinn
0388d9880c Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-05-26 10:06:00 +09:00
Alex Shinn
8247e13baf remove superfluous + when printing complex numbers with negative ratio imaginary parts 2021-05-26 10:05:40 +09:00
Alex Shinn
fa59b289a6
Merge pull request #746 from lubgr/small-doc-fix-on-static-executable
Fix documentation on building a standalone statically linked executable including compiled libs
2021-05-25 11:37:28 +09:00
Lukas Böger
6ffba28b02 use SEXP_USE_STATIC_LIBS_NO_INCLUDE for static build 2021-05-24 22:42:21 +01:00
Alex Shinn
05ca40fa51 chibi doc fixes for irregex manual 2021-05-14 13:49:07 +09:00
Alex Shinn
4a06997978 guard against failed module-ref 2021-05-13 22:10:30 +09:00
Alex Shinn
f817dbaf96 emphasize not to use emmake directly 2021-05-12 08:28:55 +09:00
Alex Shinn
05eb4ebd35 installing SRFI 179 2021-05-11 00:06:24 +09:00
Alex Shinn
f84ddfc02e bumping version 2021-05-10 23:30:26 +09:00
Alex Shinn
89a77540b4 put system module path in front of user module path 2021-05-10 23:24:18 +09:00
Alex Shinn
6c522cc04b package srfis with tests 2021-05-10 23:14:43 +09:00
Alex Shinn
037a7b24fc exporting array-coeffs 2021-05-10 22:56:36 +09:00
Alex Shinn
7b2fbb0bf2 fixing ffi doc extraction for cond-expanded procedures 2021-05-10 18:40:33 +09:00
Alex Shinn
64633d577c adding assert docs 2021-05-10 17:57:06 +09:00
Alex Shinn
3eab7bf226 package SRFI 179 2021-05-10 17:49:02 +09:00
Alex Shinn
6e5278b7a1 separating out SRFI 179 base library 2021-05-07 22:39:53 +09:00
Alex Shinn
ca47a41ccf array simplification and performance tweaks 2021-05-07 16:15:48 +09:00
Alex Shinn
12ad1d37d8 add docs and tests for assert, unify with SRFI 145 2021-05-06 20:34:03 +09:00
Alex Shinn
e3782e35a5 add note about emscripten build 2021-05-06 20:31:29 +09:00
Alex Shinn
249f4f21ba allow tracing macros 2021-05-06 10:17:03 +09:00
Alex Shinn
68a81c8aff typo for non-threads build (issue #731) 2021-05-05 21:14:22 +09:00
Alex Shinn
1db8a573f1 more extensive list of constructs not to descend into 2021-05-05 08:08:12 +09:00
Alex Shinn
9a9f974d69 assert improvements: dedup vars, ignore lambdas, allow report: 2021-05-05 07:56:14 +09:00
Alex Shinn
d5a0f0ddfa
Merge pull request #744 from pclouds/emscripten-shared-flag
Fix emscripten build
2021-05-05 07:14:35 +09:00
Nguyễn Thái Ngọc Duy
12fa4ae601 Fix emscripten build
It looks like the original -shared is ignored for some reason, so emcc
produces the final .wasm and .js code, the latter is named
chibi-scheme-static.bc, which cannot be linked to create
chibi.js. Moving -shared to STATICFLAGS seems to fix that.

I'm new to emscripten so don't trust me too much on this. But I tested
chibi.js and things still seem to work fine.
2021-05-04 18:53:53 +07:00
Alex Shinn
91f26c5313
Merge pull request #743 from pclouds/chibi-b-opt
chibi-scheme.1: document -b
2021-05-04 20:41:40 +09:00
Nguyễn Thái Ngọc Duy
27adc08ba6 chibi-scheme.1: document -b
It's added in fad9e4ca (don't make stdio nonblocking by default, allow
override with -b, 2017-05-07)
2021-05-04 18:06:06 +07:00
Alex Shinn
4df0513d6e
Merge pull request #741 from phillbush/master
Fix typo in comment.
2021-05-03 22:54:47 +09:00
phillbush
681f781208 it's /usr/bin/env 2021-05-02 21:52:21 -03:00
Alex Shinn
e3083062fa Flattening indexing further.
We can pre-subtract each coeff times its lower bound from the
base coefficient in SRFI 179 indexers.
2021-04-30 14:25:39 +09:00
Alex Shinn
d11106b2f7 Fix upper bounds checks in u64vectors. 2021-04-30 14:02:29 +09:00
Alex Shinn
3c138dc808 Fix validation on specialized-array-reshape. 2021-04-30 13:38:53 +09:00
Alex Shinn
76284f79f0 flattening array indexers 2021-04-28 22:53:16 +09:00
Alex Shinn
bf03c1cfa1 restore sexp_make_ephemeron even when not unifying filenos 2021-04-27 19:11:36 +09:00
Alex Shinn
4d22949f71 disable fileno unification by default 2021-04-27 18:30:43 +09:00
Alex Shinn
8fcd4d1f88 remove spurious debug code 2021-04-27 15:50:22 +09:00
Alex Shinn
3cf62f033a store stack traces directly in top-level exceptions to more consistently be able to report them from C 2021-04-26 21:40:39 +09:00
Alex Shinn
ef9daf22c8 handle include-shared in analyze-module 2021-04-26 14:27:11 +09:00
Alex Shinn
42aab7905c enable SEXP_USE_STRICT_TOPLEVEL_BINDINGS by default (issue #699) 2021-04-19 10:46:26 +09:00
Alex Shinn
8b3f5512e1 Merge branch 'master' of github.com:ashinn/chibi-scheme 2021-04-19 10:22:08 +09:00
Alex Shinn
d53bf51fc9 don't assume EOF < 0x80 (issue #731) 2021-04-19 10:22:00 +09:00
Alex Shinn
cd5bf03537
Merge pull request #740 from lassik/219
Add SRFI 219: Define higher-order lambda
2021-04-18 18:58:39 +09:00
Lassi Kortela
7178d22928 Add SRFI 219: Define higher-order lambda 2021-04-18 12:21:32 +03:00
Alex Shinn
ade90906f9 only reify a fileno from an integer if the fileno is still open 2021-04-18 07:01:10 +09:00
Alex Shinn
d0510bebe6 simplify array-reduce 2021-04-16 23:35:16 +09:00
Alex Shinn
c8f5f49890 add initial SRFI 179 implementation 2021-04-16 19:53:51 +09:00
Alex Shinn
487ea21d77 check value domains on uvector-set! ops 2021-04-16 10:13:37 +09:00
Alex Shinn
d64f159608 fix docs on test-group 2021-04-16 10:10:18 +09:00
Alex Shinn
af43c3214f add sexp_user_exception_ls variadic convenience 2021-04-16 10:06:03 +09:00
Alex Shinn
fc6e5da915 make-u1vector takes an optional fill 2021-04-15 17:02:44 +09:00
Alex Shinn
e74614d4b3 removing redundant uvector definitions 2021-04-14 17:06:34 +09:00
Alex Shinn
cfbd64f085 fixing bug in prime-above 2021-04-14 16:47:29 +09:00
Alex Shinn
3fc9c22245 fix regression from shadowed bindings in process->output+error+status 2021-04-09 23:09:53 +09:00
Alex Shinn
4bd4f08b59 fix longstanding todo and get signature from analyzed procedure forms 2021-04-08 23:00:12 +09:00
Alex Shinn
8c45c3fb19 better text display 2021-04-08 22:59:34 +09:00
Alex Shinn
e3078a7c4c start lambda source info at bytecode pos -1 2021-04-08 22:59:18 +09:00
Alex Shinn
d69ffce3f2 sexp_bytecode_source should always be taken from the lambda
This is taken from the read source of the lambda form itself.
Previously it was getting the source of the expanded first expression,
which more often than not was the let definition in init-7.scm
2021-04-08 10:09:58 +09:00
Alex Shinn
f7b546769c update logging tests for fixes in string-split 2021-04-08 10:08:19 +09:00
Alex Shinn
8b27ce9726 add proper grammar support to srfi 130 string-split 2021-04-02 13:51:02 +09:00
Alex Shinn
d80589144d close stdout/err in process->foo utilities
Relying on gc can accumulate many open fd's,
which is bad for code outside of chibi.
2021-03-31 09:23:21 +09:00
Alex Shinn
7ea15f3810 check for wrapping to negative in hash lookup of cell (issue #735)
Without this chibi can crash after 129 open file descriptors.

Note the bug referenced would also indirectly be fixed if
process->string-list properly closed its ports, but we
shouldn't rely on that.
2021-03-31 06:43:27 +09:00
Alex Shinn
13a2a562d9 forgot to specify literals 2021-03-28 23:43:49 +09:00
Alex Shinn
26d3a010df adding assert macro 2021-03-26 23:12:37 +09:00
Alex Shinn
adec61993b adding domain checks on uvector accessors 2021-03-26 17:34:25 +09:00
Alex Shinn
70af1d6394 Friendlier error for bad trace command (issue #733). 2021-03-23 12:13:09 +09:00
Alex Shinn
969f24db96
Merge pull request #722 from flynn162/patch-1
Typo in the documentation
2021-03-04 19:31:09 +09:00
Alex Shinn
2d562bdae1
Merge pull request #730 from smazga/plan9
make 9front "work" again by properly handling 64-bit typedefs
2021-02-21 10:10:46 +09:00
McKay Marston
683554c2ab make 9front "work" again by properly handling 64-bit typedefs 2021-02-20 17:10:43 -07:00
Alex Shinn
de02feb8ff
Merge pull request #729 from lassik/srfi-193
Add SRFI 193 Scheme library
2021-02-05 21:36:20 +09:00
Lassi Kortela
fa52b4987a Add SRFI 193 Scheme library
This was accidentally left out of the previous commit.
2021-02-05 14:08:31 +02:00
Alex Shinn
08a7ec736c
Merge pull request #728 from lassik/command-lines
Re-implement SRFI 193 (Command line)
2021-02-04 23:00:31 +09:00
Lassi Kortela
ac698ce6ae Re-implement SRFI 193 (Command line) 2021-02-01 21:29:26 +02:00
Alex Shinn
19228cbfb8 cleaning up more dirs on uninstall (issue #725) 2021-01-25 11:07:48 +09:00
Alex Shinn
b2bd44eaf0
Merge pull request #724 from ashinn/revert-619-command-lines
Revert "Implement SRFI 193: Command lines"
2021-01-24 19:58:13 +09:00
Alex Shinn
9f0ed1a869
Revert "Implement SRFI 193: Command lines" 2021-01-24 19:57:55 +09:00
Alex Shinn
751675c6b2
Merge pull request #619 from lassik/command-lines
Implement SRFI 193: Command lines
2021-01-24 16:44:35 +09:00
Alex Shinn
e53d79adfd
Merge pull request #723 from lassik/typo
Fix typo
2021-01-18 09:44:53 +09:00
Lassi Kortela
0be78ed7e6 Fix typo 2021-01-17 14:10:41 +02:00
Flynn Liu
0ccfb57833
Typo in the documentation 2021-01-10 14:13:01 -08:00
Alex Shinn
1828ef068e fix env size (issue #453) 2020-12-28 12:07:54 +09:00
Alex Shinn
b4dd757e3f more consistently setting renames (issue #453) 2020-12-28 11:55:10 +09:00
Alex Shinn
4edf3344f8
Merge pull request #721 from ilammy/aliasing-issues
Fix unaligned access in bytevector-{u,s}{16,32,64}-{ref,set!}
2020-11-30 20:11:54 +09:00
Alexei Lozovsky
266a188ce2
More tests for unaligned bytevector access
Make sure that we don't miss anything and cover the rest of bytevector
accessors with tests for unaligned memory access. Include both integers
and floats, in little and big endian flavors.
2020-11-30 17:15:57 +09:00
Alexei Lozovsky
af60b8d937
Fix unaligned access in bytevector-{u,s}{16,32,64}-{ref,set!}
Native code implementing bytevector accessors uses the following access
pattern:

    *(intNN_t*)(base+offset)

This can result in so called "unaligned memory access" if the offset is
not a multiple of 2, 4, 8, or if the base address has not been allocated
at an aligned address (unlikely).

Most popular modern architectures--x86 and ARMs--allow unaligned memory
accesses on the instruction level but they are typically performed a bit
slower than properly aligned accesses.

On the other hand, there are architectures which do not allow unaligned
memory accesses. Each load or store of a value longer than 1 byte should
use properly aligned address on those architectures. That is, u16 should
be loaded from even addresses, s32 should only be stored at an address
which is a multiple of 4, and f64 (aka double) can be located only at
addresses which are multiple of 8. If the address is not aligned, CPU
raises an exception which typically results in the process being killed
by the operating system with a SIGBUS signal.

SPARC is one of those architectures which are strict with alignment. The
current access pattern in bytevector native code can result in unaligned
accesses, which in turn results in crashes. This issue has been found in
this way: Chibi test suite includes some tests for unaligned accesses
and it failed on SPARC.

In order to avoid unaligned accesses, loads and stores need to be
performed a bit differently, doing 'type punning' in a safe way, not
just casting pointers which breaks strict aliasing rules.

The most portable and efficient way to do this is to use memcpy().
Compilers know about this trick and generate very efficient code here,
avoiding the function call and using the most efficient instructions.
(Obviously, only when optimizations are enabled.)

That is, given

    static inline uint32_t ref_u32(const void* p) {
      uint32_t v;
      memcpy(&v, p, sizeof(v));
      return v;
    }

on x86 this will be compiled into a single "movl" instruction because
x86 allows unaligned accesses, similar with ARM where this becomes
a single "ldr" instruction. However, on RISC-V--another platform with
strict alignment rules--this code compiles into 4 "lbu" instructions
fetching 4 bytes, then some more arithmetic to stitch those bytes into
a single 32-bit value.
2020-11-30 16:46:44 +09:00
Alex Shinn
3f228ce731
Merge pull request #716 from amirouche/fix/emscripten-build
Makefile: js: fix build for emscripten 2.0.8.
2020-11-30 13:51:43 +09:00
Alex Shinn
a3afe4e804 don't change dir when generating images (issue #707) 2020-11-25 23:26:18 +09:00
Alex Shinn
56a31f9cb0 don't declare image loading operations if not enabled (issue #714) 2020-11-25 23:16:12 +09:00
Alex Shinn
f9c00e0c21
Merge pull request #713 from mnieper/and-let
Fix and-let* so that it allows bodies according to SRFI 2.
2020-11-25 14:40:16 +09:00
Alex Shinn
0597ea68a5
save a char and a beta reduction 2020-11-25 14:39:49 +09:00
Alex Shinn
54f55569e2 document sexp_lookup_type (issue #718) 2020-11-25 14:36:54 +09:00
Alex Shinn
79e76b295f Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-11-19 13:14:17 +09:00
Alex Shinn
181b7fe7e4 preserve exactness in sqrt of ratios where possible 2020-11-19 13:13:37 +09:00
Alex Shinn
841a8a3167
Merge pull request #717 from bjoli/patch-1
Fix bug in accumulating in (chibi loop)
2020-11-04 21:12:42 +09:00
Linus Björnstam
c896bf90c5
Fix bug in accumulating in (chibi loop)
Accumulating has a bug that makes only lists supported, due to it ignoring the init value and always use the empty list. This fixes that.
2020-11-04 11:56:41 +01:00
Amirouche
f13c826da0 Makefile: js: fix build for emscripten 2.0.8.
$ emcc --version
emcc (Emscripten gcc/clang-like replacement) 2.0.8 (d059fd603d0b45b584f634dc2365bc9e9a6ec1dd)
2020-11-02 11:20:35 +01:00
Marc Nieper-Wißkirchen
306dbd470a Fix and-let* so that it allows bodies according to SRFI 2. 2020-10-22 15:13:04 +02:00
Alex Shinn
12636f4b19
Merge pull request #711 from woodfinisc/patch-1
Fix a typo in README.md
2020-10-17 06:57:39 +09:00
Alex Shinn
b6186d1272
Merge pull request #710 from gahr/freebsd-versioned-so
Produce a versioned so on FreeBSD
2020-10-17 06:41:17 +09:00
Tom Woodfin
0f5f9e3117
Fix a typo in README.md
seemless => seamless
2020-10-16 15:09:29 -04:00
Pietro Cerutti
f48312fad3 Produce a versioned so on FreeBSD 2020-10-16 13:10:58 +00:00
Alex Shinn
30b575debe
Merge pull request #709 from gahr/doc-depends-on-so
Building docs depends on having the shared libraries available
2020-10-14 22:10:09 +09:00
Pietro Cerutti
f85c1a3545 Building docs depends on having the shared libraries available
This unbreaks compiling with multiple make jobs.
2020-10-14 10:06:56 +00:00
Alex Shinn
568206041a Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-10-11 21:31:57 +09:00
Alex Shinn
4e1ff91cbb patch for plan9 build from raingloom 2020-10-11 21:31:42 +09:00
Alex Shinn
3334957956
Merge pull request #708 from pclouds/document-getenv
chibi-scheme.1: document CHIBI_IGNORE_SYSTEM_PATH
2020-10-02 23:00:34 +09:00
Nguyễn Thái Ngọc Duy
78e381ae7d chibi-scheme.1: document CHIBI_IGNORE_SYSTEM_PATH
while at there, spell out the empty CHIBI_MODULE_PATH case. It's obvious
if you really think about it, but it's even better if I don't have to
read between the lines.

I did grep getenv to find if anything was missing. There is
CHIBI_MAX_ALLOC, but I think that one is more about debugging
out-of-memory than to be customized by the user.
2020-09-30 16:15:54 +07:00
Alex Shinn
77aab98784 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-09-22 17:37:33 +09:00
Alex Shinn
4ef6c57d3e propagating #i prefix across radix prefixes (issue #706) 2020-09-22 17:37:22 +09:00
Alex Shinn
7448c22466
Merge pull request #705 from laserswald/fix-arithmetic-exception-filenos
Prevent arithmetic exception when spawning lots of commands
2020-09-19 13:20:39 +09:00
Ben Davenport-Ray
9278222396 Prevent crashing from arithmetic exception when spawning lots of commands
This fix is rather dumb, but it prevents things from crashing when
forking a lot and creating file handles. I assume that this is where
the filehandles go, but I don't have a good guess.
2020-09-18 17:08:25 -04:00
Alex Shinn
993a6469fe fix a ... match pattern when a is already bound 2020-09-06 22:59:42 +09:00
Alex Shinn
9c6020e22d
Merge pull request #702 from pclouds/snow-confirm-before-upload
snow: confirm before uploading packages
2020-09-05 13:21:34 +09:00
Nguyễn Thái Ngọc Duy
f4008c92cf snow: add TODO regarding summary before upload 2020-09-05 09:31:29 +07:00
Nguyễn Thái Ngọc Duy
711c89cd97 snow: confirm before uploading packages
Uploading a package is an irreversible operation. It's not even about
accidentally leaking your secret sauce to the internet. You could upload
a package to snow-fort.org by accident and pullute the package name
space [1].

So let's ask the user first before going ahead uploading stuff. We only
ask once even if we're going to upload a dozen packages, so it's not
that annoying. The target repo is also shown in case you want to upload
to a custom repo and want to make sure it does so.

[1] I did (while attempting to uploading to a local snow-fort instance
    during testing). I guess `(chibi snow commands)` is forever mine
    now.
2020-09-04 19:25:29 +07:00
Alex Shinn
645bf03749 change match names to SRFI 204 2020-09-04 18:33:25 +09:00
Alex Shinn
c82baa3aa9 ignore snow package meta files whose installed files have been removed 2020-09-04 14:04:53 +09:00
Alex Shinn
64ff69e99b include chibi.repl in images 2020-09-03 21:51:04 +09:00
Alex Shinn
d0bd93822e specify encoding meta for docs, include doctype 2020-09-02 15:52:20 +09:00
Alex Shinn
8597c3eda5 better error handling in http-server request parsing 2020-09-02 11:53:49 +09:00
Alex Shinn
24d1f6a8a5 fix not+and combo (issue #701) 2020-09-02 10:01:28 +09:00
Alex Shinn
24b1e5024c
Merge pull request #700 from pclouds/tests-without-chibi-test
make optional-test and diff-test run without (chibi test)
2020-09-01 23:00:19 +09:00
Nguyễn Thái Ngọc Duy
65a1eba878 make optional-test and diff-test run without (chibi test)
Tested with gauche. It's mostly about not importing (chibi test)
unconditionally, and importing (scheme write). And in one case I need to
exclude some tests because gauche catches invalid call forms at compile
time. I'm not sure if that can be caught...
2020-09-01 20:55:03 +07:00
Alex Shinn
e5cf364360 forgot to wrap inline cond-expand defs in begin 2020-09-01 22:27:59 +09:00
Alex Shinn
e7e034dea0 fix previous fix, fk needs to be made cheap, not sk (issue #698) 2020-09-01 17:01:27 +09:00
Alex Shinn
717aeb9e8b fix combinatorial explosion in match-not (issue #698) 2020-09-01 16:38:42 +09:00
Alex Shinn
29df4211ee fix circular expansion (issue #697) 2020-09-01 16:25:00 +09:00
Alex Shinn
9433b8b912 doc style tweaks 2020-09-01 10:59:44 +09:00
Alex Shinn
f6bd8b6266 fix inlined (chibi test) lite 2020-09-01 10:59:25 +09:00
Alex Shinn
217baeeb57 avoid cyclic test deps in snow 2020-08-31 21:52:01 +09:00
Alex Shinn
c0f632504b
Merge pull request #696 from pclouds/snow2-documents
Snow documentation improvements
2020-08-31 21:44:25 +09:00
Nguyễn Thái Ngọc Duy
5833240e34 Snow documentation improvements
This clarifies a bit about some commands, or a few interesting command
line options from my experience with chibi-snow (which is to use it for
another scheme implementation, or separate host from snow-fort.org; but
the latter is mostly for testing)
2020-08-31 18:32:19 +07:00
Alex Shinn
1d21a90275 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-08-31 17:28:43 +09:00
Alex Shinn
6c8bf386ec fixing multi-level menu nesting plus some doc css tweaks 2020-08-31 17:28:12 +09:00
Alex Shinn
8c9a40a7e4
Merge pull request #694 from lubgr/small-doc-fixes
Small documentation fixes
2020-08-31 08:36:53 +09:00
Lukas Böger
922b73b024 Sync documented \var and actual parameter name
The procedure parameter name could equally well be changed from `id` to
`proc`. Not sure which approach is more suitable - here, I chose to
stick to the original procedure signature.
2020-08-30 11:23:17 +01:00
Lukas Böger
2dcf2f0584 Fix broken link to SRFI 188 2020-08-30 11:22:46 +01:00
Lukas Böger
a3a0e67365 Add (chibi optional) to listed library docs 2020-08-30 11:21:40 +01:00
Marc Nieper-Wißkirchen
251464eade Translate assume to a noop when assumptions are disabled 2020-08-29 11:11:46 +02:00
Marc Nieper-Wißkirchen
043e4c2214 Fix generator-find 2020-08-29 10:25:23 +02:00
Alex Shinn
41ba06aa5a
Merge pull request #691 from pclouds/snow-impl-features
snow: extract feature list for cond-expand
2020-08-28 22:48:14 +09:00
Alex Shinn
1413cd1630
Merge pull request #692 from barak/master
typo: s/searchs/searches/
2020-08-28 22:46:52 +09:00
Barak A. Pearlmutter
d7a06322ec typo: s/searchs/searches/ 2020-08-28 12:52:46 +01:00
Nguyễn Thái Ngọc Duy
b52b2024f8 snow: extract feature list for cond-expand
Currently a package's cond-expand contains the symbol of the target
implementation and optionally more from config file. Execute a
command (once) on target implementation to add their full feature list,
making it available for each package to use.

All of these Schemes are tested. Larceny is just too annoying to get the
feature list (no one-liner, and it could take a while) so Larceny stays
the current behavior.

There is a small unrelated change here: the gosh command to get
version. We don't need to call (exit), if stdin is closed properly (it
should) then gosh should exit regardless.
2020-08-28 16:30:00 +07:00
Alex Shinn
a7a115323c s/dist-clean/dist-clean/ 2020-08-28 11:40:52 +09:00
Alex Shinn
b4d2370713 allow either prefix or PREFIX 2020-08-28 09:58:08 +09:00
Alex Shinn
f343708f1f use gnu coding standard make path var names 2020-08-27 22:56:57 +09:00
Alex Shinn
8a6af941ad enforce bound-identifier=? for match rewrite 2020-08-27 17:06:51 +09:00
Alex Shinn
9793fa0edf inc fileno count on sexp_make_input_port (issue #690) 2020-08-27 10:23:56 +09:00
Alex Shinn
5860a65368 track head ids in ellipsis tail 2020-08-26 17:24:38 +09:00
Alex Shinn
dda71763a5 fixing or patterns with different ids in branches 2020-08-26 16:07:52 +09:00
Alex Shinn
11852c6390 don't rewrite quote 2020-08-25 16:09:38 +09:00
Alex Shinn
9d65c61350 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-08-25 15:22:45 +09:00
Alex Shinn
0a503dc3ad use curl for GET as well as POST in snow (i(issue #549) 2020-08-25 15:21:25 +09:00
Alex Shinn
5d6efedc5f
Merge pull request #689 from pclouds/snow-gauche-version-comparison
snow: accept "_" as version separator
2020-08-25 14:28:56 +09:00
Alex Shinn
74cb05aed6
Merge pull request #688 from krzygorz/colors-fix
(srfi 166 color) fix
2020-08-25 14:28:11 +09:00
Alex Shinn
60c4007e6f adding thread-interrupt! so that (chibi repl) can preserve continuations (issue #686) 2020-08-25 14:09:29 +09:00
krzygorz
9067c8b5d5 text attribute resetting fix 2020-08-24 13:52:29 +02:00
Nguyễn Thái Ngọc Duy
0eb0834bbc snow: accept "_" as version separator
$ tools/snow-chibi  implementations
    WARNING: Implementation gauche is an unsupported version,
    0.9.10_pre1, but at least 0.9.4 is required.
    cyclone
    sagittarius

The easy solution is also accept "_" as version separator and consider
"pre1" the forth component. This makes the warning go away, and I don't
think it'll affect version comparison on other schemes.
2020-08-24 18:36:31 +07:00
Alex Shinn
e307c872bf fix include-ci (issue #687) 2020-08-23 00:23:27 +09:00
Alex Shinn
b89db31e37 typo in env-exports (issue #685) 2020-08-22 16:27:20 +09:00
Alex Shinn
006f22ccd7 fixing match-letrec with unhygienic insertion (issue #574) 2020-08-21 10:18:16 +09:00
Alex Shinn
0f6e0f56e0 assume polar tail for inexact complex following / (issue #333) 2020-08-20 10:30:23 +09:00
Alex Shinn
287753f2e3 fix inexact polar notation (issue #333) 2020-08-20 09:54:09 +09:00
Alex Shinn
d75ae9304f forgot to export make-state-variable from composite library 2020-08-17 22:02:15 +09:00
Alex Shinn
6be0e8d059 exporting make-state-variable in SRFI 166 (issue #683) 2020-08-17 21:56:57 +09:00
Alex Shinn
421e357e98 no -lutil for emscripten (issue #681) 2020-08-17 10:07:52 +09:00
Alex Shinn
5ee7ad0230 allow start/end args to uvector->vector conversions (issue #682) 2020-08-16 08:06:22 +09:00
Alex Shinn
d41fac4f73 adding (auto) library for auxiliary syntax 2020-08-14 11:24:25 +09:00
Alex Shinn
440b30cf0b 0.9.1 minor release 2020-08-13 11:03:03 +09:00
Alex Shinn
177a4d22f5
Merge pull request #680 from arvyy/master
add fl-epsilon to srfi 144
2020-08-12 12:04:51 +09:00
Arvydas Silanskas
cf40f1aca1 add fl-epsilon to srfi 144 2020-08-11 21:26:42 +03:00
Alex Shinn
31c2adf8bf hash raw bytes of bignums 2020-08-11 11:12:04 +09:00
Alex Shinn
dc524feabc add missing trailing ? on SRFI 144 inequality ops 2020-08-11 10:37:23 +09:00
Alex Shinn
5616d2fb87 adding uvector-segment test 2020-08-11 10:36:52 +09:00
Alex Shinn
a8e35f90fa s/max/max in vector-segment (issue #677) 2020-08-08 16:20:01 +09:00
Alex Shinn
ffeb960997 fixing uvector-reverse-copy (issue #676); ungeneralize unfold to take exactly one seed 2020-08-08 16:14:57 +09:00
Alex Shinn
90f0425c37 fixing distribution of random bignums, adding uniformity tests on the results (issue #675) 2020-08-07 12:40:07 +09:00
Alex Shinn
449312d3bd restoring hashing of trailing data for uvectors 2020-08-04 18:31:20 +09:00
Alex Shinn
b4520b31f5 hash should not take into account non-sexp trailing data (bug report from Arthur Gleckler) 2020-08-04 12:23:22 +09:00
Lassi Kortela
65b197f7de Implement SRFI 193: Command lines 2020-08-03 13:24:18 +03:00
Arthur A. Gleckler
2e63c53a6b Fix: Install "base.scm", too. 2020-08-02 11:25:55 +09:00
Arthur A. Gleckler
de622eb37e Fix typo. 2020-08-02 11:24:41 +09:00
Alex Shinn
772542694b missing argument in snow package-spec+files 2020-08-01 00:00:38 +09:00
Alex Shinn
1ac1c68047 fixing bytecode accessors 2020-07-31 23:12:59 +09:00
Alex Shinn
54fece36a8 0.9.0 release 2020-07-31 15:47:27 +09:00
Alex Shinn
4335d238fb image options are harmless in non-image build; images not supported on 32-bit arch 2020-07-31 15:32:59 +09:00
Alex Shinn
306cc73bd6 Revert "image options are harmless in non-image build; images not supported on 32-bit arch"
This reverts commit 9b859eda36.
2020-07-31 15:32:18 +09:00
Alex Shinn
9b859eda36 image options are harmless in non-image build; images not supported on 32-bit arch 2020-07-31 15:31:43 +09:00
Alex Shinn
7362578878 attributing lgamma_r 2020-07-31 15:24:24 +09:00
Alex Shinn
5d2a9bcc3d SRFI 160 vector= differs from SRFI 133 in not taking an eq predicate (issue #674) 2020-07-31 15:09:46 +09:00
Alex Shinn
b7ffc4e700 Revert "SRFI 160 vector= differs from SRFI 133 in not taking an eq predicate (issue #674)"
This reverts commit 340c5aa2a8.
2020-07-31 15:08:59 +09:00
Alex Shinn
340c5aa2a8 SRFI 160 vector= differs from SRFI 133 in not taking an eq predicate (issue #674) 2020-07-31 15:00:03 +09:00
Alex Shinn
a559aec9bc pass '() as user exception irritants, not NULL 2020-07-30 18:11:57 +09:00
Alex Shinn
60ee6d70d0 move remaining fields to start of types 2020-07-30 00:19:21 +09:00
Alex Shinn
b60a6a2417 refer to formal srfi docs for srfi packages 2020-07-29 15:48:22 +09:00
Alex Shinn
36f188d274 adding notes about benchmarks for string-ref approaches 2020-07-29 12:28:40 +09:00
Alex Shinn
c726273c3b fixing distribution of random bignums 2020-07-29 12:15:20 +09:00
Alex Shinn
67dcd04d03 speedup snow search 2020-07-29 11:01:56 +09:00
Alex Shinn
a3d0d7a49c fixing pre-commit hook when no c or scheme files are changed 2020-07-29 10:29:24 +09:00
Alex Shinn
e70ebc4f35 forgot to install the shared lib for (scheme bytevector) (issue #673) 2020-07-29 10:27:54 +09:00
Alex Shinn
82acca4772 remove more tabs 2020-07-28 20:10:31 +09:00
Alex Shinn
d22959a40e fix pre-commit diff reference 2020-07-28 20:03:36 +09:00
Alex Shinn
ed4ecd4dca switching to pre-commit hook 2020-07-28 17:23:53 +09:00
Alex Shinn
24c40099f0 adding githooks 2020-07-28 15:59:24 +09:00
Alex Shinn
648f615b77 tabs in srfi 146 2020-07-28 15:29:49 +09:00
Alex Shinn
d593a5cb0a death to tabs 2020-07-28 15:26:42 +09:00
Alex Shinn
113560aeb7 avoid // comments 2020-07-28 15:13:38 +09:00
Alex Shinn
23e62275df fixing scheme bytevector for 32bit arch 2020-07-28 15:09:40 +09:00
Alex Shinn
edcddd7299 fixing 64-bit uvectors 2020-07-27 16:08:24 +09:00
Alex Shinn
99a863c723 forgot to add file 2020-07-26 23:23:19 +09:00
Alex Shinn
54c4b37f0e adding make-json-reader 2020-07-26 23:15:53 +09:00
Alex Shinn
e6229a7f65 fix cc warning on 32-bit arch 2020-07-24 16:19:24 +09:00
Alex Shinn
992544d051 filter history duplicates 2020-07-24 15:59:30 +09:00
Alex Shinn
0f5f552b6d adding ffi unit tests for arrays of pointers 2020-07-24 15:51:12 +09:00
Alex Shinn
ea370db4b4 fixing some cc warnings 2020-07-24 15:35:31 +09:00
Alex Shinn
0b9332ba77 suggesting closest misspelled options (issue #588) 2020-07-24 14:25:15 +09:00
Alex Shinn
8d85bfc5d2 improving docs 2020-07-24 12:53:29 +09:00
Alex Shinn
cb3734c2d1 adding some highlight keywords 2020-07-23 18:26:15 +09:00
Alex Shinn
8540155875 Fixing and documenting test filtering logic.
Use strikethrough for skipped tests.
Assume verbose testing if no group present for easier repl usage.
2020-07-23 17:51:07 +09:00
Alex Shinn
5a54ecce1d adding italic and strikethrough ansi escapes 2020-07-23 17:50:26 +09:00
Alex Shinn
9fd9b88660 documenting (chibi diff) 2020-07-23 17:50:00 +09:00
Alex Shinn
c23bfbc2f6 including example output in (chibi doc), translate ansi escape 2020-07-23 17:47:04 +09:00
Alex Shinn
5fe3ad766f avoid duplicate libraries 2020-07-21 15:48:35 +09:00
Alex Shinn
97ea47686e implementing substring/preserve 2020-07-21 14:05:30 +09:00
Alex Shinn
bde8a618ec comments from adam nelson: fixing numeric/comma arg, wrapped doesn't append final newline 2020-07-20 17:41:34 +09:00
Alex Shinn
58f6509c6f adding some substring-terminal-width tests 2020-07-20 17:16:58 +09:00
Alex Shinn
bcbed04b3b fixing pretty-printed circular lists 2020-07-20 16:38:48 +09:00
Alex Shinn
7366a13413 adding content-type output for http server files 2020-07-17 14:42:28 +09:00
Alex Shinn
983829cab1 better inexact computation for ratios which overflow double (issue #671) 2020-07-15 16:38:56 +09:00
Alex Shinn
9104fcc44e print skipped tests in verbose mode 2020-07-15 16:33:52 +09:00
Alex Shinn
fc33d6ffa3 implementing basic colors for pretty-with-colors 2020-07-14 23:58:27 +09:00
Alex Shinn
3700cfaf91 forgot extern (issue #669) 2020-07-14 20:32:30 +09:00
Alex Shinn
b9a76ad9d8 late cpp definitions should use XCPPFLAGS, not CPPFLAGS (issue #670) 2020-07-14 10:12:07 +09:00
Alex Shinn
e300659662 don't export sexp_primitive_opcodes (issue #669) 2020-07-14 10:08:21 +09:00
Alex Shinn
b4fb077fef random_r doesn't necessarily provide enough bits even for a fixnum (issue #668) 2020-07-13 10:27:04 +09:00
Alex Shinn
9940e0d053 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-07-13 10:02:11 +09:00
Alex Shinn
5d9a53f6e3 adding tmux-256color to list of terms supporting color 2020-07-13 10:02:00 +09:00
Alex Shinn
8020d3e97e
Merge pull request #667 from katterjohn/fix-nan-comparisons
Fix some NaN comparisons: NaNs are not less than every fixnum
2020-07-11 11:53:34 +09:00
Alex Shinn
d4944a75d6 fix typo reported by Arthur Gleckler 2020-07-11 06:41:14 +09:00
Kris Katterjohn
eb9d632dbf Fix some NaN comparisons: NaNs are not less than every fixnum
(< +nan.0 n) was yielding #t for fixnum n, and similarly for
(<= +nan.0 n) and (> n +nan.0) and so on.  This also caused
(negative? +nan.0) to return #t.

It just happened that NaNs were less than all fixnums: if a
conditional was written the other way around then NaNs would
have been greater than all fixnums instead.

The flonum case was sort of "accidentally" correct, but if a
conditional was written the other way around then NaNs would
be both less than or equal to and greater than all or equal
to all flonums (but still not equal).

For both cases check for NaNs after getting the flonum values.
2020-07-10 16:49:56 -04:00
Alex Shinn
f6eeb1c9f6
Merge pull request #666 from katterjohn/delay-wna
Check the number of args to delay and delay-force
2020-07-09 09:53:09 +09:00
Kris Katterjohn
948252517f Check the number of args to delay and delay-force 2020-07-08 19:15:06 -04:00
Alex Shinn
6fabc92b3d
Merge pull request #665 from katterjohn/chown
(chibi filesystem): add chown
2020-07-09 07:06:44 +09:00
Kris Katterjohn
f4526f7fc8 (chibi filesystem): conditionalize chown to fix Windows build 2020-07-08 15:36:21 -04:00
Kris Katterjohn
8ae99cff92 (chibi filesystem): add chown 2020-07-08 15:12:14 -04:00
Alex Shinn
e31e5ffbf3 updating (chibi json) to work on ports 2020-07-08 17:27:05 +09:00
Alex Shinn
2bdaebe8c7 wrap uncaught non-exceptions (issue #664) 2020-07-06 16:20:40 +09:00
Alex Shinn
f2d38e36c7 fixing (srfi 159) after refactoring 2020-07-06 15:09:49 +09:00
Alex Shinn
a6e8e9d7ba env vars are identifiers, not symbols; fix evaluation time (issue #516) 2020-07-06 15:00:27 +09:00
Alex Shinn
47b0a19733 adding point to headers for C API docs 2020-07-06 14:41:50 +09:00
Alex Shinn
72668b6d26 fixing ,@ patterns 2020-07-06 14:24:22 +09:00
Alex Shinn
cb5f523532 adding ..= and ..* patterns to match (issue #535) 2020-07-06 13:42:34 +09:00
Alex Shinn
da5827d889 generate SRFI 166 snowball 2020-07-06 10:55:49 +09:00
Alex Shinn
a9faa6cc7b removing debugging (scheme write) import 2020-07-03 14:51:54 +09:00
Alex Shinn
36c3471fa7 adding substring/width 2020-07-03 14:45:36 +09:00
Alex Shinn
39344bcaa0 adding background colors, as-italic 2020-07-03 10:42:11 +09:00
Alex Shinn
e3fddebb26 even string-cursor->index/index->cursor are polymorphic 2020-07-03 09:43:26 +09:00
Alex Shinn
89a5b97e3c remove duplicate tests 2020-06-27 07:13:07 +09:00
Alex Shinn
25e04e2a35 switch /si default base to 1000, remove show-columns export 2020-06-24 13:08:33 +09:00
Alex Shinn
532fb83e0a don't use nested show in pretty (issue #518); use string-width for computing width (issue #517) 2020-06-24 12:25:36 +09:00
Alex Shinn
cd7480ce45 fixing image search path loading after switching to snprintf 2020-06-23 10:35:12 +09:00
Alex Shinn
06cef55723 guard should use raise-continuable (issue #661) 2020-06-19 17:48:29 +09:00
Alex Shinn
e8f1233e18 cleaning up test names 2020-06-19 17:37:55 +09:00
Alex Shinn
80d2db51d8 fix sexp_opcode_argn_type initialization with gaps between the 3rd arg and k>4th arg 2020-06-19 16:45:41 +09:00
Alex Shinn
afb4a432c9 replace (chibi string) with (srfi 130) in (srfi 166) 2020-06-18 00:00:45 +09:00
Alex Shinn
402e3c8fb1 making (chibi show) an alias of (srfi 166) 2020-06-17 23:39:24 +09:00
Alex Shinn
278bb48b00 error on recursive includes (issue #557) 2020-06-16 11:44:10 +09:00
Alex Shinn
5b7729fbfc fixing whitespace 2020-06-16 11:43:47 +09:00
Alex Shinn
23f93cceb4 better fix for #618 2020-06-16 10:05:26 +09:00
Alex Shinn
d511b8e31d s/VERSION/CHIBI_VERSION to avoid conflicts (issue #659) 2020-06-15 18:54:20 +09:00
Alex Shinn
08c72aca59 handle shared dotted tail in writing lists (issue #618) 2020-06-15 12:22:16 +09:00
Alex Shinn
4734fc1e40 friendlier report for error on module files with the wrong name (issue #624) 2020-06-15 11:51:32 +09:00
Alex Shinn
aa2a87fbba
Merge pull request #658 from lkstl/master
Use r7rs lazy primitives in srfi 41
2020-06-10 08:39:05 +09:00
Lukas Stoll
afba9d8c27 Correct record-type names in srfi 41 2020-06-09 19:50:13 +02:00
Lukas Stoll
4f23fb4e03 Add (scheme lazy) to imports for srfi 41 2020-06-09 15:05:41 +02:00
Lukas Stoll
6e2bd8d4b7 Use r7rs lazy primitives in srfi 41
Rewrite srfi 41 primitive layer in terms of r7rs primitives for delayed
evaluation.
2020-06-09 14:55:44 +02:00
Alex Shinn
2b82ef68d4 fix placement of dl in context (issue #657) 2020-06-09 01:13:28 +09:00
Alex Shinn
32580be0ff fixing test-build on static exe 2020-06-08 11:59:16 +09:00
Alex Shinn
abc3403e0a chibi-scheme-static needs -lutil if (chibi pty) is included 2020-06-08 11:54:12 +09:00
Alex Shinn
4ec2167f62 making the abi a little more stable by default 2020-06-08 00:54:36 +09:00
Alex Shinn
e694f45f71
Merge pull request #656 from okuoku/win32-guess-green-threads
Win32: Guess SEXP_USE_GREEN_THREADS
2020-06-06 17:44:57 +09:00
okuoku
1b46d91053 Win32: Guess SEXP_USE_GREEN_THREADS
Guess SEXP_USE_GREEN_THREADS=0 ifdef `_WIN32`.
2020-06-05 05:59:33 +09:00
Alex Shinn
d42d4d5600 replace define-library-alias with define-library + alias-for 2020-06-04 23:55:37 +09:00
Alex Shinn
c245d6cee8 fix case folding, update to unicode 13 2020-06-04 22:08:07 +09:00
Alex Shinn
6fb0640721 adding (chibi diff), use in tests 2020-06-04 22:06:32 +09:00
Alex Shinn
5beadf7ce8 adding missing files 2020-06-03 11:33:15 +09:00
Alex Shinn
1164ecf9b7 adding unicode-string-width/wide 2020-06-03 10:43:22 +09:00
Alex Shinn
6f1cf6588f fix ffi type annotations 2020-05-31 23:39:55 +09:00
Alex Shinn
6caca77426 adding (scheme bytevector) 2020-05-31 23:24:51 +09:00
Alex Shinn
f1b6e6bf69 adding inline ffi stubs and assertions 2020-05-31 23:23:08 +09:00
Alex Shinn
d5e97ceeb3
Merge pull request #655 from lockywolf/makefile-srfi-166-install
Add srfi 146 and 166 installation to Makefile
2020-05-28 14:52:09 +09:00
Alex Shinn
170201d3e4
Merge pull request #654 from okuoku/github-ci
CI: Add Github Actions
2020-05-28 14:51:36 +09:00
Lockywolf
ca23ec9335 Add srfi 146 and 166 installation to Makefile 2020-05-28 12:33:55 +08:00
okuoku
78f28c69ea CI: Add Github Actions
This workflow tests against the standard Makefile build on
Mac and Linux.
2020-05-28 03:14:50 +09:00
Alex Shinn
daa7263690 remove debug line 2020-05-27 18:37:03 +09:00
Alex Shinn
95310e5823 no more strcpy/sprintf (issue #653) 2020-05-27 18:35:18 +09:00
Alex Shinn
255ee079e5 fix order of arguments in lset= 2020-05-27 14:27:31 +09:00
Alex Shinn
ca52b2ff97 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-05-27 07:54:53 +09:00
Alex Shinn
7b8b534a48 use (chibi test) for srfi 146 tests (issue #651) 2020-05-27 07:54:46 +09:00
Alex Shinn
add9983728
Merge pull request #652 from lassik/fix-printf
Fix printf warning in json.c
2020-05-27 07:51:52 +09:00
Lassi Kortela
c251594f0a Fix printf warning in json.c 2020-05-27 00:51:30 +03:00
Alex Shinn
9901a67b20 adding define-library-alias (issue #650) 2020-05-26 22:20:35 +09:00
Alex Shinn
0957b54f51 adding tangerine names for srfi 160 libs 2020-05-26 17:18:50 +09:00
Alex Shinn
1ee773fa42 adding srfi 146 to lib tests 2020-05-26 17:09:21 +09:00
Alex Shinn
11e0328fef adding (srfi 146 hash) 2020-05-26 17:05:07 +09:00
Alex Shinn
61680088d2 noting Marc's SRFIs 2020-05-26 14:17:07 +09:00
Alex Shinn
3a117b27aa adding srfi 146 2020-05-26 13:57:06 +09:00
Alex Shinn
fb079b2bda adding srfi 188 2020-05-26 10:12:27 +09:00
Alex Shinn
c0933e8255 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-05-25 19:02:03 +09:00
Alex Shinn
b1af52195a adding initial srfi 166 implementation 2020-05-25 19:01:03 +09:00
Alex Shinn
6b449150fc cleanup whitespace 2020-05-25 18:52:33 +09:00
Alex Shinn
7bbbb1fb2c avoid gc recursion on non-pointers 2020-05-25 18:50:47 +09:00
Alex Shinn
2315a11e7f
Merge pull request #648 from ekaitz-zarraga/unparse-json
Unparse json feature
2020-05-24 23:48:01 +09:00
Ekaitz Zarraga
28f3641583 Use SEXP_VOID instead of SEXP_NULL 2020-05-24 16:41:43 +02:00
Alex Shinn
110487b9b2
Merge pull request #649 from okuoku/fix-install
Makefile.detect: Fix installation
2020-05-24 16:57:40 +09:00
okuoku
21708b4cf3 Makefile.detect: Fix installation 2020-05-24 16:04:44 +09:00
Ekaitz Zarraga
6693e6bf18 Add tests 2020-05-23 16:05:02 +02:00
Ekaitz Zarraga
3745c16c8c Avoid using alloca in fixnum 2020-05-23 15:33:29 +02:00
Ekaitz Zarraga
a2312503c4 Flonum support 2020-05-23 15:28:48 +02:00
Ekaitz Zarraga
1ea46958a0 Add possible common error 2020-05-22 12:51:38 +02:00
Ekaitz Zarraga
a843591136 Clean formatting and remove unneeded comments 2020-05-22 12:51:38 +02:00
Ekaitz Zarraga
0e01716827 Exception handling 2020-05-22 12:51:38 +02:00
Ekaitz Zarraga
bb1fdbb719 Unparse Fixnums 2020-05-22 12:10:42 +02:00
Ekaitz Zarraga
57c5940855 Unparse Array and Object types 2020-05-22 12:10:42 +02:00
Ekaitz Zarraga
35cdd287ea Unparse string 2020-05-22 12:10:42 +02:00
Ekaitz Zarraga
de5a4b6b28 Copyright headers 2020-05-22 12:10:42 +02:00
Alex Shinn
62ef654817 clarifying in README that GNU make is used, movign all extensions to Makefile.detect (issue #642) 2020-05-22 15:06:45 +09:00
Alex Shinn
61f2983fad apply an explicit max vector length check (issue #636) 2020-05-22 14:13:48 +09:00
Alex Shinn
b459e11ecf
Merge pull request #647 from ekaitz-zarraga/float_parse
Correct float parsing when exponent has sign
2020-05-22 10:35:13 +08:00
Alex Shinn
bda192f071 cleanup json unicode escape code 2020-05-22 11:32:19 +09:00
Alex Shinn
278657eea4
Merge pull request #644 from ekaitz-zarraga/master
Support multiple \u sequences and add error checking
2020-05-22 10:11:10 +08:00
Ekaitz Zarraga
1cc24e37d9 Fix formatting 2020-05-22 00:30:24 +02:00
Ekaitz Zarraga
ce1996f1a7 Correct float parsing when exponent has sign 2020-05-21 18:10:54 +02:00
Ekaitz Zarraga
64d04f0638 Add JSON tests 2020-05-20 13:11:12 +02:00
Ekaitz Zarraga
e79d2aefea Support multiple \u sequences and check errors 2020-05-19 20:47:19 +02:00
Alex Shinn
8df9f7ca69
Merge pull request #643 from ekaitz-zarraga/master
Support for \u sequences in JSON
2020-05-19 09:18:00 +08:00
Ekaitz Zarraga
c448e8b441 Support for \u sequences in JSON 2020-05-18 22:39:33 +02:00
Alex Shinn
62efe38c70
Merge pull request #641 from amirouche/fix-emscripten-build
Fix build with emscripten to run chibi in the browser.
2020-05-17 19:17:13 +08:00
Amirouche
d2006daa3c Fix build with emscripten to run chibi in the browser.
emcc (Emscripten gcc/clang-like replacement) 1.39.16 (9ecd579ac647c4484e2d9af2ab0bbc1e1505aa95)

Thanks @pmp-p.
2020-05-17 10:52:46 +02:00
Alex Shinn
6e8b9bf59d adding srfi 165 2020-05-17 00:08:00 +09:00
Alex Shinn
af7189e895
Merge pull request #640 from Donaim/601
Prevent stack overflow in sexp_mark_one (issue #601)
2020-05-16 22:13:27 +08:00
Vitaliy Mysak
5726c2e490 Prevent stack overflow in sexp_mark_one (issue #601)
Replace explicit recursion by heap allocations
in sexp_mark_one code.
This prevents crashes caused by stack overflow.
In particular, fixes issue #601.

As an optimization, allocate a fixed sized stack buffer first,
which should be enough for "normal" uses.
When that stack overflows, switch to heap.

Also, store "ranges" on the stack, instead of the actual sexp's,
using the fact that sexp's of a single parent are continous in memory.

This patch doesn't remove recursion on the context saves
because it didn't seem like they overflow in practice.
But changing that is simple having the stack interface.
2020-05-15 20:11:50 +02:00
Alex Shinn
4be920986f
Merge pull request #639 from Donaim/638
Avoid undefined C macro behavior
2020-05-14 08:11:36 +08:00
Donaim
bd62a076c6 Avoid undefined C macro behavior
MacOS and clang compilers complain about undefined behavior
in C macro.
Rewrite macro to solve that.

Fixes issue #638
2020-05-13 22:23:17 +02:00
Alex Shinn
72e70bef88
Merge pull request #637 from Donaim/fix-c89-compilation
Fix c89 compilation and add test build option for it
2020-05-13 18:18:39 +09:00
Vitaliy Mysak
9c680217d7 tests: add std=c89 as build option
Since chibi already compiles with c89,
it should not be too bad to maintain this compatibility.
2020-05-13 11:12:02 +02:00
Vitaliy Mysak
f449bd157d fix compilation under std=c89
There were few things that prevented successful compilation
using c89 standard. (and other c* standards in case of gcc).
Fix them in this small patch.

Changes in 27/rand.c:
- Use __GNU_SOURCE__ instead of __GNU_LIBRARY__
  or else any of -std=c* options don't work with gcc
- Add a check before using rand_r() as suggested in rand_r(3)
- Move _WIN_32 definitions to "else" branch because it uses the most portable version
2020-05-13 11:12:02 +02:00
Alex Shinn
e7e6530c35
Merge pull request #635 from Donaim/uninstall-misses
make: fix uninstall target
2020-05-12 10:43:21 +09:00
Alex Shinn
89201a4e20 remove bad redefinition of sexp_context_gc_count (issue #632) 2020-05-12 10:39:27 +09:00
Donaim
ebfe494147 make: fix uninstall target
uninstall target failed to remove
- share/srfi libraries
- man pages
- include headers

This patch repairs the makefile so that all chibi files
get removed correctly.

In case of man pages, they were actually installed
to a wrong place - "man1/man1" instead of "man1".
This was introduced by 2137fcd3f0
so current commit reverts it.
2020-05-11 23:19:48 +02:00
Alex Shinn
610b6964ce fix log table for integer-length (issue #634) 2020-05-11 21:38:40 +09:00
Alex Shinn
426579eef2 Merge branch 'master' of github.com:ashinn/chibi-scheme 2020-05-11 10:45:24 +09:00
Alex Shinn
83e82f55a7 tweaks for fixed-size heaps, fix issue #632 2020-05-11 10:43:36 +09:00
Alex Shinn
90b0336048 report diff on gc times 2020-05-11 10:28:00 +09:00
Alex Shinn
fe7ae7ca48
Merge pull request #633 from ar-nelson/srfi-133-vector-every-fix
Fix SRFI 133 vector-every crash on empty vector
2020-05-10 01:12:44 +09:00
Adam R. Nelson
18a5776587 Fix SRFI 133 vector-every crash on empty vector 2020-05-09 11:46:10 -04:00
Alex Shinn
abe8ca3b95 obi-wan error 2020-05-07 21:48:51 +09:00
Alex Shinn
e3db106f96 instrumenting alloc times and sizes 2020-05-06 23:39:01 +09:00
Alex Shinn
a4dcd04127
Merge pull request #631 from mnieper/srfi-158
Implement SRFI 158.
2020-05-06 07:48:23 +09:00
Marc Nieper-Wißkirchen
15b3449b85 Implement SRFI 158. 2020-05-05 22:28:10 +02:00
Alex Shinn
9100909ae1 better defaults and debugging for fixed size chunks 2020-05-05 00:41:20 +09:00
Alex Shinn
696bf30f5e check for circular lists in apply (issue #629) 2020-05-03 17:19:24 +09:00
Alex Shinn
156ddf793d better benchmark timing 2020-05-03 17:05:53 +09:00
Alex Shinn
c43285e5f2
Merge pull request #630 from mnieper/srfi-162
Implement SRFI 162.
2020-05-03 08:05:57 +09:00
Marc Nieper-Wißkirchen
d4527d23dc Implement SRFI 162. 2020-05-02 21:05:19 +02:00
Alex Shinn
69aed93502
Merge pull request #627 from lassik/usage
Write usage to stderr when bad options given
2020-04-23 21:31:49 +09:00
Lassi Kortela
bb0a0054c8 Write usage to stderr when bad options given 2020-04-23 13:59:27 +03:00
Alex Shinn
957ffe6a42 return successfully on --help (issue #626) 2020-04-23 19:27:52 +09:00
Alex Shinn
361dc48c62 don't verify duplicate formal parameters for more than 100 params 2020-04-19 19:20:01 +09:00
Alex Shinn
f74c34b99b make-promise is idempotent (issue #625) 2020-04-10 17:17:29 +09:00
Alex Shinn
0a83939866 fix corner case with multi-line comments in non-native read (issue #623) 2020-03-30 01:14:27 +09:00
Alex Shinn
72ea1258e6
Merge pull request #622 from katterjohn/address-info-canonname
(chibi net): add address-info-canonname
2020-03-25 16:16:28 +08:00
Alex Shinn
1795014dae throw an error on get-output-string on non-string-ports (issue #621) 2020-03-25 17:15:06 +09:00
Kris Katterjohn
3de48e0232 (chibi net): add address-info-canonname 2020-03-24 19:03:41 -05:00
Alex Shinn
d19ee75800
Merge pull request #617 from pclouds/tangerine-aliases
Add Tangerine library names
2020-02-22 10:54:35 +08:00
Nguyễn Thái Ngọc Duy
a3eda041a3 Add Tangerine library names
Chibi supports quite a few SRFIs that have been part of Tangerine
edition. These .sld are the same as their counterpart .sld, except the
rename.
2020-02-20 19:12:03 +07:00
Alex Shinn
7656be5043
Merge pull request #616 from pclouds/chibi-run
Allow to run chibi-run from anywhere
2020-02-19 22:25:24 +08:00
Nguyễn Thái Ngọc Duy
b678abbce7 Allow to run chibi-run from anywhere
chibi-run script assumes $(PWD) is at topdir. Let's remove that
assumption so that the script can be used anywhere to launch chibi from
dev environment.
2020-02-19 17:24:12 +07:00
Alex Shinn
3161edbe86
Merge pull request #613 from pclouds/chibi-test-no-protect
chibi/test: remove dead import
2020-02-14 22:19:22 +08:00
Nguyễn Thái Ngọc Duy
58b2ee34dd chibi/test: remove dead import
'protect' used to be renamed to 'guard', after excluding 'guard'
from (scheme base). But that part is now gone. test.scm itself never
uses 'protect' directly. Remove it because it's not used.
2020-02-14 19:03:42 +07:00
Alex Shinn
507e62c3e1 add safety checks on substring-cursor 2020-02-06 23:09:33 +08:00
Alex Shinn
fad3413235
Merge pull request #609 from ilammy/snow-usr-local
Always install Snow libraries to /usr/local
2020-02-06 21:15:39 +08:00
Alex Shinn
9e82ffd462
Merge pull request #612 from pclouds/srfi-159-exports
Correct srfi-159 exported procedures
2020-02-05 21:40:48 +08:00
Nguyễn Thái Ngọc Duy
c68bbf89bd Correct srfi-159 exported procedures
The two procedures pretty and pretty-simply from (chibi show pretty)
should be part of (srfi 159 base). written-shared is removed from 159
because it looks like it's an addition in 166.
2020-02-04 20:28:55 +07:00
Alex Shinn
77dad5af5c
Merge pull request #611 from ilammy/snow-remove
Use sudo when doing "snow-chibi remove"
2020-02-03 22:21:15 +08:00
Alex Shinn
addb859ab2
Merge pull request #610 from ilammy/hide-symbols
Hide unnecessarily exported symbols
2020-02-03 22:19:37 +08:00
Alex Shinn
4f7c3d5637
Merge pull request #608 from ilammy/man-path
Correct man page installation directory
2020-02-03 22:16:38 +08:00
Alex Shinn
12d3c6a504
Merge pull request #607 from ilammy/so-prefix
Common library installation prefixes
2020-02-03 22:15:45 +08:00
Alexei Lozovsky
24f207115c Hide unnecessarily exported symbols
gc_heap_err_str and load_image_header() are never used outside of
gc_heap.c but they are not marked static and are effectively exported
by Chibi's shared library. Since this is unlikely to be intentional,
let's hide them.
2020-02-02 16:59:57 +02:00
Alexei Lozovsky
50a9c9d4d4 Use sudo when doing "snow-chibi remove"
Currently "remove" command does not know how to use sudo to remove
files installed into directories owned by root. By default Snow
installs stuff into /usr/local hierarchy and uses sudo for that.
Let's teach it to remove packages without explicit sudo too.
2020-02-02 16:46:23 +02:00
Alexei Lozovsky
26061930e9 Always install Snow libraries to /usr/local
Snow-Chibi is a local package manager, not a system one. It can install
Scheme packages into system but they are not managed by system package
manager like dpkg, RPM, pacman, ports, etc.

Traditionally (and in accordance with Filesystem Hierarchy Standard),
/usr/local hierarchy should be used for local administrator installs --
and that's what Snow-Chibi provides.

Let's make sure that Snow-Chibi installs snowballs into /usr/local
hierarchy even if Chibi is compiled for installation into the system,
with PREFIX=/usr. Introduce a distinct bunch of variables holding paths
to library installation directories, with "SNOW" prefix:

  - SNOWPREFIX    - default prefix for Snow-installed stuff
  - SNOWLIBDIR    - custom libraries required for Snow itself
  - SNOWSOLIBDIR  - shared libraries required for Snow itself
  - SNOWMODDIR    - Snow installs Scheme modules here
  - SNOWBINMODDIR - Snow installs native libraries here

All of these are set to /use/local by default, just as they are now.
However, they are not affected by regular PREFIX, LIBDIR, MODDIR, etc.
which affect only libraries bundled with Chibi.

And in order for these to work, they need to be added into the current
module path so that they can be used in parallel with system libraries.
Furthermore, we need to tweak "get-install-library-dir" function to use
those paths instead of hardcoded "/usr/local/lib" by default. Introduce
a new helper "get-install-library-dirs", similar to "get-install-dirs".
It will look up the correct installation directories in current module
path, giving preference to the ones with "/lib" in them.

With these defaults, Snow will install Scheme modules into
/usr/local/share/snow and native libraries go into /usr/local/lib/snow,
similar to how built-it libraries are installed into
/usr/local/share/chibi and /usr/local/lib/chibi is used for native code.
Of course, this can be overriden at build time by setting SNOWPREFIX or
individual SNOWMODDIR, SNOWBINMODDIR variables.
2020-02-02 16:21:21 +02:00
Alexei Lozovsky
2137fcd3f0 Correct man page installation directory
According to the Filesystem Hierarchy Standard (see "man 7 hier")
man pages should be installed into an appropriate subdirectory for
their section. Fix the installation path so that our documentation
goes into the right place.

All UNIX-like systems supported by Chibi follow FHS for man pages:

  - FreeBSD
  - GNU/Linux
  - macOS
  - Plan 9
2020-02-02 11:34:24 +02:00
Alexei Lozovsky
04ce3700d7 Shared library installation prefixes
Both SOLIBDIR and BINMODDIR install into $(PREFIX)/lib which is the same
value as LIBDIR -- the traditional name of the directory for installed
libraries. Current duplication is fine for the default installation
(with PREFIX = /usr/local) but it does not play nicely with systems
supporing multiple architectures.

For example, Debian systems allow the users to install libraries for
multiple architectures simultaneously: e.g., 32-bit and 64-bit libraries
for AMD-64 CPUs go into separate directories:

  - 64-bit: /usr/lib/x86_64-linux-gnu/libchibi-scheme.so.0.8.0
  - 32-bit: /usr/lib/i386-linux-gnu/libchibi-scheme.so.0.8.0

Other Linux systems (Red Hat family) use different paths like /usr/lib64
and /usr/lib, but the general idea is the same.

In order to achive this, packaging toolchain supplies appropriate value
of LIBDIR which takes care of these details more or less automagically.

However, with Chibi you currently need to additionally override SOLIBDIR
and BINMODDIR to have all the libraries installed into multiarch-enabled
locations. While definitely doable, it's not convenient.

Redefine SOLIBDIR and BINMODDIR in terms of LIBDIR so that you only need
to override LIBDIR to get the packaging correctly. This does not change
the default installation paths and it is still possible to override
these values individually if necessary.
2020-02-02 10:48:39 +02:00
Alex Shinn
2b7927b9bc allow indexes instead of cursors for cursor-next/prev and string-any/every 2020-01-31 23:26:38 +08:00
Alex Shinn
708f57ffed SRFI 151 fixes: bitwise-if arg order swapped from SRFI 33; bit-set? on negative integers should extend infinite 1s; bit-field-every? should compare only bits within mask 2020-01-31 23:12:20 +08:00
Alex Shinn
a88a1ad244 adding ffi test with unsigned-char param 2020-01-27 22:19:51 +08:00
Alex Shinn
6a2ed9cdb4 fix iset-intersection on large trees in the first argument (issue #606) 2020-01-27 21:52:17 +08:00
Alex Shinn
5e3d2284ed
Merge pull request #604 from ar-nelson/srfi-128-hash-fix
Fix make-comparator hash function arity in SRFI 128
2020-01-12 22:46:26 +08:00
Adam R. Nelson
6aacffc0e8 fix make-comparator hash function arity in SRFI 128 2020-01-12 09:45:38 -05:00
Alex Shinn
82654b4c46 make install shouldn't fail if there are issues with images (fixes issue #603) 2020-01-12 22:43:36 +08:00
Alex Shinn
48d6c35548 nans aren't rational 2020-01-02 22:40:49 +08:00
Alex Shinn
c174465aa1 fix rational? for some boundary cases 2020-01-02 22:35:33 +08:00
Alex Shinn
a9f9b3dd8a
Merge pull request #596 from lassik/apropos
Add (chibi apropos) module
2019-12-31 00:36:10 +08:00
Lassi Kortela
60f22c978f Add (chibi apropos) module 2019-12-28 17:44:32 +02:00
Alex Shinn
6f28159667 regexp-replace should respect start/end also for pre/post substitutions 2019-12-28 22:48:44 +08:00
Alex Shinn
3c8402d4fb re-run scheduler if only thread was still waiting (issue #594) 2019-12-26 23:42:15 +08:00
Alex Shinn
588d63d901 don't escape html in sxml-display-as-text, add newline after li (issue #592) 2019-12-26 22:49:18 +08:00
Alex Shinn
d79f557d46 fix variadic foreign functions with more than 4 params 2019-12-19 23:58:51 +08:00
Alex Shinn
d5b5a079f4 initial uvector ffi support 2019-12-17 23:48:26 +08:00
Alex Shinn
5b60641f43 small documentation fixes 2019-12-17 23:47:53 +08:00
Alex Shinn
e10d82987a adding ignored failing match-letrec test case 2019-12-17 23:47:19 +08:00
Alex Shinn
33d6cfd0ac
Merge pull request #591 from krzygorz/ansi-fix
(chibi show): Make ANSI escape codes work with col state variable
2019-11-08 18:54:41 +08:00
krzygorz
5c43ca7720 move the col+ansi test to color section 2019-11-07 22:37:33 +01:00
krzygorz
15fef988af add a test for col with unicode and ANSI escapes 2019-11-07 22:31:29 +01:00
krzygorz
05521e5e1d use string-append for building ansi escape codes 2019-11-07 18:34:41 +01:00
Alex Shinn
abfa6a724e Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-11-04 20:15:40 +08:00
Alex Shinn
7b6a928974 adding levenshtein distance 2019-11-04 20:15:32 +08:00
Alex Shinn
10b713284c
Merge pull request #589 from ekaitz-zarraga/docs
Update sxml docs
2019-10-31 23:17:28 +08:00
Ekaitz Zárraga
bbe279b825 Update sxml docs 2019-10-30 10:15:52 +01:00
Alex Shinn
6f57d6ac71
Merge pull request #586 from amirouche/wasm-improvements
WASM improvements
2019-10-29 21:58:32 +08:00
Amirouche
9604fa361b Makefile: js/chibi.js: ALLOW_MEMORY_GROWTH=1
`ALLOW_MEMORY_GROWTH=1` allows to grow the wasm vm memory space as
needed and avoid out-of-memory issues. This is for development
purpose, production build will want to set memory size to something
that is fit the application (I don't remember the actual option name,
but removing ALLOW_MEMORY_GROWTH=1 from the compilation, and
re-running the app will display the good option to use).
2019-10-28 12:21:37 +01:00
Amirouche
61684647d6 Makefile: js/chibi.js: disable optimization
Optimizations will (sometime) lead to broken build.
2019-10-28 12:19:37 +01:00
Amirouche
9acd71735c Makefile: whitespace cleanup 2019-10-28 12:18:09 +01:00
Alex Shinn
4ad228a0f6
Merge pull request #585 from ekaitz-zarraga/safe-string
[WIP] Add option to ignore escaping
2019-10-24 21:00:29 +08:00
Ekaitz Zárraga
12f941dbfe Add option to ignore escaping 2019-10-24 09:56:08 +02:00
Alex Shinn
b33df19274
Merge pull request #583 from ekaitz-zarraga/patch-2
Correct typo
2019-10-24 10:27:35 +08:00
Ekaitz Zárraga
5dfc3b7909
Correct typo 2019-10-23 18:29:48 +02:00
Alex Shinn
c836311918
Merge pull request #582 from ekaitz-zarraga/patch-1
Missing ) in code example
2019-10-21 23:39:47 +08:00
Ekaitz Zárraga
cb63e9130c
Missing ) in code example 2019-10-19 13:01:10 +02:00
Alex Shinn
f4b0277d01 allow rest param in let-optionals 2019-10-14 22:04:23 +08:00
Alex Shinn
58e10b2a7d assert types in boolean=? and symbol=? (fixes issue #579) 2019-10-06 22:29:58 +08:00
Alex Shinn
544eaa79c7
Merge pull request #578 from katterjohn/mmap-heap-fixes
Fixes for mmapped heaps
2019-10-06 08:26:16 +08:00
Alex Shinn
e3935695a1
Merge pull request #577 from katterjohn/fix-mime-type
(chibi net server-util): file-mime-type: fix load-mime-types call
2019-10-06 08:20:45 +08:00
Kris Katterjohn
a1473f69ba mmapped heaps: fix for systems with W^X policies
Using read/write/exec causes an error (or possibly abort) on systems
with W^X policies (like OpenBSD and NetBSD have by default).

Since the heap does not need to be executable, just use read/write.
2019-10-04 20:50:41 -05:00
Kris Katterjohn
25d4807f50 mmapped heaps: fix the file descriptor argument to mmap for the BSDs
On the BSDs, the file descriptor passed to mmap when using MAP_ANON
must be -1.  Passing 0 causes mmap to fail.
2019-10-04 20:39:37 -05:00
Kris Katterjohn
650be6adc0 mmapped heaps: correctly check for mmap failure
When mmap fails it returns MAP_FAILED, not NULL.  POSIX does not
define the value for MAP_FAILED, but on at least the BSDs and Linux
its value is ((void *) -1).
2019-10-04 20:38:15 -05:00
Kris Katterjohn
9bbf48d084 (chibi net server-util): file-mime-type: fix load-mime-types call
Use find instead of any so load-mime-types will get the filename
instead of #t when a mime.types file is found.  Otherwise an error
occurs in load-mime-types.
2019-10-01 20:00:36 -05:00
Alex Shinn
3749d29883
Merge pull request #576 from katterjohn/memv-fix
memv: compare using eqv? instead of equal?
2019-09-24 22:07:17 +08:00
Kris Katterjohn
ea92d228b3 memv: compare using eqv? instead of equal?
memv has been defined to be member, so it has been comparing
using equal? (by default) instead of eqv?.
2019-09-23 20:43:25 -05:00
Alex Shinn
e2d43bceb8
Merge pull request #575 from katterjohn/listener-socket-leak
(chibi net): make-listener-socket: close the socket on error
2019-09-23 16:52:48 +08:00
Alex Shinn
eaf8e90e8c fix inexact json parsing 2019-09-23 12:09:52 +08:00
Alex Shinn
72971fd4f4 pipes should be escaped in symbols (fixes issue #571) 2019-09-23 11:53:54 +08:00
Kris Katterjohn
a28da66990 (chibi net): make-listener-socket: close the socket on error
A socket was leaked in the case where setting socket-opt/reuseaddr
failed.  (The socket was closed in the cases where bind or listen
failed.)
2019-09-22 19:18:18 -05:00
Alex Shinn
144581b834
Merge pull request #573 from katterjohn/net-export-addrinfo-flags
(chibi net): export address-info-flags
2019-09-20 23:02:19 +08:00
Alex Shinn
41d1f11dd3
Merge pull request #572 from katterjohn/system-export-groupp
(chibi system): export group?
2019-09-20 23:01:52 +08:00
Kris Katterjohn
407d420c21 (chibi system): export the struct group predicate group? 2019-09-19 15:47:41 -05:00
Kris Katterjohn
bb4239bac8 (chibi net): export the struct addrinfo getter address-info-flags 2019-09-19 15:45:26 -05:00
Alex Shinn
b9c25ab3f1
Merge pull request #567 from katterjohn/sockaddr-port-fix
(chibi net): sockaddr-port: return the port number in host byte order
2019-09-17 00:10:42 +08:00
Alex Shinn
dc18568236 forgot the factor of 8 in the range 2019-09-13 23:31:40 +08:00
Alex Shinn
713c6f7135 fix range check in unicode-string-width from edit-line 2019-09-13 23:10:39 +08:00
Alex Shinn
aa85d53989
Merge pull request #568 from katterjohn/sockaddr-name-fix
(chibi net): sockaddr-name: fix support for IPv6 addresses
2019-09-12 10:59:46 +08:00
Kris Katterjohn
fd7ff6d33f (chibi net): sockaddr-name: fix support for IPv6 addresses
The buffer was too small to hold all IPv6 addresses in string form
2019-09-10 18:04:01 -05:00
Kris Katterjohn
a7a620af1a (chibi net): sockaddr-port: return the port number in host byte order 2019-09-10 17:54:14 -05:00
Alex Shinn
197894eb87 fix (expt fixnum flonum) by reverting ce9c60c1 2019-09-09 23:25:27 +08:00
Alex Shinn
af686a8b50 Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-09-03 19:57:12 +08:00
Alex Shinn
e9c8bed95a random-integer should check for positive bounds 2019-09-03 19:56:59 +08:00
Alex Shinn
00d084414e
Merge pull request #563 from fisherro/chicken-5-support
Change snow-chibi to work with Chicken 5
2019-08-31 22:37:50 +08:00
Alex Shinn
ae98680259
Merge pull request #564 from katterjohn/process-bsd-fix
(chibi process): fix process-running? on OpenBSD, NetBSD and DragonFly
2019-08-31 22:36:49 +08:00
Kris Katterjohn
3da3f3cab3 (chibi process): fix process-running? on OpenBSD, NetBSD and DragonFly
tl;dr process-running? would always return #f on OpenBSD and
NetBSD, and in the one-argument case it would always return #t
on DragonFly.

To get the process information from the process table on OpenBSD
and NetBSD, we need to pass 6 level names to sysctl instead of 4.
Passing the wrong number of level names to sysctl has caused it
to always fail, which in turn caused process-running? to always
return #f:

  (process-running? 1)                        =>  #f
  (process-running? (current-process-id))     =>  #f

and so on.

After the above fix, we also need to check the amount of data
actually filled in by sysctl.  It appears that on OpenBSD, NetBSD
and DragonFly, if the requested process doesn't exist then sysctl
will return with a return value of 0 and just not actually fill in
the given structure.  This caused process-running? to return #t
when no process with the given PID existed:

  (process-running? -1)                       =>  #t
  (process-running? <other nonexistent pid>)  =>  #t

and so on.

I have tested on OpenBSD, NetBSD, DragonFly BSD and FreeBSD, and
process-running? now behaves as expected on all of them.
2019-08-30 13:05:32 -05:00
Robert Fisher
7f3d322407 Fix installation for Chicken 5
To get the repository path in Chicken 5, we not only have to require the
chicken.platform module, we also need to take the car of the result
since it now returns a list.
2019-08-29 11:42:21 -05:00
Robert Fisher
13d4bbf1d1 Change snow-chibi to work with Chicken 5
The method snow-chibi used to get the version of Chicken installed
doesn't work with Chicken 5. Adding "-R chicken.platform" would make it
work with Chicken 5, but then it wouldn't work with Chicken 4.

In both Chicken 4 & 5, however, csi has a -release option that will just
give the version number. So, I've changed the Chicken version detection
in snow-chibi to use this option.

Testing with...

	./chibi-scheme tools/snow-chibi.scm implementations

...then seemed to work with both Chicken 4 & 5.
2019-08-29 09:16:36 -05:00
Alex Shinn
0bfc31a1e5 check for too many args to if (issue #561) 2019-08-29 21:56:00 +08:00
Alex Shinn
4282a6da0d
Merge pull request #562 from katterjohn/git-ignore-pty
Add lib/chibi/pty.c to .gitignore
2019-08-29 21:50:25 +08:00
Kris Katterjohn
789abbabb3 Add lib/chibi/pty.c to .gitignore 2019-08-28 19:38:08 -05:00
Alex Shinn
19f408a041 Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-08-24 22:34:30 +08:00
Alex Shinn
e7b9510656 allowing required args in opt-lambda, adding define-opt 2019-08-24 22:34:20 +08:00
Alex Shinn
8645b23d42 fixing bug in pp-with-indent on dotted list 2019-08-24 16:00:47 +08:00
Alex Shinn
31cea4af6d
Merge pull request #560 from okuoku/disable-pty-cmake
(chibi pty): Disable in CMake build
2019-08-24 11:18:11 +08:00
okuoku
753e9e89d1 (chibi pty): Disable in CMake build
Disable `(chibi pty)` build with CMake.
2019-08-24 07:08:47 +09:00
Alex Shinn
cc1ca2622d
Merge pull request #559 from katterjohn/pty-bsd-fix
(chibi pty): fix compilation errors on the BSDs
2019-08-23 20:08:46 +08:00
Kris Katterjohn
8b6e236b09 (chibi pty): fix compilation errors on the BSDs
* Include util.h instead of pty.h on OpenBSD and NetBSD

* Include libutil.h instead of pty.h on FreeBSD and DragonFly BSD

* Include utmp.h only on non-BSD systems (FreeBSD does not have that
  header and none of these BSDs require it)

Tested on all four of these BSDs.
2019-08-22 16:33:10 -05:00
Alex Shinn
a9cebfb8da adding wip json parser 2019-08-23 00:45:58 +08:00
Alex Shinn
c7d2638fbc s/pty.h/util.h on macosx (fixes issue #558) 2019-08-22 23:53:42 +08:00
Alex Shinn
8ea1852ac1 adding (chibi pty) 2019-08-19 23:03:09 +08:00
Alex Shinn
ec09e0eed4 Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-08-19 21:53:12 +08:00
Alex Shinn
4aac80e41b
Merge pull request #555 from richlowe/sunos-build
build on Solaris-like systems
2019-08-17 21:56:07 +08:00
Alex Shinn
42b6eeff1b fix string-mismatch usage in (chibi repl) 2019-08-16 23:39:36 +08:00
Alex Shinn
56acd0eb56
Merge pull request #556 from katterjohn/bsd-detection
Fix NetBSD, DragonFly BSD and Darwin feature detection
2019-08-16 22:35:14 +08:00
Kris Katterjohn
4c1af8c92a Fix NetBSD, DragonFly BSD and Darwin feature detection
On NetBSD systems the netbsd feature identifier was not actually
provided because the macro SEXP_NETBSD was defined twice and the
second value was 0.

On DragonFly systems the dragonfly feature identifier was not actually
provided because the macro SEXP_DRAGONFLY was defined twice and the
second value was 0.  Also on DragonFly systems the darwin feature
identifier was incorrectly provided because SEXP_DARWIN had a value of
1 instead of 0.
2019-08-15 19:03:57 -05:00
Alex Shinn
83cfc7dd53 adding len limit on ffi auto-expand vars (issue #553) 2019-08-15 23:42:17 +08:00
Alex Shinn
39f34ffffb adding port-source?[-set!] to ast 2019-08-15 23:18:07 +08:00
Alex Shinn
93b718f7c3 adding set-source to ast 2019-08-15 23:11:39 +08:00
Richard Lowe
2311e41003 build on Solaris-like systems 2019-08-11 22:30:17 +00:00
Alex Shinn
a01de232b2
Merge pull request #554 from apg/apg/bsd-feature-expansion
Add features for the various BSDs.
2019-08-03 11:45:43 +08:00
Andrew Gwozdziewycz
e5ae89c9c6 Define / detect explicit features for BSD platforms 2019-08-02 11:33:59 -07:00
Andrew Gwozdziewycz
ac467ea314 Add features for the various BSDs.
This could and should be done cleaner. Works as a proof of concept at
this point in time.
2019-08-02 01:56:51 -07:00
Alex Shinn
a8680bb0b4
Merge pull request #551 from v01dXYZ/master
Fix include-shared for process
2019-07-24 22:54:30 +08:00
Alex Shinn
2a9bb14d2d
Merge pull request #548 from pclouds/sre-error-check
More error checking on some SRE syntax
2019-07-24 22:47:36 +08:00
v01dXYZ
94ca5a95ca
Fix include-shared for process
`chibi-genstatic` doesn't support expansion of `cond-expand` when the pattern is `(cond-expand (cond) (else (include-shared "module")))`
2019-07-24 11:10:04 +00:00
Nguyễn Thái Ngọc Duy
829d963a9d More error checking on some SRE syntax
When char-set, w/case, w/nocase, w/ascii or w/unicode is applied on a
<cset-sre>, only (cadr sre) is taken, the rest is ignored. Which is the
right thing to do only if (null? (cddr sre)). If there are more
arguments, error out instead of silently ignoring them.
2019-07-21 10:46:44 +07:00
Alex Shinn
b3831c3995
Merge pull request #544 from okuoku/win32-dll
Properly support DLL build on Win32
2019-07-12 00:06:31 +08:00
Alex Shinn
27e67b0ae4 Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-07-12 00:05:10 +08:00
Alex Shinn
597df2e931 missing space before quote (issue #545) 2019-07-12 00:04:52 +08:00
okuoku
205bda5ab4 cmake: Support shared-library builds
Support shared-library (DLL on Win32) builds and defaults on it.
2019-06-23 05:46:25 +09:00
okuoku
3d4e8bb3e6 Introduce SEXP_STATIC_LIBRARY
Introduce SEXP_STATIC_LIBRARY to support static-library build on
Win32/Win64. On Win32, symbol visibility is enforced on DLL builds so we
need to dedicated ABI on static-library builds.
2019-06-23 05:46:22 +09:00
Alex Shinn
6a35a95dfc
Merge pull request #540 from wasamasa/read-error-for-unterminated-strings
Consider unterminated strings as read-error
2019-05-23 14:33:51 +08:00
Alex Shinn
bbcb571ba5 fix comparison of negative bignums (issue #541) 2019-05-21 22:26:37 +08:00
Vasilij Schneidermann
ab39f12904 Consider unterminated strings as read-error 2019-05-17 10:55:22 +02:00
Alex Shinn
104811942f fixing read-line on network ports 2019-05-04 13:18:27 +08:00
Alex Shinn
26ceb64434 fix exact neg check for ratio in rounding (issue #539) 2019-05-03 00:37:30 +08:00
Alex Shinn
624b54c05c
Merge pull request #537 from lassik/fix-printf-warning
Avoid compiler warning about mismatched printf types
2019-04-26 22:33:14 +08:00
Lassi Kortela
2dc4353604 Avoid compiler warning about mismatched printf types
Under Unix with SEXP_64_BIT defined, sexp_sint_t is defined as 'long'.
But we would get the equivalent format specifier SEXP_PRIdFIXNUM from
the OS-defined PRId64 in <inttypes.h>. MacOS defines it as "lld". This
causes the clang printf checker to emit a warning about the 'long' and
'long long' mismatch.

Fix by avoiding system-defined PRId32 and PRId64 format specifiers and
always defining SEXP_PRIdFIXNUM as "d", "ld" or "lld" according to our
definition of sexp_sint_t as int, long or long long. This also means
we don't need to include <inttypes.h> any more.
2019-04-24 12:26:01 +03:00
Alex Shinn
105a4672e7 more helpful error messages on missing libraries 2019-04-21 22:11:11 +08:00
Alex Shinn
4cba9d3e6c Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-04-02 22:31:45 +08:00
Alex Shinn
08140baa3e making builtin write bounded to avoid cycles (fixes issue #532) 2019-04-02 22:31:33 +08:00
Alex Shinn
8b4acbcf71
Merge pull request #530 from Oxyd/win-fixes
Fix tests on Windows
2019-03-14 21:19:11 +08:00
Ondřej Majerech
7d82b76bc3 Fix tests on Windows 2019-03-13 22:56:06 +01:00
Alex Shinn
cd10668b3c adding true color ansi support 2019-03-13 23:57:22 +08:00
Alex Shinn
cf1f333731 fixing edge cases 2019-03-12 00:37:00 +08:00
Alex Shinn
80b360b800 Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-03-12 00:20:53 +08:00
Alex Shinn
956e7ba761 allow proper list for comma-rule 2019-03-11 23:51:42 +08:00
Alex Shinn
2e43aea7fc
Merge pull request #528 from katterjohn/readme-openbsd
Note that chibi works on OpenBSD in the README
2019-03-11 18:30:28 +08:00
Alex Shinn
269c8daf87
Merge pull request #527 from katterjohn/sysctl-inclusion
Remove duplicate sys/sysctl.h inclusion
2019-03-11 18:29:59 +08:00
Kris Katterjohn
c2615bc906 Note that chibi works on OpenBSD in the README
I have been successfully building and using chibi on both 32-bit
and 64-bit OpenBSD for over a year.
2019-03-10 15:03:48 -05:00
Kris Katterjohn
93ec1b0875 Remove duplicate sys/sysctl.h inclusion 2019-03-10 14:08:35 -05:00
Alex Shinn
bd78ebeed7 updating sign-rule to respect finalized SRFI 159 2019-03-10 14:50:44 +08:00
Alex Shinn
e921fdb95c
Merge pull request #526 from Oxyd/master
Fix typo in sexp_get_output_string documentation
2019-03-09 09:41:41 +08:00
Ondřej Majerech
801bffc3ab Fix typo in sexp_get_output_string documentation 2019-03-09 02:01:39 +01:00
Alex Shinn
80bf4013f9 exact zero minus a number is negation (fixes issue #523) 2019-03-05 23:35:15 +08:00
Alex Shinn
09b564ed7b catch failure to grow heap 2019-03-03 23:30:00 +08:00
Alex Shinn
d1bb4c27a4 removing undocumented upcased and downcased 2019-02-28 00:19:01 +08:00
Alex Shinn
7380564933 inserting commas in numerator and denominator separately for rationals 2019-02-28 00:09:08 +08:00
Alex Shinn
4c5bdcb22c allowing strings for decimal-sep; s/fn-fork/forked/g 2019-02-27 23:59:10 +08:00
Alex Shinn
2c3dfbd295 fixing default padding/trimming to be left, matching the spec (from SRFI 13 convention) 2019-02-27 22:52:18 +08:00
Alex Shinn
a126417ebe fleshing out srfi 160 api 2019-02-26 23:08:52 +08:00
Alex Shinn
a94a2c7902 uvector fixes 2019-02-25 23:01:35 +08:00
Alex Shinn
7b3413ec1a fixing bounds checks on u32 and u64 vectors 2019-02-21 02:55:35 +08:00
Alex Shinn
a5a7345df9 add 0085 (NEXT LINE) to char-set:whitespace (fixes #515 2019-02-10 22:36:23 +08:00
Alex Shinn
456853921b typos (fixing issue #512) 2019-02-05 22:49:10 +08:00
Alex Shinn
017bb1c2a0 adding -Dsafe-string-cursors feature to perform extra checks on string cursors 2019-02-01 00:31:13 +08:00
Alex Shinn
ef0a8bd199 restoring efficient read-line 2019-01-27 22:10:35 +08:00
Alex Shinn
e9ce08da78 adding note that marc wrote syntax-case in AUTHORS 2019-01-26 17:52:37 +08:00
Alex Shinn
77a964d16e Merge branch 'master' of github.com:ashinn/chibi-scheme 2019-01-26 05:35:32 +08:00
Alex Shinn
9569460a58 add compile-time option to store precomputed index->cursor tables for strings 2019-01-26 05:35:27 +08:00
Alex Shinn
08930ff41f
Merge pull request #511 from Oxyd/fix-makefile
Fix Makefile
2019-01-21 23:47:16 +08:00
Ondřej Majerech
fa7a35abae Add lib/srfi/160/uvprims.c to .gitignore 2019-01-20 20:36:52 +01:00
Ondřej Majerech
f08a6503b2 Create $prefix/lib/chibi/srfi/160 when installing
Otherwise, the Makefile installs lib/srfi/160/base.sld as
$prefix/lib/chici/srfi/160 instead of installing it into that directory.
2019-01-20 20:32:25 +01:00
Alex Shinn
677ccdce68
Merge pull request #509 from y-stm/fix-typo
typo in Makefile
2019-01-18 01:58:49 +08:00
anergy
cfcc0b021f typo in Makefile 2019-01-17 22:06:16 +09:00
Alex Shinn
d24d75621d fixing nofeature build 2019-01-16 08:33:04 +08:00
Alex Shinn
8c0c57ae6c typo in Makefile 2019-01-16 07:13:27 +08:00
Alex Shinn
2b4394ea74 adding initial support for SRFI 160 uniform vectors 2019-01-15 23:43:50 +08:00
Alex Shinn
afd887e672 update-repository shouldn't exit 2019-01-11 08:48:45 +08:00
Alex Shinn
1b3ccdaf1c fixing link to http-server docs 2019-01-06 08:52:11 +08:00
Alex Shinn
6b18b70b44 adding link to http-server docs 2019-01-06 08:47:03 +08:00
Alex Shinn
003d3d3328 clarifying default config params for http-server 2019-01-06 08:45:48 +08:00
Alex Shinn
ec0b6e98f6 also print error 2019-01-06 08:22:43 +08:00
Alex Shinn
c3189ebc9d warn when config fails to load 2019-01-06 08:19:43 +08:00
Alex Shinn
5f80618544 make-conf should validate it gets an alist 2019-01-04 01:53:49 +08:00
Alex Shinn
c9b4786648 fix default chibi.net.http-server file server for paths other than . 2019-01-03 07:39:08 +08:00
Alex Shinn
336a69a416 -R needs interpreter name, not SRFI 22 2019-01-01 23:18:49 +08:00
Alex Shinn
2962f68ced fix -R usage 2019-01-01 22:49:50 +08:00
Alex Shinn
74eb616c50 noting NetBSD support (thanks Riastradh) 2018-12-29 10:51:46 +08:00
Alex Shinn
b782ee575b removing duplicate revomal of program-name in (chibi app) 2018-12-28 23:48:13 +08:00
Alex Shinn
479efcdc33 don't start thread checking for leap seconds if env var is unspecified 2018-12-28 23:40:55 +08:00
Alex Shinn
ec345fe370 typo, export ellipsis-identifier? 2018-12-28 23:40:26 +08:00
Alex Shinn
43d6d20598 fix -xchibi.primitive and spurious output in snow-chibi (thanks Martin Hayman) 2018-12-28 23:29:13 +08:00
Alex Shinn
264cbc756f
Merge pull request #506 from edw/srfi-159
SRFI 159 definition has a typo
2018-12-24 11:15:13 +08:00
Edwin Watkeys
d256ebd368 fix typo update!->with in srfi-159 2018-12-23 11:25:45 +01:00
Edwin Watkeys
ddc8b39e7e Merge branch 'master' of https://github.com/ashinn/chibi-scheme 2018-12-23 11:13:49 +01:00
Alex Shinn
c250685607 updating names of core types in (chibi ast) docs after switching to upper-case (fixes issue #505) 2018-12-17 01:11:27 +08:00
Edwin Watkeys
7635cefe4f Merge branch 'master' of https://github.com/ashinn/chibi-scheme 2018-12-14 15:20:48 +01:00
Alex Shinn
90ed977202 Merge branch 'master' of github.com:ashinn/chibi-scheme 2018-12-11 22:54:18 +08:00
Alex Shinn
e0f23d4286
Merge pull request #504 from edw/args
Fix invocation of main caused by fix for #484
2018-12-11 22:54:00 +08:00
Alex Shinn
7b428d2a54
Merge pull request #503 from edw/parse->list
Parse->list calls parse->fold with incorrect argument order
2018-12-11 22:44:59 +08:00
Edwin Watkeys
2be201a2c1 Merge branch 'parse->list' of https://github.com/edw/chibi-scheme 2018-12-11 14:15:56 +01:00
Edwin Watkeys
6c9e5d3c54 fix invocation of main 2018-12-11 14:08:45 +01:00
Edwin Watkeys
c912f1e24f fix order of arguments to parse-fold 2018-12-11 12:46:42 +01:00
Alex Shinn
960c39c4bf ignore generated file with derived char-sets 2018-12-11 00:28:27 +08:00
Alex Shinn
670cd82488 ignore generated file with derived char-sets 2018-12-10 23:58:33 +08:00
Alex Shinn
06c27d81ce command-line shouldn't include interpreter name (fixes issue #484) 2018-12-10 23:44:39 +08:00
Alex Shinn
f0a8930ab4
Merge pull request #502 from mnieper/with-ellipsis
with-ellipsis
2018-12-10 22:10:42 +08:00
Marc Nieper-Wißkirchen
d2fbd59ae5 Export ellipsis-identifier? 2018-12-09 19:06:24 +01:00
Marc Nieper-Wißkirchen
5d978dd37b Implement with-ellipsis 2018-12-09 19:05:22 +01:00
Alex Shinn
2c37dfedd3
Merge pull request #500 from mnieper/syntax-case
Implement syntax-case
2018-12-09 04:08:31 +08:00
Alex Shinn
77a6ca8ea7 supporting ber encoding in bytevectors 2018-12-09 03:44:19 +08:00
Alex Shinn
3aae0e8481 supporting non-native endianness and non-finite floating values 2018-12-06 23:25:18 +08:00
Alex Shinn
9af77c9b4f adding CHIBI_IGNORE_SYSTEM_PATH=1 env var (fixes issue #501) 2018-12-06 00:54:21 +08:00
Marc Nieper-Wisskirchen
5c963df96f Move datum->syntax back to init-7.scm. Don't crash when renamer not present in syntactic closure. 2018-12-05 15:59:39 +01:00
Marc Nieper-Wißkirchen
081a2a7b3f Construct constructor/predicate names in the syntactic context of the record name, not the context of the invokation of define-record-type 2018-12-05 12:15:17 +01:00
Alex Shinn
d513bdc977 adding floating point utils for bytevectors 2018-12-04 00:43:08 +08:00
Alex Shinn
11ccfcb5de support exact scaling of bignum literals via moderate sized exponents 2018-12-03 23:05:00 +08:00
Alex Shinn
13311e78c5 Merge branch 'master' of github.com:ashinn/chibi-scheme 2018-12-02 12:23:17 +08:00
Alex Shinn
521e23e3c7 Reduce error in sexp_read_float_tail (from Taylor R Campbell)
scale*10 is computed exactly until scale exceeds 2^54/10; in
contrast, scale*0.1 may not be computed exactly, and fl(0.1) is not
even 0.1.

WARNING: This change is not complete -- it does nothing to prevent
overflow with very long strings of digits after the decimal point.
2018-12-02 12:22:14 +08:00
Marc Nieper-Wisskirchen
152b20f244 Implement syntax-case 2018-12-01 13:48:25 +01:00
Alex Shinn
3c4d839c71
Merge pull request #498 from amirouche/emsdk-update
Emsdk update
2018-11-27 23:12:09 +08:00
Alex Shinn
5bbef040c5 BSD portability fixes from Taylor Campbell 2018-11-27 23:01:23 +08:00
Amirouche
80dea6ce19 Makefile: export 'cwrap' and 'ccall' from emscripten 2018-11-25 19:12:05 +01:00
Amirouche
13dacf870a js/exported_functions.json: make it proper json 2018-11-25 19:10:35 +01:00
Alex Shinn
b5331233cb adding missing status response in http-send-directory (thanks to Martin Hayman) 2018-11-19 22:06:43 +08:00
Alex Shinn
7435174d3b
Merge pull request #493 from mnieper/master
Make write/display output bytevectors with hex constants (issue #483)
2018-11-08 23:24:52 +08:00
Marc Nieper-Wisskirchen
5519679dcd Display zeros in bytevectors as '0' 2018-11-08 16:16:07 +01:00
Marc Nieper-Wisskirchen
f9be5c8d46 Make write/display output bytevectors with hex constants (issue #483) 2018-11-06 14:22:38 +01:00
Alex Shinn
3f9dfb7837 fixing call to call-with-temp-file for HEAD requests 2018-11-06 15:09:18 +08:00
Alex Shinn
59e5584ab2
Merge pull request #492 from edw/repl-history
add history support as $0...9
2018-11-04 23:10:47 +08:00
Edwin Watkeys
cbe1b045b4 add history documentation 2018-10-31 14:51:49 -04:00
Edwin Watkeys
5bcd37477f add history support as $0...9 2018-10-31 13:12:30 -04:00
Alex Shinn
78c757af4b
Merge pull request #487 from vaartis/gc-heap-extern-c
Add C++ extern "C" to gc_heap.h
2018-10-05 02:43:08 +08:00
Ekaterina Vaartis
5f161d03ce Add C++ extern "C" to gc_heap.h 2018-10-04 10:49:30 +03:00
Alex Shinn
a7584ae647 allow zero-or-more (*) combining characters in the 'grapheme SRE rather than one-or-more (+) 2018-09-18 23:21:27 +08:00
Alex Shinn
7830ca1654 Merge branch 'master' of https://github.com/ashinn/chibi-scheme 2018-08-24 10:27:39 +08:00
Alex Shinn
9c0d8d0a86 adding docs for sexp_env_import 2018-08-24 10:27:06 +08:00
Alex Shinn
96de49efb8
Merge pull request #481 from katterjohn/master
Avoid undefined C macro behavior
2018-07-30 10:37:53 +08:00
Kris Katterjohn
f32def466b Avoid undefined C macro behavior
A C macro expanding to a `defined' has undefined behavior.  The
clang compiler was issuing warnings.
2018-07-29 19:58:37 -05:00
Alex Shinn
bce1e6a4d2 adding define-c-strerror 2018-07-23 23:59:52 +08:00
Alex Shinn
17102697e9 no need to zero out calloc result in ffi 2018-07-16 23:33:00 +08:00
Alex Shinn
b52df76e8a
Merge pull request #480 from Hamayama/synrule
Fix syntax-rules on ellipsis escape templates
2018-07-08 22:25:04 +08:00
Hamayama
216d6a8d87 Revert and fix syntax-rules by reflecting review 2018-07-05 00:53:17 +09:00
Hamayama
fdc1f86f09 Fix syntax-rules on ellipsis escape templates 2018-07-03 12:41:00 +09:00
Alex Shinn
0efa071672 use PRId64/32 where available for printing fixnums (issue #479) 2018-06-29 22:44:16 +08:00
Alex Shinn
f5a228ee9e fixing bug in flushed output on custom ports 2018-06-23 19:21:38 +08:00
Alex Shinn
f16e889e04
Merge pull request #478 from okuoku/win32-cmake
Activate Win64 platform with MSVC
2018-06-21 22:36:56 +08:00
okuoku
961131d5e1 doc: Update README-win32.md to reflect recent changes 2018-06-20 21:22:36 +09:00
okuoku
dcf23aaa02 AppVeyor: Add MSVC x64 configuration to CI 2018-06-20 21:22:36 +09:00
okuoku
432b763555 cmake: Use SEXP_64BIT on Win64
Do not override SEXP_64BIT on Win64 as now we have custom-long-long for
it.
2018-06-20 21:16:40 +09:00
Alex Shinn
f9bd4f9c0e
Merge pull request #477 from tramboi/expt_fix
Expt fix
2018-06-20 18:46:11 +08:00
Alex Shinn
12d7c1638e
Merge pull request #475 from tramboi/master
More portable bignums
2018-06-20 18:45:38 +08:00
Bertrand Augereau
952d7c806b More portable bignums that don't have to rely on gcc 128bit arithmetics extension
SEXP_USE_CUSTOM_LONG_LONGS currently needs SEXP_64_BIT
2018-06-19 04:46:05 +02:00
Bertrand Augereau
ce9c60c1e8 Fix (expt 3 -1) when SEXP_USE_BIGNUMS 2018-06-16 09:41:09 +02:00
Alex Shinn
5f428d1299 limit waiting in thread scheduler to 10ms 2018-06-13 22:33:39 +08:00
Alex Shinn
e8c10ce259
Merge pull request #476 from tramboi/expt_neg
(expt bignum -k) was equal to (expt bignum k)
2018-06-10 22:39:07 +08:00
Bertrand Augereau
d88dfeb172 Fix (expt bignum -k) 2018-06-10 03:21:00 +02:00
Bertrand Augereau
4d8933119f Test that (expt bignum -k) is correct 2018-06-10 03:20:35 +02:00
Alex Shinn
39043bc47c support infinite real with exact zero imaginary literals (issue #474) 2018-06-09 18:02:50 +08:00
Alex Shinn
22f87f67ab char names should obey case-(in)sensitivity (issue #471) 2018-05-12 19:43:02 +08:00
Alex Shinn
bfcab41056 add cc command line to ffi debug output 2018-05-12 07:39:26 +08:00
Alex Shinn
10ed000e1b
Merge pull request #469 from jacius/invalid_apply
Raise error if apply is called with invalid args.
2018-04-15 22:02:14 +09:00
John Croisant
42dd447a06 Raise error if apply is called with invalid args.
* If called with only the procedure, but no args list.
* If called with a final arg that is not a proper list.
2018-04-14 20:49:03 -05:00
Alex Shinn
d8e2e4aa54 add support for user-defined error types and functions in ffi, address-of, frameworks 2018-04-14 23:22:02 +09:00
Alex Shinn
10759e8bdb moving some scripts to tools/ 2018-04-05 22:21:33 +09:00
Alex Shinn
72de3ba12f exit codes should be exact (issue #467) 2018-04-05 22:11:05 +09:00
Alex Shinn
278911e93c
Merge pull request #466 from okuoku/fix-pull-465
test: Do not create file under /tmp in show-test
2018-04-04 23:35:11 +09:00
okuoku
583c45a6c1 test: Do not create file under /tmp in show-test
Do not create test file under /tmp as it might break
concurrent builds. Creating file on the current directory should
suffice.
2018-04-04 05:27:03 +09:00
Alex Shinn
656efad587 updating note about thread status in TODO 2018-04-03 07:53:36 +09:00
Alex Shinn
ecbaa9939a require proof of the presence of synclos before stripping them with quote (issue #464) 2018-04-01 21:38:21 +09:00
Alex Shinn
f67f63d570 fixing number->string for numbers within an ulp of round numbers 2018-04-01 21:01:58 +09:00
Alex Shinn
060cfd550e
Merge pull request #465 from jimrees/master
changes from jim rees
2018-04-01 15:32:32 +09:00
Alex Shinn
502a011b18 Merge branch 'master' of https://github.com/ashinn/chibi-scheme 2018-04-01 10:47:02 +09:00
Alex Shinn
757b8969dd
Merge pull request #463 from katterjohn/master
Avoid placing duplicate feature identifiers in the features list
2018-04-01 10:46:51 +09:00
Kris Katterjohn
5e80cb2c2b In my last commit, make the feature variable a gc variable 2018-03-31 20:23:00 -05:00
Kris Katterjohn
dc80bf4f04 Avoid placing duplicate feature identifiers in the (features) list
In my case "bsd" was present twice on my *BSD boxes
2018-03-31 14:19:18 -05:00
Alex Shinn
731c544872
Merge pull request #462 from katterjohn/master
Check for valid "rest" parameters in parameter lists
2018-03-29 18:45:23 +09:00
Kris Katterjohn
439e35da61 Check for valid "rest" parameters in parameter lists
Checks for invalid parameter names and duplicate parameters were
being performed on parameter lists, but these checks were not
considering any rest parameters.  This means that

  ((lambda (x . x) x) 'foo 'bar)   =>  foo
  ((lambda (x . 0) x) 'foo 'bar)   =>  foo
  ((lambda (x . #t) x) 'foo 'bar)  =>  foo
  ((lambda 0 'foo))                =>  foo
  ((lambda #t 'foo))               =>  foo

and so on.  Now these all produce errors.
2018-03-28 21:11:33 -05:00
Jim Rees
9b72412e4e Added additional show-tests which demonstrate recent bugs & fixes. 2018-03-27 14:47:14 -04:00
Jim Rees
b3100857fd Fixed escaped to support the documented double-quoting functionality
when esc-char is #f.
2018-03-26 06:44:37 -04:00
Jim Rees
88e8d89460 Fixed integer-log-base to use exact arithmetic so rounding doesn't cause
a wrong result to things like (numeric (- (* 36 36 36) 1) 36).

Fixed a bug in numeric that caused comma-sep and dec-sep to get
initialized wrongly.

Fixed maybe-trim-zeros to leave behind at least a ".0" on
inexact numbers that otherwise would have been output without
the decimal point.  This is for consistency with number->string
which is used when the radix is 10.

In gen-general, fixed a bug in the digit-generating loop for the
whole part of the number.  Previously, an integer that should
have looked like 5003 would be emitted as 5300.

Switched the order of application of maybe-round and
maybe-trim-zeros so that a number that should round to
.0000000000000001 doesn't get emitted as 0.1.

In gen-positive-real, fixed the ratio case to not call
number->string with a radix that might not be in {2,8,10,16}.

Also in gen-positive-real, fixed the call to number->string to
include the radix which was missing previously.

Fixed wrap-sign to correctly handle the case of -0.0.

In numeric/si, always emit the supplied separator even if the
number is too small for an SI-suffix to be emitted.  The
examples in the SRFI document depend on this.
2018-03-23 12:22:03 -04:00
Jim Rees
17eb19e43d Changed sexp_double_to_bignum to extract "digits" in base-16 rather
than base 10 so no round-off errors occur at each step.  This is
assuming FLT_RADIX is 2,4,8 or 16.
2018-03-23 10:50:15 -04:00
Jim Rees
b25e46b11b Introduced a second version of sexp_double_to_ratio, named
sexp_double_to_ratio_2, which converts without introducing
round-off errors the way sexp_double_to_ratio does when it
multiplies by 10.

Changed sexp_inexact_to_exact to use this new function when
a non-zero fractional part of the input exists.
2018-03-22 22:19:39 -04:00
Jim Rees
406aacf4dd try-fitted2/output* calls output on the argument string if it's
determined the string will not exceed the column width.  But
output is the caller environment's output state variable.  A
better choice is output-default.

In two places (length+ form) is replaced with (or (length+ form) +inf.0)
so that arithmetic can be performed on the result.

To support cyclic structures in pretty-simply (wrapped with
trimmed/lazy), the call-with-output form in pp-with-indent needs to be
wrapped with an appropriate trimmed/lazy.

In pp-pair, call (pp (car ls)) instead of (pretty (car ls)).

In pretty-simply, don't use call-with-output, that prevents
(trimmed/lazy n (pretty-simply ...)) from working at all on cyclic
input.
2018-03-22 11:06:55 -04:00
Jim Rees
b947e4ef47 Fixed trivial bug in padded/both where the "odd space" was being emitted
on the left rather than the right as specified.

Fixed trivial bug in padded/left where a string longer than the provided
width would result in a call to make-string with a negative length.

Fixed trivial bug in trimmed/lazy around an fn-binding for the output
state variable.
2018-03-22 10:41:52 -04:00
Jim Rees
ece2d470c3 Fixed from-file so that it produces more than just one line of output. 2018-03-22 09:50:34 -04:00
Alex Shinn
098d50d4e4 Merge branch 'master' of https://github.com/ashinn/chibi-scheme 2018-03-17 17:01:42 +09:00
Alex Shinn
933aeb5654 tests which expect an inexact value can accept an equivalent exact value 2018-03-17 16:50:41 +09:00
Alex Shinn
d0b63109e8
Merge pull request #461 from jacius/remainder_inf
Regression tests for remainder with infinity
2018-03-16 22:40:32 +09:00
John Croisant
fe85ccc94a Add regression tests for remainder with infinity. 2018-03-15 21:48:19 -05:00
John Croisant
3c41f9d3e2 Add "test-division" Makefile target.
Runs tests/division-tests.scm. The "test-all" target now also runs
test-division.
2018-03-15 21:43:21 -05:00
John Croisant
c5345a5b48 Fix errors in tests/division-tests.scm.
Import (scheme base) to get the basic division procedures.

The "centered" procedures were renamed to "balanced" in commit
975dc690a1.

Also cleaned up some trailing whitespace.
2018-03-15 21:37:08 -05:00
Alex Shinn
d167f90802
Merge pull request #460 from jacius/remainder_inf
Raise type error if remainder called with infinity.
2018-03-15 21:46:25 +09:00
John Croisant
e5d9ccb69f Raise type error if remainder called with infinity.
To prevent an infinite loop, raise a type error if the remainder
procedure is called with +inf.0 or -inf.0 as either argument.
2018-03-15 02:42:26 -05:00
Alex Shinn
f0c9f0e705 adding chibi-version variable to (chibi ast) 2018-03-11 23:47:33 +09:00
Alex Shinn
e4cc2dd33c default comparator compares numbers with = (issue #459) 2018-03-10 11:11:59 +09:00
Alex Shinn
d07170d6c3 Documenting sexp_register_c_type and sexp_make_cpointer. 2018-02-18 09:19:36 +09:00
Alex Shinn
e5f6c1bbba adding better debugging for zero-sized object warning 2018-02-16 17:01:21 +09:00
Alex Shinn
dc76aee1d6 s/sexp_init/sexp_scheme_init/ 2018-02-15 10:15:26 +09:00
Alex Shinn
1658cf66d6 adding sexp_init() (noop by default) to C example in docs 2018-02-15 10:13:18 +09:00
Alex Shinn
7ae96fdba5 typo in vector-select! 2018-02-01 15:43:46 +09:00
430 changed files with 38130 additions and 4534 deletions

30
.githooks/pre-commit Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
if git rev-parse --verify HEAD >/dev/null 2>&1; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# fail if we add any new lines to C or Scheme source containing a tab
if git diff --name-only "$against" | egrep -q '\.(cpp|h|scm|sld|stub)$' &&\
git diff --name-only "$against" |\
egrep '\.(cpp|h|scm|sld|stub)$' |\
xargs -d'\n' git diff -U0 --no-color "$against" -- |\
grep -q $'^+ *\t'; then
echo "Error: Attempting to add a source file using tabs for indentation."
echo
echo -n " "
git diff --name-only "$against" |\
egrep '\.(cpp|h|scm|sld|stub)$' |\
xargs -d'\n' git diff -U0 "$against" -- |\
grep $'^+ *\t' | head -1
echo
cat <<EOF
It's important for arguments to line up vertically to a precise column.
Since there is no standard tab width, using tabs for indentation makes
this impossible in general. Please use spaces.
EOF
exit 1
fi

23
.github/workflows/CI.yaml vendored Normal file
View file

@ -0,0 +1,23 @@
name: CI
on: [push, pull_request]
jobs:
build:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v2
- name: Build
run: make # assumes GNUMake
- name: Test
run: make test-all
- name: Setup
run: sudo make install
- name: Run in PATH
run: chibi-scheme r7rs-tests.scm
working-directory: tests

14
.gitignore vendored
View file

@ -46,18 +46,30 @@ lib/chibi/filesystem.c
lib/chibi/io/io.c lib/chibi/io/io.c
lib/chibi/net.c lib/chibi/net.c
lib/chibi/process.c lib/chibi/process.c
lib/chibi/pty.c
lib/chibi/snow/install.sld
lib/chibi/stty.c lib/chibi/stty.c
lib/chibi/system.c lib/chibi/system.c
lib/chibi/time.c lib/chibi/time.c
lib/chibi/win32/process-win32.c lib/chibi/win32/process-win32.c
lib/scheme/bytevector.c
lib/srfi/144/math.c lib/srfi/144/math.c
lib/srfi/160/uvprims.c
*.tgz *.tgz
*.bz2
*.xz
*.html *.html
*.img *.img
*.err *.err
*.fasl *.fasl
*.txt
!CMakeLists.txt
*.test
*.train
*.h5
!index.html !index.html
benchmarks/gabriel/times.tsv
examples/snow-fort examples/snow-fort
examples/synthcode examples/synthcode
tests/snow/repo-cache tests/snow/repo-cache
@ -70,3 +82,5 @@ tmp
js/chibi.* js/chibi.*
build-lib/chibi/char-set/derived.scm
build-lib/chibi/char-set/width.scm

31
AUTHORS
View file

@ -1,8 +1,8 @@
Alex Shinn wrote the initial version of chibi-scheme and all Alex Shinn wrote the initial version of chibi-scheme and all
distributed modules. distributed modules.
The Emscripten build, SRFI 139 implementation, and various other The Emscripten build, syntax-case and SRFI 139 implementation, and
patches were contributed by Marc Nieper-Wißkirchen. various other patches were contributed by Marc Nieper-Wißkirchen.
The image handling code in gc_heap.c was written by Chris Walsh. The image handling code in gc_heap.c was written by Chris Walsh.
@ -14,11 +14,16 @@ The (scheme time) module includes code for handling leap seconds
from Alan Watson's Scheme clock library at from Alan Watson's Scheme clock library at
http://code.google.com/p/scheme-clock/ under the same license. http://code.google.com/p/scheme-clock/ under the same license.
The lgamma_r implementation for Windows builds is based on code by
Haruhiko Okumura via Ruby.
The following distributed SRFIs use the reference implementations: The following distributed SRFIs use the reference implementations:
(srfi 101) is adapted from David van Horn's implementation (srfi 101) is adapted from David van Horn's implementation
(srfi 134) is Shiro Kawai's implementation (srfi 134) is Shiro Kawai's implementation
(srfi 135) is Will Clinger's implementation (srfi 135) is Will Clinger's implementation
(srfi 139), (srfi 146), (srfi 154), (srfi 165) are Marc Nieper-Wißkirchen's implementations
(srfi 146 hash) is Arthur Gleckler's Hash Array Mapped Trie implementation
The benchmarks are based on the Racket versions of the classic The benchmarks are based on the Racket versions of the classic
Gabriel benchmarks from Gabriel benchmarks from
@ -27,35 +32,57 @@ They are not installed or needed but are included for convenience.
Thanks to the following people for patches and bug reports: Thanks to the following people for patches and bug reports:
* Adam Feuer
* Alan Watson * Alan Watson
* Alexei Lozovsky * Alexei Lozovsky
* Alexander Shendi * Alexander Shendi
* Andreas Rottman * Andreas Rottman
* Arthur Gleckler
* Bakul Shah * Bakul Shah
* Ben Davenport-Ray
* Ben Mather * Ben Mather
* Ben Weaver * Ben Weaver
* Bertrand Augereau
* Bradley Lucier
* Bruno Deferrari * Bruno Deferrari
* Damien Diederen
* Daphne Preston-Kendal
* Doug Currie * Doug Currie
* Derrick Eddington * Derrick Eddington
* Dmitry Chestnykh * Dmitry Chestnykh
* Eduardo Cavazos * Eduardo Cavazos
* Ekaitz Zarraga
* Felix Winkelmann * Felix Winkelmann
* Gregor Klinke * Gregor Klinke
* Jeremy Wolff * Jeremy Wolff
* Jeronimo Pellegrini * Jeronimo Pellegrini
* John Cowan * John Cowan
* John Samsa * John Samsa
* Jonas Rinke
* Kris Katterjohn
* Lars J Aas * Lars J Aas
* Lassi Kortela
* Lorenzo Campedelli * Lorenzo Campedelli
* Lukas Böger
* Marc Nieper-Wißkirchen * Marc Nieper-Wißkirchen
* McKay Marston
* Meng Zhang * Meng Zhang
* Michal Kowalski (sladegen) * Michal Kowalski (sladegen)
* Miroslav Urbanek * Miroslav Urbanek
* Naoki Koguro
* Nguyễn Thái Ngọc Duy
* Petteri Piiroinen
* Rajesh Krishnan * Rajesh Krishnan
* Ricardo G. Herdt
* Roger Crew
* Seth Alves * Seth Alves
* Sören Tempel
* Stephen Lewis * Stephen Lewis
* Taylor Venable * Taylor Venable
* Travis Cross * Travis Cross
* Vasilij Schneidermann
* Vitaliy Mysak
* Yota Toyama
* Yuki Okumura * Yuki Okumura
If you would prefer not to be listed, or are one of the users listed If you would prefer not to be listed, or are one of the users listed

View file

@ -1,20 +1,28 @@
#
# FIXME: This CMakeLists.txt is only for Win32 platforms for now
#
cmake_minimum_required(VERSION 2.8.7) cmake_minimum_required(VERSION 3.12)
project(chibi-scheme)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VERSION version)
string(STRIP ${version} version)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/RELEASE release)
string(STRIP ${release} release)
project(chibi-scheme LANGUAGES C VERSION ${version}
DESCRIPTION "Chibi-Scheme: minimal r7rs implementation, release: ${release}")
include(CheckIncludeFile) include(CheckIncludeFile)
include(CheckSymbolExists)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
if(APPLE) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
message(FATAL_ERROR
"DYLD platforms are not supported with this CMakeLists.txt. Use Makefile instead.")
endif()
if(UNIX) set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
message(FATAL_ERROR "Build type: None, Debug, Release, RelWithDebInfo, MinSizeRel, or Sanitizer." FORCE)
"UNIX platforms are not supported with this CMakeLists.txt. Use Makefile instead.")
if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt AND NOT CMAKE_BUILD_TYPE)
# CMake doesn't have a default build type, so set one manually
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
endif() endif()
# #
@ -22,48 +30,77 @@ endif()
# #
check_include_file(poll.h HAVE_POLL_H) check_include_file(poll.h HAVE_POLL_H)
check_include_file(stdint.h HAVE_STDINT_H) check_symbol_exists(ntp_gettime sys/timex.h HAVE_NTP_GETTIME)
# option(CHIBI_SCHEME_USE_DL "Use dynamic loading" ON) check_symbol_exists(int_least8_t inttypes.h HAVE_STDINT_H)
set(CHIBI_SCHEME_USE_DL OFF)
if(CHIBI_SCHEME_USE_DL) if (WIN32 AND NOT CYGWIN)
add_definitions(-DSEXP_USE_DL=1) set(DEFAULT_SHARED_LIBS OFF)
else() else()
add_definitions(-DSEXP_USE_DL=0) set(DEFAULT_SHARED_LIBS ON)
endif() endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8) option(BUILD_SHARED_LIBS "Build chibi-scheme as a shared library" ${DEFAULT_SHARED_LIBS})
if(MSVC) option(SEXP_USE_BOEHM "Use Boehm garbage collection library" OFF)
# On MSVC, SEXP_64_BIT is not supported for now (#438)
add_definitions(-DSEXP_64_BIT=0)
else()
add_definitions(-DSEXP_64_BIT=1)
endif()
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
add_definitions(-DSEXP_64_BIT=0)
endif()
if(HAVE_STDINT_H) if(SEXP_USE_BOEHM)
add_definitions(-DSEXP_USE_INTTYPES=1) find_library(BOEHMGC gc REQUIRED)
endif() find_path(BOEHMGC_INCLUDE NAMES gc/gc.h)
if(NOT HAVE_POLL_H)
# Disable green threads: It depends on non-blocking I/O
add_definitions(-DSEXP_USE_GREEN_THREADS=0)
endif() endif()
set(chibi-scheme-exclude-modules) set(chibi-scheme-exclude-modules)
if(WIN32) if(WIN32)
add_definitions(-DBUILDING_DLL)
set(chibi-scheme-exclude-modules set(chibi-scheme-exclude-modules
# Following modules are not compatible with Win32 # Following modules are not compatible with Win32
lib/chibi/net.sld lib/chibi/net.sld
lib/chibi/process.sld lib/chibi/process.sld
lib/chibi/stty.sld lib/chibi/stty.sld
lib/chibi/system.sld lib/chibi/system.sld
lib/chibi/time.sld) lib/chibi/time.sld
lib/chibi/pty.sld)
endif() endif()
#
# Default settings for all targets. We use an interface library here to not
# pollute/mutate global settings. Any configuration applied to this library
# is propagated to its client targets.
#
add_library(libchibi-common
INTERFACE)
target_compile_definitions(libchibi-common
INTERFACE
SEXP_STATIC_LIBRARY=$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>
SEXP_USE_DL=$<BOOL:${BUILD_SHARED_LIBS}>
$<$<PLATFORM_ID:Windows>:BUILDING_DLL=$<BOOL:${BUILD_SHARED_LIBS}>>
SEXP_USE_INTTYPES=$<BOOL:${HAVE_STDINT_H}>
SEXP_USE_NTPGETTIME=$<BOOL:${HAVE_NTP_GETTIME}>
$<$<NOT:$<BOOL:${HAVE_POLL_H}>>:SEXP_USE_GREEN_THREADS=0>
$<$<PLATFORM_ID:Windows>:SEXP_USE_STRING_STREAMS=0>
$<$<BOOL:${SEXP_USE_BOEHM}>:SEXP_USE_BOEHM=1>)
target_compile_options(libchibi-common
INTERFACE
$<$<C_COMPILER_ID:GNU>:-Wall>
$<$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>:-Wall>
$<$<CONFIG:SANITIZER>:-g
-fsanitize=address,undefined,integer,float-divide-by-zero,float-cast-overflow,return
-fno-omit-frame-pointer>)
target_include_directories(libchibi-common
INTERFACE
${BOEHMGC_INCLUDE}
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_link_libraries(libchibi-common INTERFACE
${BOEHMGC}
$<$<CONFIG:SANITIZER>:-fsanitize=address,undefined>
$<$<PLATFORM_ID:Windows>:ws2_32>
$<$<AND:$<PLATFORM_ID:Linux>,$<BOOL:${BUILD_SHARED_LIBS}>>:${CMAKE_DL_LIBS}>
$<$<PLATFORM_ID:Linux>:m>)
# #
# Sources # Sources
# #
@ -81,65 +118,163 @@ set(chibi-scheme-srcs
eval.c eval.c
simplify.c) simplify.c)
include_directories(
include
${CMAKE_CURRENT_BINARY_DIR}/include)
# #
# Bootstrap # Bootstrap
# #
add_executable(chibi-scheme-bootstrap add_executable(chibi-scheme-bootstrap
EXCLUDE_FROM_ALL
${chibi-scheme-srcs} ${chibi-scheme-srcs}
main.c) main.c)
if(WIN32) target_link_libraries(chibi-scheme-bootstrap PRIVATE libchibi-common)
target_link_libraries(chibi-scheme-bootstrap ws2_32)
endif()
#
# Core library
#
add_library(libchibi-scheme
${chibi-scheme-srcs})
target_link_libraries(libchibi-scheme
PUBLIC libchibi-common)
set_target_properties(libchibi-scheme
PROPERTIES
PREFIX "" # It's liblibchibi-scheme otherwise
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}
VERSION ${CMAKE_PROJECT_VERSION})
if(CYGWIN OR WIN32)
set(soext ".dll")
else()
set(soext ".so")
endif()
# #
# Generate modules # Generate modules
# #
# FIXME: Currently, it depends on GLOB thus we have to re-run CMake
# when we've gotten additional/removed library
file(GLOB_RECURSE stubs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/lib/*.stub)
file(GLOB_RECURSE slds RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} file(GLOB_RECURSE slds RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib/*.sld) CONFIGURE_DEPENDS lib/*.sld)
if (chibi-scheme-exclude-modules)
# CMake doesn't complain anymore about an empty 2nd argument, but 3.12 does. When we require a
# more recent version, the if-guard should go.
list(REMOVE_ITEM slds ${chibi-scheme-exclude-modules}) list(REMOVE_ITEM slds ${chibi-scheme-exclude-modules})
endif()
set(chibi-ffi ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-ffi) set(chibi-ffi ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-ffi)
set(chibi-genstatic ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-genstatic) set(chibi-genstatic ${CMAKE_CURRENT_SOURCE_DIR}/tools/chibi-genstatic)
set(stuboutdir ${CMAKE_CURRENT_BINARY_DIR}/stubs/lib) add_custom_target(chibi-compiled-libs)
foreach(e ${stubs})
get_filename_component(stubdir ${e} PATH) function(add_compiled_library cfile)
get_filename_component(basename ${e} NAME_WE) if (NOT BUILD_SHARED_LIBS)
set(stubfile ${CMAKE_CURRENT_SOURCE_DIR}/lib/${e}) return()
set(stubdir ${stuboutdir}/${stubdir}) endif()
set(link-libraries LINK_LIBRARIES)
cmake_parse_arguments(compiledlib-options "" "" "${link-libraries}" ${ARGN})
get_filename_component(basename ${cfile} NAME_WE)
get_filename_component(libdir ${cfile} DIRECTORY)
if(NOT IS_ABSOLUTE ${libdir})
set(libdir ${CMAKE_CURRENT_BINARY_DIR}/${libdir})
endif()
file(RELATIVE_PATH libname ${CMAKE_CURRENT_BINARY_DIR} ${libdir}/${basename})
string(REPLACE "/" "-" libname ${libname})
add_library(${libname} ${cfile})
target_link_libraries(${libname} PRIVATE libchibi-scheme ${compiledlib-options_LINK_LIBRARIES})
add_dependencies(chibi-compiled-libs ${libname})
set_target_properties(${libname} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${libdir}
LIBRARY_OUTPUT_NAME ${basename}
PREFIX "")
file(RELATIVE_PATH installsubdir ${CMAKE_CURRENT_BINARY_DIR}/lib ${libdir})
install(TARGETS ${libname}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/chibi/${installsubdir})
endfunction()
if(BUILD_SHARED_LIBS)
# This makes sure we only use the separate bootstrap executable for static
# builds. With dynamic linking, the default executable is fine. The dispatch
# is not a generator expression within the actual custom command to process
# the stubs, as older CMake versions fail to properly construct the dependency
# on the bootstrap executable from the generator expression.
set(bootstrap chibi-scheme)
else()
set(bootstrap chibi-scheme-bootstrap)
endif()
function(add_stubs_library stub)
set(link-libraries LINK_LIBRARIES)
cmake_parse_arguments(stubs-options "" "" "${link-libraries}" ${ARGN})
get_filename_component(stubdir ${stub} PATH)
get_filename_component(basename ${stub} NAME_WE)
set(stubfile ${CMAKE_CURRENT_SOURCE_DIR}/${stub})
set(stubdir ${CMAKE_CURRENT_BINARY_DIR}/${stubdir})
set(stubout ${stubdir}/${basename}.c) set(stubout ${stubdir}/${basename}.c)
set(stubouts ${stubouts} ${stubout} PARENT_SCOPE)
set(stublinkedlibs ${stublinkedlibs} ${stubs-options_LINK_LIBRARIES} PARENT_SCOPE)
file(MAKE_DIRECTORY ${stubdir}) file(MAKE_DIRECTORY ${stubdir})
add_custom_command(OUTPUT ${stubout} add_custom_command(OUTPUT ${stubout}
COMMAND chibi-scheme-bootstrap COMMAND ${bootstrap} ${chibi-ffi} ${stubfile} ${stubout}
${chibi-ffi} ${stubfile} ${stubout}
DEPENDS ${stubfile} ${chibi-ffi} DEPENDS ${stubfile} ${chibi-ffi}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND stubouts ${stubout})
endforeach() add_compiled_library(${stubout} LINK_LIBRARIES ${stubs-options_LINK_LIBRARIES})
endfunction()
add_stubs_library(lib/chibi/crypto/crypto.stub)
add_stubs_library(lib/chibi/emscripten.stub)
add_stubs_library(lib/chibi/filesystem.stub)
add_stubs_library(lib/chibi/io/io.stub)
add_stubs_library(lib/scheme/bytevector.stub)
add_stubs_library(lib/srfi/144/math.stub)
add_stubs_library(lib/srfi/160/uvprims.stub)
if(NOT WIN32)
add_stubs_library(lib/chibi/net.stub)
add_stubs_library(lib/chibi/process.stub)
add_stubs_library(lib/chibi/pty.stub LINK_LIBRARIES util)
add_stubs_library(lib/chibi/stty.stub)
add_stubs_library(lib/chibi/system.stub)
add_stubs_library(lib/chibi/time.stub)
else()
add_stubs_library(lib/chibi/win32/process-win32.stub)
endif()
add_custom_target(chibi-scheme-stubs DEPENDS ${stubouts}) add_custom_target(chibi-scheme-stubs DEPENDS ${stubouts})
if (NOT BUILD_SHARED_LIBS)
add_dependencies(libchibi-scheme chibi-scheme-stubs)
endif()
add_compiled_library(lib/chibi/weak.c)
add_compiled_library(lib/chibi/heap-stats.c)
add_compiled_library(lib/chibi/disasm.c)
add_compiled_library(lib/chibi/ast.c)
add_compiled_library(lib/chibi/json.c)
add_compiled_library(lib/srfi/18/threads.c)
add_compiled_library(lib/chibi/optimize/rest.c)
add_compiled_library(lib/chibi/optimize/profile.c)
add_compiled_library(lib/srfi/27/rand.c)
add_compiled_library(lib/srfi/151/bit.c)
add_compiled_library(lib/srfi/39/param.c)
add_compiled_library(lib/srfi/69/hash.c)
add_compiled_library(lib/srfi/95/qsort.c)
add_compiled_library(lib/srfi/98/env.c)
add_compiled_library(lib/scheme/time.c)
# #
# Generate clib.c for SEXP_USE_STATIC_LIBS # Generate clib.c for SEXP_USE_STATIC_LIBS
# #
if (NOT BUILD_SHARED_LIBS)
string(REPLACE ";" "\n" genstatic-input "${slds}") string(REPLACE ";" "\n" genstatic-input "${slds}")
set(clibin ${CMAKE_CURRENT_BINARY_DIR}/clib-in.txt) set(clibin ${CMAKE_CURRENT_BINARY_DIR}/clib-in.txt)
set(clibout ${CMAKE_CURRENT_BINARY_DIR}/clib.c) set(clibout ${CMAKE_CURRENT_BINARY_DIR}/clib.c)
@ -162,70 +297,75 @@ add_custom_command(OUTPUT ${clibout}
${genstatic-helper} ${genstatic-helper}
${slds}) ${slds})
# The generated file will #include both manually written files in
# the source directory as well as files generated by chibi-ffi in
# the build directory. The latter can be found without special flags,
# as they are relative to the clib.c, but the preprocessor needs
# help for the former. As only clib.c needs this flag, we set it
# as locally as possible, i.e., not as a target property.
set_source_files_properties(${clibout}
PROPERTIES
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(libchibi-scheme
PUBLIC
SEXP_USE_STATIC_LIBS=1)
target_sources(libchibi-scheme
PRIVATE
${clibout})
target_link_libraries(libchibi-scheme
PRIVATE
${stublinkedlibs})
endif()
# #
# Interpreter # Interpreter
# #
include_directories(
.
${stuboutdir}/..)
add_executable(chibi-scheme add_executable(chibi-scheme
${chibi-scheme-srcs}
${clibout}
main.c) main.c)
set_target_properties(chibi-scheme target_link_libraries(chibi-scheme
PROPERTIES COMPILE_DEFINITIONS "SEXP_USE_STATIC_LIBS=1") PRIVATE libchibi-scheme)
add_dependencies(chibi-scheme chibi-scheme-stubs)
if(WIN32)
target_link_libraries(chibi-scheme ws2_32)
endif()
# #
# Generate "chibi/install.h" # Generate "chibi/install.h"
# #
if(CYGWIN OR WIN32)
set(thePrefix "bin")
else()
set(thePrefix "lib")
endif()
if(WIN32)
set(pathsep "\\;")
else()
set(pathsep ":")
endif()
if(WIN32) if(WIN32)
set(platform "windows") set(platform "windows")
elseif(CYGWIN)
set(platform "cygwin")
elseif(APPLE)
set(platform "macosx")
elseif(CMAKE_SYSTEM MATCHES "[Bb][Ss][Dd]")
set(platform "bsd")
elseif(CMAKE_SYSTEM MATCHES "[Aa]ndroid")
set(platform "android")
elseif(CMAKE_SYSTEM MATCHES "[Ss]un[Oo][Ss]")
set(platform "solaris")
elseif (CMAKE_SYSTEM MATCHES "[Ll]inux")
set(platform "linux")
else() else()
set(platform "unknown") set(platform "unix")
endif() endif()
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/RELEASE release) if(WIN32)
string(STRIP ${release} release) # Leave this empty for now, as the default GNU install directories won't
# help on Windows.
set(default_module_path "")
else()
string(JOIN ":" default_module_path
${CMAKE_INSTALL_FULL_DATAROOTDIR}/chibi
${CMAKE_INSTALL_FULL_LIBDIR}/chibi
${CMAKE_INSTALL_FULL_DATAROOTDIR}/snow
${CMAKE_INSTALL_FULL_LIBDIR}/snow)
endif()
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VERSION version) configure_file(include/chibi/install.h.in include/chibi/install.h)
string(STRIP ${version} version)
set(version "${version}-cmake")
set(default_module_path
""
#"${CMAKE_INSTALL_PREFIX}/${thePrefix}${pathsep}${CMAKE_INSTALL_PREFIX}/bin"
)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/chibi)
file(WRITE
${CMAKE_CURRENT_BINARY_DIR}/include/chibi/install.h
"#define sexp_so_extension \"${soext}\"
#define sexp_default_module_path \"${default_module_path}\"
#define sexp_platform \"${platform}\"
#define sexp_version \"\"
#define sexp_release_name \"${release}\"")
# #
# Testing # Testing
@ -235,28 +375,27 @@ enable_testing()
set(chibi-scheme-tests set(chibi-scheme-tests
r7rs-tests r7rs-tests
## Not connected division-tests
#division-tests syntax-tests
#r5rs-tests unicode-tests)
#syntax-tests
#unicode-tests
## Require threads
# lib-tests
)
foreach(e ${chibi-scheme-tests}) foreach(e ${chibi-scheme-tests})
add_test(NAME "${e}" add_test(NAME "${e}"
COMMAND chibi-scheme tests/${e}.scm COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib tests/${e}.scm
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endforeach() endforeach()
add_test(NAME r5rs-test
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -xchibi tests/r5rs-tests.scm
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE srfi_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib file(GLOB_RECURSE srfi_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/lib/srfi/*/test.sld) CONFIGURE_DEPENDS lib/srfi/*/test.sld)
file(GLOB_RECURSE chibi_scheme_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib file(GLOB_RECURSE chibi_scheme_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/lib/chibi/*-test.sld) CONFIGURE_DEPENDS lib/chibi/*-test.sld)
set(testexcludes set(win32testexcludes
# Excluded tests # Excluded tests
chibi/filesystem-test chibi/filesystem-test
chibi/memoize-test chibi/memoize-test
@ -270,22 +409,195 @@ set(testexcludes
chibi/system-test chibi/system-test
chibi/tar-test # Depends (chibi system) chibi/tar-test # Depends (chibi system)
chibi/process-test # Not applicable chibi/process-test # Not applicable
chibi/pty-test # Depends (chibi pty)
chibi/shell-test # Depends Linux procfs
) )
set(testlibs)
foreach(e ${srfi_tests} ${chibi_scheme_tests}) foreach(e ${srfi_tests} ${chibi_scheme_tests})
get_filename_component(pth ${e} PATH) get_filename_component(pth ${e} PATH)
get_filename_component(nam ${e} NAME_WE) get_filename_component(nam ${e} NAME_WE)
list(APPEND testlibs ${pth}/${nam}) list(APPEND testlibs ${pth}/${nam})
endforeach() endforeach()
list(REMOVE_ITEM testlibs ${testexcludes})
if(WIN32)
list(REMOVE_ITEM testlibs ${win32testexcludes})
endif()
foreach(e ${testlibs}) foreach(e ${testlibs})
string(REGEX REPLACE "/" "_" testname ${e}) string(REGEX REPLACE "/" "_" testname ${e})
string(REGEX REPLACE "/" " " form ${e}) string(REGEX REPLACE "/" " " form ${e})
add_test(NAME "lib_${testname}" add_test(NAME "lib_${testname}"
COMMAND chibi-scheme -e "(import (${form}))" COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib
-e "(import (${form}))"
-e "(run-tests)" -e "(run-tests)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endforeach() endforeach()
#
# Testing (embedding)
#
add_executable(test-foreign-apply-loop
tests/foreign/apply-loop.c)
target_link_libraries(test-foreign-apply-loop
PRIVATE libchibi-scheme)
add_test(NAME "foreign-apply-loop"
COMMAND test-foreign-apply-loop
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_executable(test-foreign-typeid
tests/foreign/typeid.c)
target_link_libraries(test-foreign-typeid
PRIVATE libchibi-scheme)
add_test(NAME "foreign-typeid"
COMMAND test-foreign-typeid
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
#
# Image, pkgconfig and meta file generation
#
add_custom_command(OUTPUT chibi.img
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -mchibi.repl
-d ${CMAKE_CURRENT_BINARY_DIR}/chibi.img
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_command(OUTPUT red.img
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib -xscheme.red -mchibi.repl
-d ${CMAKE_CURRENT_BINARY_DIR}/red.img
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_command(OUTPUT snow.img
COMMAND chibi-scheme -I ${CMAKE_CURRENT_BINARY_DIR}/lib
-mchibi.snow.commands -mchibi.snow.interface -mchibi.snow.package -mchibi.snow.utils
-d ${CMAKE_CURRENT_BINARY_DIR}/snow.img
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(BUILD_SHARED_LIBS)
# Currently, image dumps only work with shared library builds, which includes Windows
add_custom_target(chibi-images ALL
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/chibi.img
${CMAKE_CURRENT_BINARY_DIR}/red.img
${CMAKE_CURRENT_BINARY_DIR}/snow.img
# The dependency on libchibi-scheme is crucial here:
chibi-compiled-libs)
endif()
configure_file(contrib/chibi-scheme.pc.cmake.in chibi-scheme.pc @ONLY)
function(generate_package_list libdir output)
add_custom_command(OUTPUT ${output}
COMMAND
${CMAKE_COMMAND}
-DEXEC=$<TARGET_FILE:chibi-scheme>
-DLIBDIR=${libdir}
-DGENMETA=tools/generate-install-meta.scm
-DVERSION=${CMAKE_PROJECT_VERSION}
-DOUT=${CMAKE_CURRENT_BINARY_DIR}/${output}
-P contrib/chibi-generate-install-meta-helper.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
chibi-scheme
tools/generate-install-meta.scm
contrib/chibi-generate-install-meta-helper.cmake)
endfunction()
generate_package_list(lib/chibi .chibi.meta)
generate_package_list(lib/scheme .scheme.meta)
generate_package_list(lib/srfi .srfi.meta)
add_custom_target(chibi-meta-lists ALL
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/.chibi.meta
${CMAKE_CURRENT_BINARY_DIR}/.scheme.meta
${CMAKE_CURRENT_BINARY_DIR}/.srfi.meta)
#
# Installation
#
install(DIRECTORY include/chibi
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
PATTERN "sexp-*.[hc]" EXCLUDE
PATTERN "*.h.in" EXCLUDE)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/chibi/install.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/chibi)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/chibi-scheme.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
add_library(chibi::libchibi-scheme ALIAS libchibi-scheme)
install(TARGETS libchibi-scheme libchibi-common chibi-scheme
EXPORT chibi-scheme-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES
tools/chibi-ffi
tools/chibi-doc
tools/snow-chibi
tools/snow-chibi.scm
DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES
doc/chibi-scheme.1
doc/chibi-ffi.1
doc/chibi-doc.1
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
if(BUILD_SHARED_LIBS)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/chibi.img
${CMAKE_CURRENT_BINARY_DIR}/red.img
${CMAKE_CURRENT_BINARY_DIR}/snow.img
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi)
endif()
install(DIRECTORY
lib/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi
PATTERN "*win32" EXCLUDE
PATTERN "*test.sld" EXCLUDE
PATTERN "*.c" EXCLUDE
PATTERN "*.stub" EXCLUDE)
# This is to revert the above exclusion pattern
install(FILES lib/chibi/test.sld
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi/chibi)
if(WIN32)
install(DIRECTORY
lib/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi
FILES_MATCHING
PATTERN "*win32/*.scm"
PATTERN "*win32/*.sld")
endif()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/.chibi.meta
${CMAKE_CURRENT_BINARY_DIR}/.scheme.meta
${CMAKE_CURRENT_BINARY_DIR}/.srfi.meta
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/chibi)
install(EXPORT chibi-scheme-targets
FILE chibi-scheme-targets.cmake
NAMESPACE chibi::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/chibi)
write_basic_package_version_file(chibi-scheme-config-version.cmake
VERSION ${CMAKE_PROJECT_VERSION}
COMPATIBILITY ExactVersion)
install(FILES
contrib/chibi-scheme-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/chibi-scheme-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/chibi)

13
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,13 @@
# Contributing to Chibi-Scheme
Thanks for your interest!
Chibi-Scheme is fun and easy to hack. If you want to contribute your
changes back upstream, there are just a few guidelines:
* Code must be released following the license in COPYING.
* New modules likely belong on snow-fort.org, not the core distribution.
* Chibi values small size over speed.
* Features should be built up in layers, not added directly to the core.
* Once you're ready to contribute, run `make init-dev` to install some
local settings (currently only git submit hooks).

View file

@ -1,4 +1,4 @@
Copyright (c) 2009-2018 Alex Shinn Copyright (c) 2009-2021 Alex Shinn
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

250
Makefile
View file

@ -1,49 +1,33 @@
# -*- makefile-gmake -*- # -*- makefile-gmake -*-
.PHONY: dist mips-dist cleaner test test-all test-dist checkdefs debian snowballs .PHONY: dist mips-dist cleaner distclean dist-clean test test-all test-dist checkdefs debian snowballs init-dev
.DEFAULT_GOAL := all .DEFAULT_GOAL := all
VERSION ?= $(shell cat VERSION) CHIBI_VERSION ?= $(shell cat VERSION)
SOVERSION ?= $(VERSION) SOVERSION ?= $(CHIBI_VERSION)
SOVERSION_MAJOR ?= $(shell echo "$(SOVERSION)" | sed "s/\..*//") SOVERSION_MAJOR ?= $(shell echo "$(SOVERSION)" | sed "s/\..*//")
CHIBI_FFI ?= $(CHIBI) -q tools/chibi-ffi CHIBI_FFI ?= $(CHIBI) -q tools/chibi-ffi
CHIBI_FFI_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-ffi CHIBI_FFI_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-ffi
CHIBI_DOC ?= $(CHIBI) tools/chibi-doc CHIBI_DOC ?= $(CHIBI) tools/chibi-doc
CHIBI_DOC_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-doc CHIBI_DOC_DEPENDENCIES ?= $(CHIBI_DEPENDENCIES) tools/chibi-doc $(COMPILED_LIBS)
GENSTATIC ?= ./tools/chibi-genstatic GENSTATIC ?= ./tools/chibi-genstatic
CHIBI ?= LD_LIBRARY_PATH=".:$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH=".:$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH=lib ./chibi-scheme$(EXE) CHIBI ?= LD_LIBRARY_PATH=".:$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH=".:$(DYLD_LIBRARY_PATH)" CHIBI_IGNORE_SYSTEM_PATH=1 CHIBI_MODULE_PATH=lib ./chibi-scheme$(EXE)
CHIBI_DEPENDENCIES = ./chibi-scheme$(EXE) CHIBI_DEPENDENCIES = ./chibi-scheme$(EXE)
SNOW_CHIBI ?= tools/snow-chibi SNOW_CHIBI ?= tools/snow-chibi
TEMPFILE := $(shell mktemp -t chibi.XXXXXX)
########################################################################
# Choose compiled library on MSYS
ifeq ($(OS), Windows_NT)
ifeq ($(PLATFORM),msys)
EXCLUDE_WIN32_LIBS=1
else
ifeq ($(shell uname -o),Cygwin)
EXCLUDE_WIN32_LIBS=1
else
EXCLUDE_POSIX_LIBS=1
endif
endif
endif
######################################################################## ########################################################################
CHIBI_COMPILED_LIBS = lib/chibi/filesystem$(SO) lib/chibi/weak$(SO) \ CHIBI_COMPILED_LIBS = lib/chibi/filesystem$(SO) lib/chibi/weak$(SO) \
lib/chibi/heap-stats$(SO) lib/chibi/disasm$(SO) lib/chibi/ast$(SO) \ lib/chibi/heap-stats$(SO) lib/chibi/disasm$(SO) lib/chibi/ast$(SO) \
lib/chibi/emscripten$(SO) lib/chibi/json$(SO) lib/chibi/emscripten$(SO)
CHIBI_POSIX_COMPILED_LIBS = lib/chibi/process$(SO) lib/chibi/time$(SO) \ CHIBI_POSIX_COMPILED_LIBS = lib/chibi/process$(SO) lib/chibi/time$(SO) \
lib/chibi/system$(SO) lib/chibi/stty$(SO) lib/chibi/net$(SO) lib/chibi/system$(SO) lib/chibi/stty$(SO) lib/chibi/pty$(SO) \
lib/chibi/net$(SO) lib/srfi/18/threads$(SO)
CHIBI_WIN32_COMPILED_LIBS = lib/chibi/win32/process-win32$(SO) CHIBI_WIN32_COMPILED_LIBS = lib/chibi/win32/process-win32$(SO)
CHIBI_CRYPTO_COMPILED_LIBS = lib/chibi/crypto/crypto$(SO) CHIBI_CRYPTO_COMPILED_LIBS = lib/chibi/crypto/crypto$(SO)
CHIBI_IO_COMPILED_LIBS = lib/chibi/io/io$(SO) CHIBI_IO_COMPILED_LIBS = lib/chibi/io/io$(SO)
@ -51,91 +35,78 @@ CHIBI_OPT_COMPILED_LIBS = lib/chibi/optimize/rest$(SO) \
lib/chibi/optimize/profile$(SO) lib/chibi/optimize/profile$(SO)
EXTRA_COMPILED_LIBS ?= EXTRA_COMPILED_LIBS ?=
ifndef EXCLUDE_POSIX_LIBS
CHIBI_COMPILED_LIBS += $(CHIBI_POSIX_COMPILED_LIBS)
else
CHIBI_COMPILED_LIBS += $(CHIBI_WIN32_COMPILED_LIBS)
endif
COMPILED_LIBS = $(CHIBI_COMPILED_LIBS) $(CHIBI_IO_COMPILED_LIBS) \ COMPILED_LIBS = $(CHIBI_COMPILED_LIBS) $(CHIBI_IO_COMPILED_LIBS) \
$(CHIBI_OPT_COMPILED_LIBS) $(CHIBI_CRYPTO_COMPILED_LIBS) \ $(CHIBI_OPT_COMPILED_LIBS) $(CHIBI_CRYPTO_COMPILED_LIBS) \
$(EXTRA_COMPILED_LIBS) \ $(EXTRA_COMPILED_LIBS) \
lib/srfi/27/rand$(SO) lib/srfi/151/bit$(SO) \ lib/srfi/27/rand$(SO) lib/srfi/151/bit$(SO) \
lib/srfi/39/param$(SO) lib/srfi/69/hash$(SO) lib/srfi/95/qsort$(SO) \ lib/srfi/39/param$(SO) lib/srfi/69/hash$(SO) lib/srfi/95/qsort$(SO) \
lib/srfi/98/env$(SO) lib/srfi/144/math$(SO) lib/scheme/time$(SO) lib/srfi/98/env$(SO) lib/srfi/144/math$(SO) lib/srfi/160/uvprims$(SO) \
lib/scheme/bytevector$(SO) lib/scheme/time$(SO)
ifndef EXCLUDE_POSIX_LIBS
COMPILED_LIBS += lib/srfi/18/threads$(SO)
endif
BASE_INCLUDES = include/chibi/sexp.h include/chibi/features.h include/chibi/install.h include/chibi/bignum.h BASE_INCLUDES = include/chibi/sexp.h include/chibi/features.h include/chibi/install.h include/chibi/bignum.h
INCLUDES = $(BASE_INCLUDES) include/chibi/eval.h include/chibi/gc_heap.h INCLUDES = $(BASE_INCLUDES) include/chibi/eval.h include/chibi/gc_heap.h
MODULE_DOCS := app ast config disasm equiv filesystem generic heap-stats io \ MODULE_DOCS := app assert ast base64 binary-record bytevector config \
loop match mime modules net parse pathname process repl scribble stty \ crypto/md5 crypto/rsa crypto/sha2 diff disasm doc edit-distance \
system test time trace type-inference uri weak monad/environment \ equiv filesystem generic heap-stats io \
show show/base crypto/sha2 iset/base iset/constructors iset/iterators json loop \
match math/prime memoize mime modules net net/http-server net/servlet \
optional parse pathname process repl scribble string stty sxml system \
temp-file test time trace type-inference uri weak monad/environment \
crypto/sha2 shell
IMAGE_FILES = lib/chibi.img lib/red.img lib/snow.img IMAGE_FILES = lib/chibi.img lib/red.img lib/snow.img
HTML_LIBS = $(MODULE_DOCS:%=doc/lib/chibi/%.html) HTML_LIBS = $(MODULE_DOCS:%=doc/lib/chibi/%.html) doc/lib/srfi/166/base.html
META_FILES = lib/.chibi.meta lib/.srfi.meta lib/.scheme.meta META_FILES = lib/.chibi.meta lib/.srfi.meta lib/.scheme.meta
######################################################################## ########################################################################
# This includes the rules to build optional libraries.
# It also pulls in Makefile.detect for platform detection.
include Makefile.libs include Makefile.libs
########################################################################
# Library config.
#
# This is to allow "make SEXP_USE_BOEHM=1" and "make SEXP_USE_DL=0" to
# automatically include the necessary compiler and linker flags in
# addition to setting those features. If not using GNU make just
# comment out the ifs and use the else branches for the defaults.
ifeq ($(SEXP_USE_BOEHM),1)
GCLDFLAGS := -lgc
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%) -DSEXP_USE_BOEHM=1
else
GCLDFLAGS :=
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%)
endif
ifeq ($(SEXP_USE_DL),0)
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) -lm
XCFLAGS := -Wall -DSEXP_USE_DL=0 -g -g3 -O3 $(CFLAGS)
else
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) $(LIBDL) -lm
XCFLAGS := -Wall -g -g3 -O3 $(CFLAGS)
endif
######################################################################## ########################################################################
all: chibi-scheme$(EXE) all-libs chibi-scheme.pc $(META_FILES) all: chibi-scheme$(EXE) all-libs chibi-scheme.pc $(META_FILES)
# Please run this if you want to contribute.
init-dev:
git config core.hooksPath .githooks
js: js/chibi.js js: js/chibi.js
js/chibi.js: chibi-scheme-emscripten chibi-scheme-static.bc js/pre.js js/post.js js/exported_functions.json js/chibi.js: chibi-scheme-emscripten chibi-scheme-static.bc js/pre.js js/post.js js/exported_functions.json
emcc -O3 chibi-scheme-static.bc -o $@ -s MODULARIZE=1 -s EXPORT_NAME=\"Chibi\" -s EXPORTED_FUNCTIONS=@js/exported_functions.json `find lib -type f \( -name "*.scm" -or -name "*.sld" \) -printf " --preload-file %p"` --pre-js js/pre.js --post-js js/post.js emcc -O0 chibi-scheme-static.bc -o $@ -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=\"Chibi\" -s EXPORTED_FUNCTIONS=@js/exported_functions.json `find lib -type f \( -name "*.scm" -or -name "*.sld" \) -printf " --preload-file %p"` -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]' --pre-js js/pre.js --post-js js/post.js
chibi-scheme-static.bc: chibi-scheme-static.bc:
emmake $(MAKE) PLATFORM=emscripten CHIBI_DEPENDENCIES= CHIBI=./chibi-scheme-emscripten PREFIX= CFLAGS=-O2 SEXP_USE_DL=0 EXE=.bc SO=.bc CPPFLAGS="-DSEXP_USE_STRICT_TOPLEVEL_BINDINGS=1 -DSEXP_USE_ALIGNED_BYTECODE=1 -DSEXP_USE_STATIC_LIBS=1 -DSEXP_USE_STATIC_LIBS_NO_INCLUDE=0" clibs.c chibi-scheme-static.bc emmake $(MAKE) PLATFORM=emscripten CHIBI_DEPENDENCIES= CHIBI=./chibi-scheme-emscripten PREFIX= CFLAGS=-O2 SEXP_USE_DL=0 EXE=.bc SO=.bc STATICFLAGS=-shared CPPFLAGS="-DSEXP_USE_STRICT_TOPLEVEL_BINDINGS=1 -DSEXP_USE_ALIGNED_BYTECODE=1 -DSEXP_USE_STATIC_LIBS=1 -DSEXP_USE_STATIC_LIBS_NO_INCLUDE=0" clibs.c chibi-scheme-static.bc VERBOSE=1
chibi-scheme-emscripten: VERSION chibi-scheme-emscripten: VERSION
$(MAKE) dist-clean $(MAKE) distclean
$(MAKE) chibi-scheme-static PLATFORM=emscripten SEXP_USE_DL=0 $(MAKE) chibi-scheme-static PLATFORM=emscripten SEXP_USE_DL=0
mv chibi-scheme-static$(EXE) $(TEMPFILE) (tempfile="`mktemp -t chibi.XXXXXX`" && \
$(MAKE) dist-clean mv chibi-scheme-static$(EXE) "$$tempfile" && \
mv $(TEMPFILE) chibi-scheme-emscripten $(MAKE) distclean; \
mv "$$tempfile" chibi-scheme-emscripten)
include/chibi/install.h: Makefile include/chibi/install.h: Makefile.libs Makefile.detect
echo '#define sexp_so_extension "'$(SO)'"' > $@ echo '#define sexp_so_extension "'$(SO)'"' > $@
echo '#define sexp_default_module_path "'$(MODDIR):$(BINMODDIR)'"' >> $@ echo '#define sexp_default_module_path "'$(MODDIR):$(BINMODDIR):$(SNOWMODDIR):$(SNOWBINMODDIR)'"' >> $@
echo '#define sexp_platform "'$(PLATFORM)'"' >> $@ echo '#define sexp_platform "'$(PLATFORM)'"' >> $@
echo '#define sexp_version "'$(VERSION)'"' >> $@ echo '#define sexp_architecture "'$(ARCH)'"' >> $@
echo '#define sexp_version "'$(CHIBI_VERSION)'"' >> $@
echo '#define sexp_release_name "'`cat RELEASE`'"' >> $@ echo '#define sexp_release_name "'`cat RELEASE`'"' >> $@
lib/chibi/snow/install.sld: Makefile.libs Makefile.detect
echo '(define-library (chibi snow install)' > $@
echo ' (import (scheme base))' >> $@
echo ' (export snow-module-directory snow-binary-module-directory)' >> $@
echo ' (begin' >> $@
echo ' (define snow-module-directory "'$(SNOWMODDIR)'")' >> $@
echo ' (define snow-binary-module-directory "'$(SNOWBINMODDIR)'")))' >> $@
%.o: %.c $(BASE_INCLUDES) %.o: %.c $(BASE_INCLUDES)
$(CC) -c $(XCPPFLAGS) $(XCFLAGS) $(CLIBFLAGS) -o $@ $< $(CC) -c $(XCPPFLAGS) $(XCFLAGS) $(CLIBFLAGS) -o $@ $<
@ -168,16 +139,20 @@ libchibi-scheme.a: $(SEXP_OBJS) $(EVAL_OBJS)
$(AR) rcs $@ $^ $(AR) rcs $@ $^
chibi-scheme$(EXE): main.o libchibi-scheme$(SO) chibi-scheme$(EXE): main.o libchibi-scheme$(SO)
$(CC) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. -lchibi-scheme $(CC) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) -lchibi-scheme
chibi-scheme-static$(EXE): main.o $(SEXP_OBJS) $(EVAL_OBJS) chibi-scheme-static$(EXE): main.o $(SEXP_OBJS) $(EVAL_OBJS)
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) -lm $(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) $(STATIC_LDFLAGS)
chibi-scheme-ulimit$(EXE): main.o $(SEXP_ULIMIT_OBJS) $(EVAL_OBJS) chibi-scheme-ulimit$(EXE): main.o $(SEXP_ULIMIT_OBJS) $(EVAL_OBJS)
$(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) -lm $(CC) $(XCFLAGS) $(STATICFLAGS) -o $@ $^ $(LDFLAGS) $(GCLDFLAGS) $(STATIC_LDFLAGS)
clibs.c: $(GENSTATIC) $(CHIBI_DEPENDENCIES) $(COMPILED_LIBS:%$(SO)=%.c) clibs.c: $(GENSTATIC) $(CHIBI_DEPENDENCIES) $(COMPILED_LIBS:%$(SO)=%.c)
$(FIND) lib -name \*.sld | $(CHIBI) -q $(GENSTATIC) > $@ if [ -d .git ]; then \
$(GIT) ls-files lib | $(GREP) .sld | $(CHIBI) -q $(GENSTATIC) > $@; \
else \
$(FIND) lib -name \*.sld | $(CHIBI) -q $(GENSTATIC) > $@; \
fi
chibi-scheme.pc: chibi-scheme.pc.in chibi-scheme.pc: chibi-scheme.pc.in
echo "# pkg-config" > chibi-scheme.pc echo "# pkg-config" > chibi-scheme.pc
@ -185,14 +160,21 @@ chibi-scheme.pc: chibi-scheme.pc.in
echo "exec_prefix=\$${prefix}" >> chibi-scheme.pc echo "exec_prefix=\$${prefix}" >> chibi-scheme.pc
echo "libdir=$(LIBDIR)" >> chibi-scheme.pc echo "libdir=$(LIBDIR)" >> chibi-scheme.pc
echo "includedir=\$${prefix}/include" >> chibi-scheme.pc echo "includedir=\$${prefix}/include" >> chibi-scheme.pc
echo "version=$(VERSION)" >> chibi-scheme.pc echo "version=$(CHIBI_VERSION)" >> chibi-scheme.pc
echo "" >> chibi-scheme.pc echo "" >> chibi-scheme.pc
cat chibi-scheme.pc.in >> chibi-scheme.pc cat chibi-scheme.pc.in >> chibi-scheme.pc
# A special case, this needs to be linked with the LDFLAGS in case # A special case, this needs to be linked with the LDFLAGS in case
# we're using Boehm. # we're using Boehm.
lib/chibi/ast$(SO): lib/chibi/ast.c $(INCLUDES) libchibi-scheme$(SO) lib/chibi/ast$(SO): lib/chibi/ast.c $(INCLUDES) libchibi-scheme$(SO)
-$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< $(GCLDFLAGS) -L. -lchibi-scheme -$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< $(GCLDFLAGS) -L. $(RLDFLAGS) -lchibi-scheme
lib/chibi/crypto/crypto.c: lib/chibi/crypto/sha2.c
lib/chibi/filesystem.c: lib/chibi/filesystem_win32_shim.c
lib/chibi/io/io.c: lib/chibi/io/port.c
lib/chibi/net.c: lib/chibi/accept.c
lib/chibi/process.c: lib/chibi/signal.c
lib/srfi/144/math.c: lib/srfi/144/lgamma_r.c
lib/chibi.img: $(CHIBI_DEPENDENCIES) all-libs lib/chibi.img: $(CHIBI_DEPENDENCIES) all-libs
$(CHIBI) -d $@ $(CHIBI) -d $@
@ -208,9 +190,9 @@ doc: doc/chibi.html doc-libs
%.html: %.scrbl $(CHIBI_DOC_DEPENDENCIES) %.html: %.scrbl $(CHIBI_DOC_DEPENDENCIES)
$(CHIBI_DOC) --html $< > $@ $(CHIBI_DOC) --html $< > $@
lib/.%.meta: lib/%/ tools/generate-install-meta.scm lib/.%.meta: lib/%/ tools/generate-install-meta.scm $(CHIBI_DEPENDENCIES)
-$(FIND) $< -name \*.sld | \ -$(FIND) $< -name \*.sld | \
$(CHIBI) tools/generate-install-meta.scm $(VERSION) > $@ $(CHIBI) tools/generate-install-meta.scm $(CHIBI_VERSION) > $@
######################################################################## ########################################################################
# Dist builds - rules to build generated files included in distribution # Dist builds - rules to build generated files included in distribution
@ -223,14 +205,25 @@ data/%.txt:
build-lib/chibi/char-set/derived.scm: data/UnicodeData.txt data/DerivedCoreProperties.txt chibi-scheme$(EXE) build-lib/chibi/char-set/derived.scm: data/UnicodeData.txt data/DerivedCoreProperties.txt chibi-scheme$(EXE)
$(CHIBI) tools/extract-unicode-props.scm --default > $@ $(CHIBI) tools/extract-unicode-props.scm --default > $@
build-lib/chibi/char-set/width.scm: data/UnicodeData.txt data/EastAsianWidth.txt chibi-scheme$(EXE)
$(CHIBI) tools/extract-unicode-props.scm Zero-Width=Mn > $@
$(CHIBI) tools/extract-unicode-props.scm -d data/EastAsianWidth.txt Full-Width=F@1,W@1 Ambiguous-Width=A@1 >> $@
lib/chibi/char-set/ascii.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE) lib/chibi/char-set/ascii.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE)
$(CHIBI) -Abuild-lib tools/optimize-char-sets.scm --ascii chibi.char-set.compute > $@ $(CHIBI) -Abuild-lib tools/optimize-char-sets.scm --ascii chibi.char-set.compute > $@
lib/chibi/char-set/full.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE) lib/chibi/char-set/full.scm: build-lib/chibi/char-set/derived.scm chibi-scheme$(EXE)
$(CHIBI) -Abuild-lib tools/optimize-char-sets.scm chibi.char-set.compute > $@ $(CHIBI) -Abuild-lib tools/optimize-char-sets.scm chibi.char-set.compute > $@
lib/scheme/char/case-offsets.scm: data/UnicodeData.txt chibi-scheme$(EXE) all-libs lib/chibi/show/width.scm: build-lib/chibi/char-set/width.scm chibi-scheme$(EXE)
$(CHIBI) tools/extract-case-offsets.scm $< > $@ $(CHIBI) -Abuild-lib tools/optimize-char-sets.scm --predicate chibi.char-set.width > $@
lib/scheme/char/case-offsets.scm: data/UnicodeData.txt data/CaseFolding.txt chibi-scheme$(EXE) all-libs
$(CHIBI) tools/extract-case-offsets.scm data/UnicodeData.txt data/CaseFolding.txt > $@
# WARNING: this has a line for ß added by hand
lib/scheme/char/special-casing.scm: data/CaseFolding.txt data/SpecialCasing.txt chibi-scheme$(EXE) all-libs
$(CHIBI) tools/extract-special-casing.scm data/CaseFolding.txt data/SpecialCasing.txt > $@
######################################################################## ########################################################################
# Tests # Tests
@ -270,7 +263,11 @@ test-snow: chibi-scheme$(EXE) $(IMAGE_FILES)
test-unicode: chibi-scheme$(EXE) test-unicode: chibi-scheme$(EXE)
$(CHIBI) -xchibi tests/unicode-tests.scm $(CHIBI) -xchibi tests/unicode-tests.scm
test-division: chibi-scheme$(EXE)
$(CHIBI) tests/division-tests.scm
test-libs: chibi-scheme$(EXE) test-libs: chibi-scheme$(EXE)
@echo "\e[1mloading tests first, it may take a while to see output...\e[0m"
$(CHIBI) tests/lib-tests.scm $(CHIBI) tests/lib-tests.scm
test-r5rs: chibi-scheme$(EXE) test-r5rs: chibi-scheme$(EXE)
@ -279,9 +276,16 @@ test-r5rs: chibi-scheme$(EXE)
test-r7rs: chibi-scheme$(EXE) test-r7rs: chibi-scheme$(EXE)
$(CHIBI) tests/r7rs-tests.scm $(CHIBI) tests/r7rs-tests.scm
test-syntax: chibi-scheme$(EXE)
$(CHIBI) tests/syntax-tests.scm
test: test-r7rs test: test-r7rs
test-all: test test-libs test-ffi test-safe-string-cursors: chibi-scheme$(EXE)
$(CHIBI) -Dsafe-string-cursors tests/r7rs-tests.scm
$(CHIBI) -Dsafe-string-cursors tests/lib-tests.scm
test-all: test test-syntax test-libs test-ffi test-division
test-dist: test-all test-memory test-build test-dist: test-all test-memory test-build
@ -298,12 +302,15 @@ clean: clean-libs
cleaner: clean cleaner: clean
-$(RM) chibi-scheme$(EXE) chibi-scheme-static$(EXE) chibi-scheme-ulimit$(EXE) \ -$(RM) chibi-scheme$(EXE) chibi-scheme-static$(EXE) chibi-scheme-ulimit$(EXE) \
$(IMAGE_FILES) libchibi-scheme*$(SO) *.a *.pc \ $(IMAGE_FILES) libchibi-scheme*$(SO) *.a *.pc \
libchibi-scheme$(SO_VERSIONED_SUFFIX) \
libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX) \
include/chibi/install.h lib/.*.meta \ include/chibi/install.h lib/.*.meta \
chibi-scheme-emscripten \ chibi-scheme-emscripten \
js/chibi.* \ js/chibi.* \
$(shell $(FIND) lib -name \*.o) $(shell $(FIND) lib -name \*.o)
dist-clean: dist-clean-libs cleaner distclean: dist-clean-libs cleaner
dist-clean: distclean
install-base: all install-base: all
$(MKDIR) $(DESTDIR)$(BINDIR) $(MKDIR) $(DESTDIR)$(BINDIR)
@ -312,10 +319,10 @@ install-base: all
$(INSTALL) -m0755 tools/chibi-doc $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 tools/chibi-doc $(DESTDIR)$(BINDIR)/
$(INSTALL) -m0755 tools/snow-chibi $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 tools/snow-chibi $(DESTDIR)$(BINDIR)/
$(INSTALL) -m0755 tools/snow-chibi.scm $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 tools/snow-chibi.scm $(DESTDIR)$(BINDIR)/
$(MKDIR) $(DESTDIR)$(MODDIR)/chibi/char-set $(DESTDIR)$(MODDIR)/chibi/crypto $(DESTDIR)$(MODDIR)/chibi/io $(DESTDIR)$(MODDIR)/chibi/iset $(DESTDIR)$(MODDIR)/chibi/loop $(DESTDIR)$(MODDIR)/chibi/match $(DESTDIR)$(MODDIR)/chibi/math $(DESTDIR)$(MODDIR)/chibi/monad $(DESTDIR)$(MODDIR)/chibi/net $(DESTDIR)$(MODDIR)/chibi/optimize $(DESTDIR)$(MODDIR)/chibi/parse $(DESTDIR)$(MODDIR)/chibi/regexp $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(MODDIR)/chibi/term $(MKDIR) $(DESTDIR)$(MODDIR)/chibi/char-set $(DESTDIR)$(MODDIR)/chibi/crypto $(DESTDIR)$(MODDIR)/chibi/io $(DESTDIR)$(MODDIR)/chibi/iset $(DESTDIR)$(MODDIR)/chibi/loop $(DESTDIR)$(MODDIR)/chibi/match $(DESTDIR)$(MODDIR)/chibi/math $(DESTDIR)$(MODDIR)/chibi/monad $(DESTDIR)$(MODDIR)/chibi/net $(DESTDIR)$(MODDIR)/chibi/optimize $(DESTDIR)$(MODDIR)/chibi/parse $(DESTDIR)$(MODDIR)/chibi/regexp $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(MODDIR)/chibi/term $(DESTDIR)$(MODDIR)/chibi/text
$(MKDIR) $(DESTDIR)$(MODDIR)/scheme/char $(MKDIR) $(DESTDIR)$(MODDIR)/scheme/char
$(MKDIR) $(DESTDIR)$(MODDIR)/scheme/time $(MKDIR) $(DESTDIR)$(MODDIR)/scheme/time
$(MKDIR) $(DESTDIR)$(MODDIR)/srfi/1 $(DESTDIR)$(MODDIR)/srfi/18 $(DESTDIR)$(MODDIR)/srfi/27 $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(MODDIR)/srfi/39 $(DESTDIR)$(MODDIR)/srfi/69 $(DESTDIR)$(MODDIR)/srfi/95 $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(MODDIR)/srfi/113 $(DESTDIR)$(MODDIR)/srfi/117 $(DESTDIR)$(MODDIR)/srfi/121 $(DESTDIR)$(MODDIR)/srfi/125 $(DESTDIR)$(MODDIR)/srfi/128 $(DESTDIR)$(MODDIR)/srfi/129 $(DESTDIR)$(MODDIR)/srfi/132 $(DESTDIR)$(MODDIR)/srfi/133 $(DESTDIR)$(MODDIR)/srfi/135 $(DESTDIR)$(MODDIR)/srfi/143 $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(MODDIR)/srfi/159 $(MKDIR) $(DESTDIR)$(MODDIR)/srfi/1 $(DESTDIR)$(MODDIR)/srfi/18 $(DESTDIR)$(MODDIR)/srfi/27 $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(MODDIR)/srfi/39 $(DESTDIR)$(MODDIR)/srfi/69 $(DESTDIR)$(MODDIR)/srfi/95 $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(MODDIR)/srfi/113 $(DESTDIR)$(MODDIR)/srfi/117 $(DESTDIR)$(MODDIR)/srfi/121 $(DESTDIR)$(MODDIR)/srfi/125 $(DESTDIR)$(MODDIR)/srfi/128 $(DESTDIR)$(MODDIR)/srfi/129 $(DESTDIR)$(MODDIR)/srfi/132 $(DESTDIR)$(MODDIR)/srfi/133 $(DESTDIR)$(MODDIR)/srfi/135 $(DESTDIR)$(MODDIR)/srfi/143 $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(MODDIR)/srfi/159 $(DESTDIR)$(MODDIR)/srfi/160 $(DESTDIR)$(MODDIR)/srfi/166 $(DESTDIR)$(MODDIR)/srfi/146 $(DESTDIR)$(MODDIR)/srfi/179 $(DESTDIR)$(MODDIR)/srfi/211 $(DESTDIR)$(MODDIR)/srfi/231
$(INSTALL) -m0644 $(META_FILES) $(DESTDIR)$(MODDIR)/ $(INSTALL) -m0644 $(META_FILES) $(DESTDIR)$(MODDIR)/
$(INSTALL) -m0644 lib/*.scm $(DESTDIR)$(MODDIR)/ $(INSTALL) -m0644 lib/*.scm $(DESTDIR)$(MODDIR)/
$(INSTALL) -m0644 lib/chibi/*.sld lib/chibi/*.scm $(DESTDIR)$(MODDIR)/chibi/ $(INSTALL) -m0644 lib/chibi/*.sld lib/chibi/*.scm $(DESTDIR)$(MODDIR)/chibi/
@ -334,6 +341,7 @@ install-base: all
$(INSTALL) -m0644 lib/chibi/show/*.sld lib/chibi/show/*.scm $(DESTDIR)$(MODDIR)/chibi/show/ $(INSTALL) -m0644 lib/chibi/show/*.sld lib/chibi/show/*.scm $(DESTDIR)$(MODDIR)/chibi/show/
$(INSTALL) -m0644 lib/chibi/snow/*.sld lib/chibi/snow/*.scm $(DESTDIR)$(MODDIR)/chibi/snow/ $(INSTALL) -m0644 lib/chibi/snow/*.sld lib/chibi/snow/*.scm $(DESTDIR)$(MODDIR)/chibi/snow/
$(INSTALL) -m0644 lib/chibi/term/*.sld lib/chibi/term/*.scm $(DESTDIR)$(MODDIR)/chibi/term/ $(INSTALL) -m0644 lib/chibi/term/*.sld lib/chibi/term/*.scm $(DESTDIR)$(MODDIR)/chibi/term/
$(INSTALL) -m0644 lib/chibi/text/*.sld lib/chibi/text/*.scm $(DESTDIR)$(MODDIR)/chibi/text/
$(INSTALL) -m0644 lib/scheme/*.sld lib/scheme/*.scm $(DESTDIR)$(MODDIR)/scheme/ $(INSTALL) -m0644 lib/scheme/*.sld lib/scheme/*.scm $(DESTDIR)$(MODDIR)/scheme/
$(INSTALL) -m0644 lib/scheme/char/*.sld lib/scheme/char/*.scm $(DESTDIR)$(MODDIR)/scheme/char/ $(INSTALL) -m0644 lib/scheme/char/*.sld lib/scheme/char/*.scm $(DESTDIR)$(MODDIR)/scheme/char/
$(INSTALL) -m0644 lib/scheme/time/*.sld $(DESTDIR)$(MODDIR)/scheme/time/ $(INSTALL) -m0644 lib/scheme/time/*.sld $(DESTDIR)$(MODDIR)/scheme/time/
@ -359,17 +367,29 @@ install-base: all
$(INSTALL) -m0644 lib/srfi/143/*.scm $(DESTDIR)$(MODDIR)/srfi/143/ $(INSTALL) -m0644 lib/srfi/143/*.scm $(DESTDIR)$(MODDIR)/srfi/143/
$(INSTALL) -m0644 lib/srfi/144/*.scm $(DESTDIR)$(MODDIR)/srfi/144/ $(INSTALL) -m0644 lib/srfi/144/*.scm $(DESTDIR)$(MODDIR)/srfi/144/
$(INSTALL) -m0644 lib/srfi/151/*.scm $(DESTDIR)$(MODDIR)/srfi/151/ $(INSTALL) -m0644 lib/srfi/151/*.scm $(DESTDIR)$(MODDIR)/srfi/151/
$(INSTALL) -m0644 lib/srfi/159/*.scm $(DESTDIR)$(MODDIR)/srfi/159/
$(INSTALL) -m0644 lib/srfi/159/*.sld $(DESTDIR)$(MODDIR)/srfi/159/ $(INSTALL) -m0644 lib/srfi/159/*.sld $(DESTDIR)$(MODDIR)/srfi/159/
$(INSTALL) -m0644 lib/srfi/160/*.sld $(DESTDIR)$(MODDIR)/srfi/160/
$(INSTALL) -m0644 lib/srfi/160/*.scm $(DESTDIR)$(MODDIR)/srfi/160/
$(INSTALL) -m0644 lib/srfi/166/*.sld $(DESTDIR)$(MODDIR)/srfi/166/
$(INSTALL) -m0644 lib/srfi/166/*.scm $(DESTDIR)$(MODDIR)/srfi/166/
$(INSTALL) -m0644 lib/srfi/146/*.sld $(DESTDIR)$(MODDIR)/srfi/146/
$(INSTALL) -m0644 lib/srfi/146/*.scm $(DESTDIR)$(MODDIR)/srfi/146/
$(INSTALL) -m0644 lib/srfi/179/*.sld $(DESTDIR)$(MODDIR)/srfi/179/
$(INSTALL) -m0644 lib/srfi/179/*.scm $(DESTDIR)$(MODDIR)/srfi/179/
$(INSTALL) -m0644 lib/srfi/211/*.sld $(DESTDIR)$(MODDIR)/srfi/211/
$(INSTALL) -m0644 lib/srfi/231/*.sld lib/srfi/231/*.scm $(DESTDIR)$(MODDIR)/srfi/231/
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/crypto/ $(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/crypto/
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/io/ $(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/io/
$(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/optimize/ $(MKDIR) $(DESTDIR)$(BINMODDIR)/chibi/optimize/
$(MKDIR) $(DESTDIR)$(BINMODDIR)/scheme/ $(MKDIR) $(DESTDIR)$(BINMODDIR)/scheme/
$(MKDIR) $(DESTDIR)$(BINMODDIR)/srfi/18 $(DESTDIR)$(BINMODDIR)/srfi/27 $(DESTDIR)$(BINMODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/39 $(DESTDIR)$(BINMODDIR)/srfi/69 $(DESTDIR)$(BINMODDIR)/srfi/95 $(DESTDIR)$(BINMODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/144 $(MKDIR) $(DESTDIR)$(BINMODDIR)/srfi/18 $(DESTDIR)$(BINMODDIR)/srfi/27 $(DESTDIR)$(BINMODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/39 $(DESTDIR)$(BINMODDIR)/srfi/69 $(DESTDIR)$(BINMODDIR)/srfi/95 $(DESTDIR)$(BINMODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/144 $(DESTDIR)$(BINMODDIR)/srfi/160
$(INSTALL_EXE) -m0755 $(CHIBI_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/ $(INSTALL_EXE) -m0755 $(CHIBI_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/
$(INSTALL_EXE) -m0755 $(CHIBI_CRYPTO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/crypto/ $(INSTALL_EXE) -m0755 $(CHIBI_CRYPTO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/crypto/
$(INSTALL_EXE) -m0755 $(CHIBI_IO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/io/ $(INSTALL_EXE) -m0755 $(CHIBI_IO_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/io/
$(INSTALL_EXE) -m0755 $(CHIBI_OPT_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/optimize/ $(INSTALL_EXE) -m0755 $(CHIBI_OPT_COMPILED_LIBS) $(DESTDIR)$(BINMODDIR)/chibi/optimize/
$(INSTALL_EXE) -m0755 lib/scheme/time$(SO) $(DESTDIR)$(BINMODDIR)/scheme/ $(INSTALL_EXE) -m0755 lib/scheme/time$(SO) $(DESTDIR)$(BINMODDIR)/scheme/
$(INSTALL_EXE) -m0755 lib/scheme/bytevector$(SO) $(DESTDIR)$(BINMODDIR)/scheme/
$(INSTALL_EXE) -m0755 lib/srfi/18/threads$(SO) $(DESTDIR)$(BINMODDIR)/srfi/18 $(INSTALL_EXE) -m0755 lib/srfi/18/threads$(SO) $(DESTDIR)$(BINMODDIR)/srfi/18
$(INSTALL_EXE) -m0755 lib/srfi/27/rand$(SO) $(DESTDIR)$(BINMODDIR)/srfi/27 $(INSTALL_EXE) -m0755 lib/srfi/27/rand$(SO) $(DESTDIR)$(BINMODDIR)/srfi/27
$(INSTALL_EXE) -m0755 lib/srfi/39/param$(SO) $(DESTDIR)$(BINMODDIR)/srfi/39 $(INSTALL_EXE) -m0755 lib/srfi/39/param$(SO) $(DESTDIR)$(BINMODDIR)/srfi/39
@ -378,6 +398,7 @@ install-base: all
$(INSTALL_EXE) -m0755 lib/srfi/98/env$(SO) $(DESTDIR)$(BINMODDIR)/srfi/98 $(INSTALL_EXE) -m0755 lib/srfi/98/env$(SO) $(DESTDIR)$(BINMODDIR)/srfi/98
$(INSTALL_EXE) -m0755 lib/srfi/144/math$(SO) $(DESTDIR)$(BINMODDIR)/srfi/144 $(INSTALL_EXE) -m0755 lib/srfi/144/math$(SO) $(DESTDIR)$(BINMODDIR)/srfi/144
$(INSTALL_EXE) -m0755 lib/srfi/151/bit$(SO) $(DESTDIR)$(BINMODDIR)/srfi/151 $(INSTALL_EXE) -m0755 lib/srfi/151/bit$(SO) $(DESTDIR)$(BINMODDIR)/srfi/151
$(INSTALL_EXE) -m0755 lib/srfi/160/uvprims$(SO) $(DESTDIR)$(BINMODDIR)/srfi/160
$(MKDIR) $(DESTDIR)$(INCDIR) $(MKDIR) $(DESTDIR)$(INCDIR)
$(INSTALL) -m0644 $(INCLUDES) $(DESTDIR)$(INCDIR)/ $(INSTALL) -m0644 $(INCLUDES) $(DESTDIR)$(INCDIR)/
$(MKDIR) $(DESTDIR)$(LIBDIR) $(MKDIR) $(DESTDIR)$(LIBDIR)
@ -392,14 +413,14 @@ install-base: all
$(INSTALL) -m0644 doc/chibi-scheme.1 $(DESTDIR)$(MANDIR)/ $(INSTALL) -m0644 doc/chibi-scheme.1 $(DESTDIR)$(MANDIR)/
$(INSTALL) -m0644 doc/chibi-ffi.1 $(DESTDIR)$(MANDIR)/ $(INSTALL) -m0644 doc/chibi-ffi.1 $(DESTDIR)$(MANDIR)/
$(INSTALL) -m0644 doc/chibi-doc.1 $(DESTDIR)$(MANDIR)/ $(INSTALL) -m0644 doc/chibi-doc.1 $(DESTDIR)$(MANDIR)/
-if type $(LDCONFIG) >/dev/null 2>/dev/null; then $(LDCONFIG); fi -if type $(LDCONFIG) >/dev/null 2>/dev/null; then $(LDCONFIG) >/dev/null 2>/dev/null; fi
install: install-base install: install-base
ifneq "$(IMAGE_FILES)" "" ifneq "$(IMAGE_FILES)" ""
echo "Generating images" echo "Generating images"
-cd / && LD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" $(DESTDIR)$(BINDIR)/chibi-scheme$(EXE) -d $(DESTDIR)$(MODDIR)/chibi.img -[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -mchibi.repl -d $(MODDIR)/chibi.img
-cd / && LD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" $(DESTDIR)$(BINDIR)/chibi-scheme$(EXE) -xscheme.red -d $(DESTDIR)$(MODDIR)/red.img -[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -xscheme.red -mchibi.repl -d $(MODDIR)/red.img
-cd / && LD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(DESTDIR)$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" $(DESTDIR)$(BINDIR)/chibi-scheme$(EXE) -mchibi.snow.commands -mchibi.snow.interface -mchibi.snow.package -mchibi.snow.utils -d $(DESTDIR)$(MODDIR)/snow.img -[ -z "$(DESTDIR)" ] && LD_LIBRARY_PATH="$(SOLIBDIR):$(LD_LIBRARY_PATH)" DYLD_LIBRARY_PATH="$(SOLIBDIR):$(DYLD_LIBRARY_PATH)" CHIBI_MODULE_PATH="$(MODDIR):$(BINMODDIR)" $(BINDIR)/chibi-scheme$(EXE) -mchibi.snow.commands -mchibi.snow.interface -mchibi.snow.package -mchibi.snow.utils -d $(DESTDIR)$(MODDIR)/snow.img
endif endif
uninstall: uninstall:
@ -414,7 +435,8 @@ uninstall:
-$(RM) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX) -$(RM) $(DESTDIR)$(SOLIBDIR)/libchibi-scheme$(SO_MAJOR_VERSIONED_SUFFIX)
-$(RM) $(DESTDIR)$(LIBDIR)/libchibi-scheme$(SO).a -$(RM) $(DESTDIR)$(LIBDIR)/libchibi-scheme$(SO).a
-$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc -$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc
-$(CD) $(DESTDIR)$(INCDIR) && $(RM) $(INCLUDES) -$(CD) $(DESTDIR)$(PREFIX) && $(RM) $(INCLUDES)
-$(RMDIR) $(DESTDIR)$(INCDIR)
-$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.sld -$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.sld
-$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.scm -$(RM) $(DESTDIR)$(MODDIR)/srfi/99/records/*.scm
-$(RM) $(DESTDIR)$(MODDIR)/.*.meta -$(RM) $(DESTDIR)$(MODDIR)/.*.meta
@ -438,6 +460,7 @@ uninstall:
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(BINMODDIR)/chibi/show -$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/show $(DESTDIR)$(BINMODDIR)/chibi/show
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(BINMODDIR)/chibi/snow -$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/snow $(DESTDIR)$(BINMODDIR)/chibi/snow
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/term $(DESTDIR)$(BINMODDIR)/chibi/term -$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/term $(DESTDIR)$(BINMODDIR)/chibi/term
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi/text $(DESTDIR)$(BINMODDIR)/chibi/text
-$(RMDIR) $(DESTDIR)$(MODDIR)/chibi $(DESTDIR)$(BINMODDIR)/chibi -$(RMDIR) $(DESTDIR)$(MODDIR)/chibi $(DESTDIR)$(BINMODDIR)/chibi
-$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/char $(DESTDIR)$(BINMODDIR)/scheme/char -$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/char $(DESTDIR)$(BINMODDIR)/scheme/char
-$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/time $(DESTDIR)$(BINMODDIR)/scheme/time -$(RMDIR) $(DESTDIR)$(MODDIR)/scheme/time $(DESTDIR)$(BINMODDIR)/scheme/time
@ -451,21 +474,38 @@ uninstall:
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/98 -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/98 $(DESTDIR)$(BINMODDIR)/srfi/98
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(BINMODDIR)/srfi/99/records -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99/records $(DESTDIR)$(BINMODDIR)/srfi/99/records
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(BINMODDIR)/srfi/99 -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/99 $(DESTDIR)$(BINMODDIR)/srfi/99
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/113 $(DESTDIR)$(BINMODDIR)/srfi/113
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/117 $(DESTDIR)$(BINMODDIR)/srfi/117
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/121 $(DESTDIR)$(BINMODDIR)/srfi/121
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/125 $(DESTDIR)$(BINMODDIR)/srfi/125
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/128 $(DESTDIR)$(BINMODDIR)/srfi/128
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/129 $(DESTDIR)$(BINMODDIR)/srfi/129
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/132 $(DESTDIR)$(BINMODDIR)/srfi/132
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/133 $(DESTDIR)$(BINMODDIR)/srfi/133
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/135 $(DESTDIR)$(BINMODDIR)/srfi/135
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/143 $(DESTDIR)$(BINMODDIR)/srfi/143
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/151 -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/151 $(DESTDIR)$(BINMODDIR)/srfi/151
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(BINMODDIR)/srfi/144 -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/144 $(DESTDIR)$(BINMODDIR)/srfi/144
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/146 $(DESTDIR)$(BINMODDIR)/srfi/146
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/159 $(DESTDIR)$(BINMODDIR)/srfi/159
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/160 $(DESTDIR)$(BINMODDIR)/srfi/160
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/166 $(DESTDIR)$(BINMODDIR)/srfi/166
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/179 $(DESTDIR)$(BINMODDIR)/srfi/179
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/211 $(DESTDIR)$(BINMODDIR)/srfi/211
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi/231 $(DESTDIR)$(BINMODDIR)/srfi/231
-$(RMDIR) $(DESTDIR)$(MODDIR)/srfi $(DESTDIR)$(BINMODDIR)/srfi -$(RMDIR) $(DESTDIR)$(MODDIR)/srfi $(DESTDIR)$(BINMODDIR)/srfi
-$(RMDIR) $(DESTDIR)$(MODDIR) $(DESTDIR)$(BINMODDIR) -$(RMDIR) $(DESTDIR)$(MODDIR) $(DESTDIR)$(BINMODDIR)
-$(RM) $(DESTDIR)$(MANDIR)/chibi-scheme.1 $(DESTDIR)$(MANDIR)/chibi-ffi.1 $(DESTDIR)$(MANDIR)/chibi-doc.1 -$(RM) $(DESTDIR)$(MANDIR)/chibi-scheme.1 $(DESTDIR)$(MANDIR)/chibi-ffi.1 $(DESTDIR)$(MANDIR)/chibi-doc.1
-$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc -$(RM) $(DESTDIR)$(PKGCONFDIR)/chibi-scheme.pc
dist: dist-clean dist: distclean
$(RM) chibi-scheme-$(VERSION).tgz $(RM) chibi-scheme-$(CHIBI_VERSION).tgz
$(MKDIR) chibi-scheme-$(VERSION) $(MKDIR) chibi-scheme-$(CHIBI_VERSION)
@for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-$(VERSION)/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-$(VERSION)/$$f; done @for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-$(CHIBI_VERSION)/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-$(CHIBI_VERSION)/$$f; done
$(TAR) cphzvf chibi-scheme-$(VERSION).tgz chibi-scheme-$(VERSION) $(TAR) cphzvf chibi-scheme-$(CHIBI_VERSION).tgz chibi-scheme-$(CHIBI_VERSION)
$(RM) -r chibi-scheme-$(VERSION) $(RM) -r chibi-scheme-$(CHIBI_VERSION)
mips-dist: dist-clean mips-dist: distclean
$(RM) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`.tgz $(RM) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`.tgz
$(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-` $(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`
@for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/$$f; done @for f in `git ls-files | grep -v ^benchmarks/`; do $(MKDIR) chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/`dirname $$f`; $(SYMLINK) `pwd`/$$f chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`/$$f; done
@ -473,7 +513,7 @@ mips-dist: dist-clean
$(RM) -r chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-` $(RM) -r chibi-scheme-`date +%Y%m%d`-`git log HEAD^..HEAD | head -1 | cut -c8-`
debian: debian:
sudo checkinstall -D --pkgname chibi-scheme --pkgversion $(VERSION) --maintainer "http://groups.google.com/group/chibi-scheme" -y make PREFIX=/usr install sudo checkinstall -D --pkgname chibi-scheme --pkgversion $(CHIBI_VERSION) --maintainer "http://groups.google.com/group/chibi-scheme" -y make PREFIX=/usr install
# Libraries in the standard distribution we want to make available to # Libraries in the standard distribution we want to make available to
# other Scheme implementations. Note this is run with my own # other Scheme implementations. Note this is run with my own
@ -484,9 +524,11 @@ snowballs:
$(SNOW_CHIBI) package --license public-domain lib/chibi/match.sld $(SNOW_CHIBI) package --license public-domain lib/chibi/match.sld
$(SNOW_CHIBI) package -r lib/chibi/char-set.sld $(SNOW_CHIBI) package -r lib/chibi/char-set.sld
$(SNOW_CHIBI) package -r lib/chibi/iset.sld lib/chibi/iset/optimize.sld $(SNOW_CHIBI) package -r lib/chibi/iset.sld lib/chibi/iset/optimize.sld
$(SNOW_CHIBI) package -r lib/chibi/show.sld lib/chibi/show/pretty.sld $(SNOW_CHIBI) package --doc https://srfi.schemers.org/srfi-115/srfi-115.html --test-library lib/srfi/115.sld
$(SNOW_CHIBI) package lib/srfi/115.sld $(SNOW_CHIBI) package -r --doc https://srfi.schemers.org/srfi-166/srfi-166.html --test-library lib/srfi/166/test.sld lib/srfi/166.sld lib/chibi/show/shared.sld
$(SNOW_CHIBI) package -r --doc https://srfi.schemers.org/srfi-179/srfi-179.html --test-library lib/srfi/179/test.sld lib/srfi/179.sld
$(SNOW_CHIBI) package lib/chibi/app.sld $(SNOW_CHIBI) package lib/chibi/app.sld
$(SNOW_CHIBI) package lib/chibi/assert.sld
$(SNOW_CHIBI) package lib/chibi/base64.sld $(SNOW_CHIBI) package lib/chibi/base64.sld
$(SNOW_CHIBI) package lib/chibi/binary-record.sld $(SNOW_CHIBI) package lib/chibi/binary-record.sld
$(SNOW_CHIBI) package lib/chibi/bytevector.sld $(SNOW_CHIBI) package lib/chibi/bytevector.sld
@ -494,6 +536,8 @@ snowballs:
$(SNOW_CHIBI) package lib/chibi/crypto/md5.sld $(SNOW_CHIBI) package lib/chibi/crypto/md5.sld
$(SNOW_CHIBI) package lib/chibi/crypto/rsa.sld $(SNOW_CHIBI) package lib/chibi/crypto/rsa.sld
$(SNOW_CHIBI) package lib/chibi/crypto/sha2.sld $(SNOW_CHIBI) package lib/chibi/crypto/sha2.sld
$(SNOW_CHIBI) package lib/chibi/diff.sld
$(SNOW_CHIBI) package lib/chibi/edit-distance.sld
$(SNOW_CHIBI) package lib/chibi/filesystem.sld $(SNOW_CHIBI) package lib/chibi/filesystem.sld
$(SNOW_CHIBI) package lib/chibi/math/prime.sld $(SNOW_CHIBI) package lib/chibi/math/prime.sld
$(SNOW_CHIBI) package lib/chibi/mime.sld $(SNOW_CHIBI) package lib/chibi/mime.sld

View file

@ -9,6 +9,7 @@ PLATFORM=macosx
else else
ifeq ($(shell uname),FreeBSD) ifeq ($(shell uname),FreeBSD)
PLATFORM=bsd PLATFORM=bsd
LIBCHIBI_FLAGS = -Wl,-soname,libchibi-scheme$(SO).$(SOVERSION_MAJOR)
else else
ifeq ($(shell uname),NetBSD) ifeq ($(shell uname),NetBSD)
PLATFORM=bsd PLATFORM=bsd
@ -35,6 +36,9 @@ else
ifeq ($(shell uname -o),GNU/Linux) ifeq ($(shell uname -o),GNU/Linux)
PLATFORM=linux PLATFORM=linux
else else
ifeq ($(shell uname),SunOS)
PLATFORM=solaris
else
PLATFORM=unix PLATFORM=unix
endif endif
endif endif
@ -46,6 +50,11 @@ endif
endif endif
endif endif
endif endif
endif
ifndef ARCH
ARCH = $(shell uname -m)
endif
######################################################################## ########################################################################
# Set default variables for the platform. # Set default variables for the platform.
@ -53,6 +62,7 @@ endif
LIBDL = -ldl LIBDL = -ldl
SO_VERSIONED_SUFFIX = $(SO).$(SOVERSION) SO_VERSIONED_SUFFIX = $(SO).$(SOVERSION)
SO_MAJOR_VERSIONED_SUFFIX = $(SO).$(SOVERSION_MAJOR) SO_MAJOR_VERSIONED_SUFFIX = $(SO).$(SOVERSION_MAJOR)
STATIC_LDFLAGS = -lm -ldl -lutil
ifeq ($(PLATFORM),macosx) ifeq ($(PLATFORM),macosx)
SO = .dylib SO = .dylib
@ -70,6 +80,15 @@ EXE =
CLIBFLAGS = -fPIC CLIBFLAGS = -fPIC
CLINKFLAGS = -shared CLINKFLAGS = -shared
LIBDL = LIBDL =
RLDFLAGS=-Wl,-R$(LIBDIR)
else
ifeq ($(PLATFORM),solaris)
SO = .so
EXE =
CLIBFLAGS = -fPIC
CLINKFLAGS = -shared
LIBDL = -ldl
RLDFLAGS=-Wl,-R$(LIBDIR)
else else
ifeq ($(PLATFORM),windows) ifeq ($(PLATFORM),windows)
SO = .dll SO = .dll
@ -80,6 +99,7 @@ CLINKFLAGS = -shared
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 -DSEXP_USE_GREEN_THREADS=0 -DSEXP_USE_GC_FILE_DESCRIPTORS=0 -DBUILDING_DLL CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 -DSEXP_USE_GREEN_THREADS=0 -DSEXP_USE_GC_FILE_DESCRIPTORS=0 -DBUILDING_DLL
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
STATICFLAGS = STATICFLAGS =
STATIC_LDFLAGS = -lm -ldl
LIBDL = -lws2_32 LIBDL = -lws2_32
else else
ifeq ($(PLATFORM),msys) ifeq ($(PLATFORM),msys)
@ -90,6 +110,7 @@ CLIBFLAGS =
CLINKFLAGS = -shared CLINKFLAGS = -shared
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
STATIC_LDFLAGS = -lm -ldl
else else
ifeq ($(PLATFORM),cygwin) ifeq ($(PLATFORM),cygwin)
SO = .dll SO = .dll
@ -99,6 +120,7 @@ CLIBFLAGS =
CLINKFLAGS = -shared CLINKFLAGS = -shared
CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0 CPPFLAGS += -DSEXP_USE_STRING_STREAMS=0
LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a LIBCHIBI_FLAGS = -Wl,--out-implib,libchibi-scheme$(SO).a
STATIC_LDFLAGS = -lm -ldl
else else
SO = .so SO = .so
EXE = EXE =
@ -106,9 +128,6 @@ CLIBFLAGS = -fPIC
CLINKFLAGS = -shared CLINKFLAGS = -shared
STATICFLAGS = -static -DSEXP_USE_DL=0 STATICFLAGS = -static -DSEXP_USE_DL=0
LIBCHIBI_FLAGS = -Wl,-soname,libchibi-scheme$(SO).$(SOVERSION_MAJOR) LIBCHIBI_FLAGS = -Wl,-soname,libchibi-scheme$(SO).$(SOVERSION_MAJOR)
ifeq ($(PLATFORM),BSD)
LIBDL=
RLDFLAGS=-Wl,-R$(DESTDIR)$(LIBDIR)
endif endif
endif endif
endif endif
@ -116,26 +135,83 @@ endif
endif endif
endif endif
ifeq ($(PLATFORM),emscripten)
STATIC_LDFLAGS = -lm -ldl
endif
ifeq ($(PLATFORM),unix) ifeq ($(PLATFORM),unix)
#RLDFLAGS=-rpath $(LIBDIR) #RLDFLAGS=-rpath $(LIBDIR)
RLDFLAGS=-Wl,-R$(DESTDIR)$(LIBDIR) RLDFLAGS=-Wl,-R$(LIBDIR)
endif
########################################################################
# Library config.
#
# This is to allow "make SEXP_USE_BOEHM=1" and "make SEXP_USE_DL=0" to
# automatically include the necessary compiler and linker flags in
# addition to setting those features. If not using GNU make just
# comment out the ifs and use the else branches for the defaults.
ifeq ($(SEXP_USE_BOEHM),1)
GCLDFLAGS := -lgc
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%) -DSEXP_USE_BOEHM=1
else
GCLDFLAGS :=
XCPPFLAGS := $(CPPFLAGS) -Iinclude $(D:%=-DSEXP_USE_%)
endif
ifeq ($(SEXP_USE_DL),0)
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) -lm
XCFLAGS := -Wall -DSEXP_USE_DL=0 -g -g3 -O3 $(CFLAGS)
else
XLDFLAGS := $(LDFLAGS) $(RLDFLAGS) $(GCLDFLAGS) $(LIBDL) -lm
XCFLAGS := -Wall -g -g3 -O3 $(CFLAGS)
endif
ifeq ($(PLATFORM),solaris)
XLDFLAGS += -lsocket
XCPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS
endif
# Choose compiled library on MSYS
ifeq ($(OS), Windows_NT)
ifeq ($(PLATFORM),msys)
EXCLUDE_WIN32_LIBS=1
else
ifeq ($(shell uname -o),Cygwin)
EXCLUDE_WIN32_LIBS=1
else
EXCLUDE_POSIX_LIBS=1
endif
endif
endif
CHIBI_POSIX_COMPILED_LIBS = lib/chibi/process$(SO) lib/chibi/time$(SO) \
lib/chibi/system$(SO) lib/chibi/stty$(SO) lib/chibi/pty$(SO) \
lib/chibi/net$(SO) lib/srfi/18/threads$(SO)
CHIBI_WIN32_COMPILED_LIBS = lib/chibi/win32/process-win32$(SO)
ifndef EXCLUDE_POSIX_LIBS
CHIBI_COMPILED_LIBS += $(CHIBI_POSIX_COMPILED_LIBS)
else
CHIBI_COMPILED_LIBS += $(CHIBI_WIN32_COMPILED_LIBS)
endif endif
######################################################################## ########################################################################
# Check for headers (who needs autoconf?) # Check for headers (who needs autoconf?)
ifndef SEXP_USE_NTP_GETTIME ifndef SEXP_USE_NTP_GETTIME
SEXP_USE_NTP_GETTIME := $(shell echo "main(){struct ntptimeval n; ntp_gettime(&n);}" | gcc -fsyntax-only -include sys/timex.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0) SEXP_USE_NTP_GETTIME := $(shell echo "int main(){struct ntptimeval n; ntp_gettime(&n);}" | $(CC) -fsyntax-only -include sys/timex.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
endif endif
ifeq ($(SEXP_USE_NTP_GETTIME),1) ifeq ($(SEXP_USE_NTP_GETTIME),1)
CPPFLAGS += -DSEXP_USE_NTPGETTIME XCPPFLAGS += -DSEXP_USE_NTPGETTIME
endif endif
ifndef SEXP_USE_INTTYPES ifndef SEXP_USE_INTTYPES
SEXP_USE_INTTYPES := $(shell echo "main(){int_least8_t x;}" | gcc -fsyntax-only -include inttypes.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0) SEXP_USE_INTTYPES := $(shell echo "int main(){int_least8_t x;}" | $(CC) -fsyntax-only -include inttypes.h -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
endif endif
ifeq ($(SEXP_USE_INTTYPES),1) ifeq ($(SEXP_USE_INTTYPES),1)
CPPFLAGS += -DSEXP_USE_INTTYPES XCPPFLAGS += -DSEXP_USE_INTTYPES
endif endif

View file

@ -21,21 +21,42 @@ MKDIR ?= $(INSTALL) -d
RMDIR ?= rmdir RMDIR ?= rmdir
TAR ?= tar TAR ?= tar
DIFF ?= diff DIFF ?= diff
GIT ?= git
GREP ?= grep GREP ?= grep
FIND ?= find FIND ?= find
SYMLINK ?= ln -s SYMLINK ?= ln -s
LDCONFIG ?= ldconfig LDCONFIG ?= ldconfig
PREFIX ?= /usr/local # gnu coding standards
BINDIR ?= $(PREFIX)/bin prefix ?= /usr/local
LIBDIR ?= $(PREFIX)/lib PREFIX ?= $(prefix)
SOLIBDIR ?= $(PREFIX)/lib exec_prefix ?= $(PREFIX)
INCDIR ?= $(PREFIX)/include/chibi bindir ?= $(exec_prefix)/bin
MODDIR ?= $(PREFIX)/share/chibi libdir ?= $(exec_prefix)/lib
BINMODDIR ?= $(PREFIX)/lib/chibi includedir ?= $(PREFIX)/include
PKGCONFDIR ?= $(SOLIBDIR)/pkgconfig datarootdir ?= $(PREFIX)/share
MANDIR ?= $(PREFIX)/share/man/man1 datadir ?= $(datarootdir)
mandir ?= $(datarootdir)/man
man1dir ?= $(mandir)/man1
# hysterical raisins
BINDIR ?= $(bindir)
LIBDIR ?= $(libdir)
SOLIBDIR ?= $(libdir)
INCDIR ?= $(includedir)/chibi
MODDIR ?= $(datadir)/chibi
BINMODDIR ?= $(SOLIBDIR)/chibi
PKGCONFDIR ?= $(SOLIBDIR)/pkgconfig
MANDIR ?= $(man1dir)
# allow snow to be configured separately
SNOWPREFIX ?= /usr/local
SNOWLIBDIR ?= $(SNOWPREFIX)/lib
SNOWSOLIBDIR ?= $(SNOWLIBDIR)
SNOWMODDIR ?= $(SNOWPREFIX)/share/snow
SNOWBINMODDIR ?= $(SNOWSOLIBDIR)/snow
# for packaging tools
DESTDIR ?= DESTDIR ?=
######################################################################## ########################################################################
@ -46,13 +67,16 @@ include Makefile.detect
######################################################################## ########################################################################
all-libs: $(COMPILED_LIBS) all-libs: $(COMPILED_LIBS) lib/chibi/snow/install.sld
lib/%.c: lib/%.stub $(CHIBI_FFI_DEPENDENCIES) lib/%.c: lib/%.stub $(CHIBI_FFI_DEPENDENCIES)
$(CHIBI_FFI) $< $(CHIBI_FFI) $<
lib/chibi/pty$(SO): lib/chibi/pty.c $(INCLUDES) libchibi-scheme$(SO)
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) $(XLIBS) -lchibi-scheme -lutil
lib/%$(SO): lib/%.c $(INCLUDES) libchibi-scheme$(SO) lib/%$(SO): lib/%.c $(INCLUDES) libchibi-scheme$(SO)
$(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(XLIBS) -lchibi-scheme $(CC) $(CLIBFLAGS) $(CLINKFLAGS) $(XCPPFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ $< -L. $(RLDFLAGS) $(XLIBS) -lchibi-scheme
doc-libs: $(HTML_LIBS) doc-libs: $(HTML_LIBS)

View file

@ -12,7 +12,7 @@ Supported Environments
Chibi-scheme can be compiled with following platforms: Chibi-scheme can be compiled with following platforms:
* Microsoft Visual Studio 2017 (32bit only) * Microsoft Visual Studio 2017
* MinGW32 * MinGW32
* MinGW64 * MinGW64
* MSYS * MSYS
@ -74,8 +74,8 @@ it does not support UNIX/APPLE platforms either.
1. (Make sure CMake was selected with Visual Studio installer) 1. (Make sure CMake was selected with Visual Studio installer)
2. Open this directory with "Open with Visual Studio" 2. Open this directory with "Open with Visual Studio"
3. Choose "x86-Release" or "x86-Debug" configuration 3. Choose "x86-" or "x64-" configuration
4. "CMake" => "Build all" 4. "CMake" => "Build all"
5. "CMake" => "Run Tests" => "chibi-scheme" 5. "CMake" => "Tests" => "Run chibi-scheme Tests"

View file

@ -2,7 +2,7 @@
**Minimal Scheme Implementation for use as an Extension Language** **Minimal Scheme Implementation for use as an Extension Language**
http://synthcode.com/wiki/chibi-scheme https://github.com/ashinn/chibi-scheme
Chibi-Scheme is a very small library intended for use as an extension Chibi-Scheme is a very small library intended for use as an extension
and scripting language in C programs. In addition to support for and scripting language in C programs. In addition to support for
@ -12,22 +12,32 @@ allowing multiple VMs to run simultaneously in different OS threads.
There are no external dependencies so is relatively easy to drop into There are no external dependencies so is relatively easy to drop into
any project. any project.
The default repl language contains all bindings from Despite the small size, Chibi-Scheme attempts to do The Right Thing.
[R7RS small](http://trac.sacrideo.us/wg/wiki/R7RSHomePage), The default settings include:
available explicitly as the `(scheme small)` library. The
language is built in layers, however - see the manual for
instructions on compiling with fewer features or requesting
a smaller language on startup.
Chibi-Scheme is known to work on **32** and **64-bit** Linux, * a full numeric tower, with rational and complex numbers
FreeBSD and OS X, Plan 9, Windows (using Cygwin), iOS, Android, * full and seamless Unicode support
ARM and [Emscripten](https://kripken.github.io/emscripten-site). * low-level and high-level hygienic macros
Basic support for native Windows desktop also exists. See * an extensible module system
README-win32.md for details and build instructions.
To build on most platforms just run `make && make test`. This will Specifically, the default repl language contains all bindings from
provide a shared library *libchibi-scheme*, as well as a sample [R7RS small](https://small.r7rs.org/), available explicitly as the
*chibi-scheme* command-line repl. You can then run `(scheme small)` library. The language is built in layers, however -
see the manual for instructions on compiling with fewer features or
requesting a smaller language on startup.
Chibi-Scheme is known to work on **32** and **64-bit** Linux, FreeBSD,
NetBSD, OpenBSD, DragonFlyBSD, OS X, Plan 9, Windows, iOS, Android,
ARM and [Emscripten](https://kripken.github.io/emscripten-site). Basic
support for native Windows desktop also exists. See README-win32.md
for details and build instructions.
To build on most platforms just run `make && make test`. This has a
few conditionals assuming GNU make. If using another make, there are
a few parameters in Makefile.detect you need to set by hand.
This will provide a shared library *libchibi-scheme*, as well as a
sample *chibi-scheme* command-line repl. You can then run
sudo make install sudo make install
@ -40,7 +50,11 @@ to install the binaries and libraries. You can optionally specify a
By default files are installed in **/usr/local**. By default files are installed in **/usr/local**.
If you want to try out chibi-scheme without installing, be sure to set If you want to try out chibi-scheme without installing, be sure to set
`LD_LIBRARY_PATH` so it can find the shared libraries. `LD_LIBRARY_PATH` (`DYLD_LIBRARY_PATH` on macOS) so it can find the
shared libraries.
To make the emscripten build run `make js` (_not_ `emmake make js`).
For more detailed documentation, run `make doc` and see the generated For more detailed documentation, run `make doc` and see the generated
*doc/chibi.html*. *doc/chibi.html* or read the [manual](http://synthcode.com/scheme/chibi/)
online.

View file

@ -1 +1 @@
oxygen sodium

2
TODO
View file

@ -91,8 +91,6 @@
- State "DONE" from "TODO" [2010-07-11 Sun 15:31] - State "DONE" from "TODO" [2010-07-11 Sun 15:31]
VM now supports an optional hook for green threads, VM now supports an optional hook for green threads,
and a SRFI-18 interface is provided as a separate module. and a SRFI-18 interface is provided as a separate module.
I/O operations will currently block all threads though,
this needs to be addressed.
*** DONE thread-local parameters *** DONE thread-local parameters
CLOSED: [2010-12-06 Mon 21:52] CLOSED: [2010-12-06 Mon 21:52]
*** TODO efficient priority queues *** TODO efficient priority queues

View file

@ -1 +1 @@
0.8.0 0.11.0

View file

@ -20,11 +20,15 @@ environment:
- ARCH: x86 - ARCH: x86
TOOLCHAIN: MSVC TOOLCHAIN: MSVC
BUILDSYSTEM: CMAKE BUILDSYSTEM: CMAKE
- ARCH: x64
TOOLCHAIN: MSVC
BUILDSYSTEM: CMAKE
install: install:
- if %BUILDSYSTEM%.==CMAKE. cinst ninja - if %BUILDSYSTEM%.==CMAKE. cinst ninja
- if %BUILDSYSTEM%.==CMAKE. set PATH=c:/tools/ninja;%PATH% - if %BUILDSYSTEM%.==CMAKE. set PATH=c:/tools/ninja;%PATH%
- if %TOOLCHAIN%.==MSVC. call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" - if %TOOLCHAIN%%ARCH%.==MSVCx86. call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
- if %TOOLCHAIN%%ARCH%.==MSVCx64. call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
before_build: before_build:
- set BUILDTYPE= %ARCH%%TOOLCHAIN% - set BUILDTYPE= %ARCH%%TOOLCHAIN%

View file

@ -5,26 +5,42 @@
(quotient (+ (* 1000000 (timeval-seconds tv)) (timeval-microseconds tv)) (quotient (+ (* 1000000 (timeval-seconds tv)) (timeval-microseconds tv))
1000)) 1000))
(define (timeval-diff start end)
(- (timeval->milliseconds end)
(timeval->milliseconds start)))
(define (time* thunk) (define (time* thunk)
(call-with-output-string (call-with-output-string
(lambda (out) (lambda (out)
(gc)
(let* ((start (car (get-time-of-day))) (let* ((start (car (get-time-of-day)))
(start-rusage (get-resource-usage))
(gc-start (gc-usecs)) (gc-start (gc-usecs))
(gc-start-count (gc-count))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(result (parameterize ((current-output-port out)) (thunk))) (result (parameterize ((current-output-port out)) (thunk)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(end (car (get-time-of-day))) (end (car (get-time-of-day)))
(end-rusage (get-resource-usage))
(gc-end (gc-usecs)) (gc-end (gc-usecs))
(gc-msecs (quotient (- gc-end gc-start) 1000)) (gc-msecs (quotient (- gc-end gc-start) 1000))
(msecs (- (timeval->milliseconds end) (real-msecs (timeval-diff start end))
(timeval->milliseconds start)))) (user-msecs
(timeval-diff (resource-usage-time start-rusage)
(resource-usage-time end-rusage)))
(system-msecs
(timeval-diff (resource-usage-system-time start-rusage)
(resource-usage-system-time end-rusage))))
(display "user: ") (display "user: ")
(display msecs) (display user-msecs)
(display " system: 0") (display " system: ")
(display system-msecs)
(display " real: ") (display " real: ")
(display msecs) (display real-msecs)
(display " gc: ") (display " gc: ")
(display gc-msecs) (display gc-msecs)
(display " (") (display " (")
(display (gc-count)) (display (- (gc-count) gc-start-count))
(display " times)\n") (display " times)\n")
(display "result: ") (display "result: ")
(write result) (write result)

34
benchmarks/gabriel/difftimes.sh Executable file
View file

@ -0,0 +1,34 @@
#!/bin/bash
# set -ex
BENCHDIR=$(dirname $0)
if [ "${BENCHDIR%%/*}" = "." ]; then
BENCHDIR="$(pwd)${BENCHDIR#.}"
fi
TS1="${1:--2}"
TS2="${2:--1}"
DB="${3:-${BENCHDIR}/times.tsv}"
if [ "$TS1" -lt 1000000000 ]; then
SORT_OPTS='-nu'
if [ "$TS1" -lt 0 ]; then
SORT_OPTS='-nru'
TS1=$((0 - TS1))
fi
TS1=$(cut -f 7 "$DB" | sort "$SORT_OPTS" | tail -n +$TS1 | head -1)
fi
if [ "$TS2" -lt 1000000000 ]; then
SORT_OPTS='-nu'
if [ "$TS2" -lt 0 ]; then
SORT_OPTS='-nru'
TS2=$((0 - TS2))
fi
TS2=$(cut -f 7 "$DB" | sort "$SORT_OPTS" | tail -n +$TS2 | head -1)
fi
join -t $'\t' \
<(grep $'\t'"$TS1"$'\t' "$DB" | cut -f 1-2,5) \
<(grep $'\t'"$TS2"$'\t' "$DB" | cut -f 1-2,5) \
| perl -F'\t' -ane 'sub gain{($_[0]<=0)?0:100*($_[1]-$_[0])/$_[0]} $u=gain($F[1], $F[3]); $g=gain($F[2], $F[4]); printf STDOUT "%s\t%d\t%d\t%.2f%%\t%d\t%d\t%.2f%%\n", $F[0], $F[1], $F[3], $u, $F[2], $F[4], $g'

View file

@ -1,16 +1,32 @@
#!/bin/sh #!/bin/sh
BENCHDIR=$(dirname $0) # set -ex
if [ "${BENCHDIR%%/*}" == "." ]; then
BENCHDIR=$(pwd)${BENCHDIR#.}
fi
CHIBIHOME=${BENCHDIR%%/benchmarks/gabriel}
CHIBI="${CHIBI:-${CHIBIHOME}/chibi-scheme} -I$CHIBIHOME"
cd $BENCHDIR BENCHDIR=$(dirname $0)
if [ "${BENCHDIR%%/*}" = "." ]; then
BENCHDIR="$(pwd)${BENCHDIR#.}"
fi
OUTPUT="$BENCHDIR/out.txt"
DB="$BENCHDIR/times.tsv"
CHIBIHOME="${BENCHDIR%%/benchmarks/gabriel}"
CHIBI="${CHIBI:-${CHIBIHOME}/chibi-scheme} -I$CHIBIHOME"
HEAP="2M"
cd "$BENCHDIR"
for t in *.sch; do for t in *.sch; do
echo "${t%%.sch}" echo "program: ${t%%.sch}"
LD_LIBRARY_PATH="$CHIBIHOME" DYLD_LIBRARY_PATH="$CHIBIHOME" \ LD_LIBRARY_PATH="$CHIBIHOME" DYLD_LIBRARY_PATH="$CHIBIHOME" \
$CHIBI -I"$CHIBIHOME/lib" -q -lchibi-prelude.scm $t $CHIBI -I"$CHIBIHOME/lib" -h"$HEAP" -q -lchibi-prelude.scm "$t"
done done | tee "$OUTPUT"
cd - cd -
if [ ! -f "$DB" ]; then
echo $'program\tuser_ms\tsystem_ms\treal_ms\tgc_ms\tgc_count\ttimestamp\tcommit\tfeatures\tinit_heap\tcpu' > "$DB"
fi
#DATE=$(date -Iseconds)
DATE=$(date +%s)
COMMIT=$(git -C "$CHIBIHOME" rev-parse HEAD)
FEATURES=$(LD_LIBRARY_PATH="$CHIBIHOME" DYLD_LIBRARY_PATH="$CHIBIHOME" $CHIBI -q -p'(cddr *features*)' | tr ' ' , | tr -d '()')
CPU=$(lscpu | perl -ne 'if (s/^Model name:\s*//){s/\b(Intel|Core|Atom|AMD|CPU)(\s*\(\w+\))?\s*//gi;s/\s*@\s*[.\d]+[KMGT]Hz\b\s*//gi;print}')
perl -ane 'if (/^program:\s*(\w+)/) {$p=$1} elsif (/^user:\s*(\d+)\s*system:\s*(\d+)\s*real:\s*(\d+)(?:\s*gc:\s*(\d+)\s*(?:\((\d+)\s*times\))?)?/) {print"$p\t$1\t$2\t$3\t$4\t$5\t'"$DATE"'\t'"$COMMIT"'\t'"$FEATURES"'\t'"$HEAP"'\t'"$CPU"'\n"}' "$OUTPUT" >> "$DB"

404
bignum.c
View file

@ -35,38 +35,91 @@ sexp sexp_fixnum_to_bignum (sexp ctx, sexp a) {
return res; return res;
} }
sexp sexp_make_integer (sexp ctx, sexp_lsint_t x) { sexp sexp_make_integer_from_lsint (sexp ctx, sexp_lsint_t x) {
sexp res; sexp res;
if ((SEXP_MIN_FIXNUM <= x) && (x <= SEXP_MAX_FIXNUM)) { if (lsint_is_fixnum(x)) {
res = sexp_make_fixnum(x); res = sexp_make_fixnum(lsint_to_sint(x));
} else { } else if (sexp_lsint_fits_sint(x)) {
res = sexp_make_bignum(ctx, 1); res = sexp_make_bignum(ctx, 1);
if (x < 0) { if (lsint_lt_0(x)) {
sexp_bignum_sign(res) = -1; sexp_bignum_sign(res) = -1;
sexp_bignum_data(res)[0] = (sexp_uint_t)-x; sexp_bignum_data(res)[0] = (sexp_uint_t)-lsint_to_sint(x);
} else { } else {
sexp_bignum_sign(res) = 1; sexp_bignum_sign(res) = 1;
sexp_bignum_data(res)[0] = (sexp_uint_t)x; sexp_bignum_data(res)[0] = (sexp_uint_t)lsint_to_sint(x);
}
} else {
res = sexp_make_bignum(ctx, 2);
if (lsint_lt_0(x)) {
sexp_bignum_sign(res) = -1;
sexp_bignum_data(res)[0] = (sexp_uint_t)-lsint_to_sint(x);
sexp_bignum_data(res)[1] = (sexp_uint_t)~lsint_to_sint_hi(x);
} else {
sexp_bignum_sign(res) = 1;
sexp_bignum_data(res)[0] = (sexp_uint_t)lsint_to_sint(x);
sexp_bignum_data(res)[1] = (sexp_uint_t)lsint_to_sint_hi(x);
} }
} }
return res; return res;
} }
sexp sexp_make_unsigned_integer (sexp ctx, sexp_luint_t x) { sexp sexp_make_unsigned_integer_from_luint (sexp ctx, sexp_luint_t x) {
sexp res; sexp res;
if (x <= SEXP_MAX_FIXNUM) { if (luint_is_fixnum(x)) {
res = sexp_make_fixnum(x); res = sexp_make_fixnum(luint_to_uint(x));
} else { } else if (sexp_luint_fits_uint(x)) {
res = sexp_make_bignum(ctx, 1); res = sexp_make_bignum(ctx, 1);
sexp_bignum_sign(res) = 1; sexp_bignum_sign(res) = 1;
sexp_bignum_data(res)[0] = (sexp_uint_t)x; sexp_bignum_data(res)[0] = luint_to_uint(x);
} else {
res = sexp_make_bignum(ctx, 2);
sexp_bignum_sign(res) = 1;
sexp_bignum_data(res)[0] = luint_to_uint(x);
sexp_bignum_data(res)[1] = luint_to_uint_hi(x);
} }
return res; return res;
} }
#if SEXP_USE_CUSTOM_LONG_LONGS
sexp sexp_make_integer(sexp ctx, long long x) {
return sexp_make_integer_from_lsint(ctx, lsint_from_sint(x));
}
sexp sexp_make_unsigned_integer(sexp ctx, unsigned long long x) {
return sexp_make_unsigned_integer_from_luint(ctx, luint_from_uint(x));
}
#else
sexp sexp_make_integer (sexp ctx, sexp_lsint_t x) {
return sexp_make_integer_from_lsint(ctx, x);
}
sexp sexp_make_unsigned_integer (sexp ctx, sexp_luint_t x) {
return sexp_make_unsigned_integer_from_luint(ctx, x);
}
#endif
#if !SEXP_64_BIT
long long sexp_bignum_to_sint(sexp x) {
if (!sexp_bignump(x))
return 0;
if (sexp_bignum_length(x) > 1)
return sexp_bignum_sign(x) * (
(((long long)(sexp_bignum_data(x)[1]))<<(8*sizeof(sexp_bignum_data(x)[0]))) + sexp_bignum_data(x)[0]);
return sexp_bignum_sign(x) * sexp_bignum_data(x)[0];
}
unsigned long long sexp_bignum_to_uint(sexp x) {
if (!sexp_bignump(x))
return 0;
if (sexp_bignum_length(x) > 1)
return (((unsigned long long)(sexp_bignum_data(x)[1]))<<(8*sizeof(sexp_bignum_data(x)[0]))) + sexp_bignum_data(x)[0];
return sexp_bignum_data(x)[0];
}
#endif
#define double_trunc_10s_digit(f) (trunc((f)/10.0)*10.0) #define double_trunc_10s_digit(f) (trunc((f)/10.0)*10.0)
#define double_10s_digit(f) ((f)-double_trunc_10s_digit(f)) #define double_10s_digit(f) ((f)-double_trunc_10s_digit(f))
#define double_16s_digit(f) fmod(f,16.0)
sexp sexp_double_to_bignum (sexp ctx, double f) { sexp sexp_double_to_bignum (sexp ctx, double f) {
int sign; int sign;
sexp_gc_var3(res, scale, tmp); sexp_gc_var3(res, scale, tmp);
@ -74,10 +127,10 @@ sexp sexp_double_to_bignum (sexp ctx, double f) {
res = sexp_fixnum_to_bignum(ctx, SEXP_ZERO); res = sexp_fixnum_to_bignum(ctx, SEXP_ZERO);
scale = sexp_fixnum_to_bignum(ctx, SEXP_ONE); scale = sexp_fixnum_to_bignum(ctx, SEXP_ONE);
sign = (f < 0 ? -1 : 1); sign = (f < 0 ? -1 : 1);
for (f=fabs(f); f >= 1.0; f=trunc(f/10)) { for (f=fabs(f); f >= 1.0; f=trunc(f/16)) {
tmp = sexp_bignum_fxmul(ctx, NULL, scale, (sexp_uint_t)double_10s_digit(f), 0); tmp = sexp_bignum_fxmul(ctx, NULL, scale, (sexp_uint_t)double_16s_digit(f), 0);
res = sexp_bignum_add(ctx, res, res, tmp); res = sexp_bignum_add(ctx, res, res, tmp);
scale = sexp_bignum_fxmul(ctx, NULL, scale, 10, 0); scale = sexp_bignum_fxmul(ctx, NULL, scale, 16, 0);
} }
sexp_bignum_sign(res) = sign; sexp_bignum_sign(res) = sign;
sexp_gc_release3(ctx); sexp_gc_release3(ctx);
@ -135,7 +188,8 @@ sexp_sint_t sexp_bignum_compare_abs (sexp a, sexp b) {
sexp_sint_t sexp_bignum_compare (sexp a, sexp b) { sexp_sint_t sexp_bignum_compare (sexp a, sexp b) {
if (sexp_bignum_sign(a) != sexp_bignum_sign(b)) if (sexp_bignum_sign(a) != sexp_bignum_sign(b))
return sexp_bignum_sign(a); return sexp_bignum_sign(a);
return sexp_bignum_compare_abs(a, b); sexp_sint_t cmp = sexp_bignum_compare_abs(a, b);
return sexp_bignum_sign(a) < 0 ? -cmp : cmp;
} }
sexp sexp_bignum_normalize (sexp a) { sexp sexp_bignum_normalize (sexp a) {
@ -198,9 +252,9 @@ sexp sexp_bignum_fxmul (sexp ctx, sexp d, sexp a, sexp_uint_t b, int offset) {
tmp = d; tmp = d;
data = sexp_bignum_data(d); data = sexp_bignum_data(d);
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
n = (sexp_luint_t)adata[i]*b + carry; n = luint_add(luint_mul_uint(luint_from_uint(adata[i]), b), luint_from_uint(carry));
data[i+offset] = (sexp_uint_t)n; data[i+offset] = luint_to_uint(n);
carry = n >> (sizeof(sexp_uint_t)*8); carry = luint_to_uint(luint_shr(n, (sizeof(sexp_uint_t)*8)));
} }
if (carry) { if (carry) {
if (sexp_bignum_length(d) <= len+offset) if (sexp_bignum_length(d) <= len+offset)
@ -214,13 +268,13 @@ sexp sexp_bignum_fxmul (sexp ctx, sexp d, sexp a, sexp_uint_t b, int offset) {
sexp_uint_t sexp_bignum_fxdiv (sexp ctx, sexp a, sexp_uint_t b, int offset) { sexp_uint_t sexp_bignum_fxdiv (sexp ctx, sexp a, sexp_uint_t b, int offset) {
sexp_uint_t len=sexp_bignum_hi(a), *data=sexp_bignum_data(a), q, r=0; sexp_uint_t len=sexp_bignum_hi(a), *data=sexp_bignum_data(a), q, r=0;
int i; int i;
sexp_luint_t n = 0; sexp_luint_t n = luint_from_uint(0);
for (i=len-1; i>=offset; i--) { for (i=len-1; i>=offset; i--) {
n = (n << sizeof(sexp_uint_t)*8) + data[i]; n = luint_add(luint_shl(n, sizeof(sexp_uint_t)*8), luint_from_uint(data[i]));
q = (sexp_uint_t)(n / b); q = luint_to_uint(luint_div_uint(n, b));
r = (sexp_uint_t)(n - (sexp_luint_t)q * b); r = luint_to_uint(luint_sub(n, luint_mul_uint(luint_from_uint(q), b)));
data[i] = q; data[i] = q;
n = r; n = luint_from_uint(r);
} }
return r; return r;
} }
@ -228,7 +282,7 @@ sexp_uint_t sexp_bignum_fxdiv (sexp ctx, sexp a, sexp_uint_t b, int offset) {
sexp sexp_bignum_fxrem (sexp ctx, sexp a, sexp_sint_t b) { sexp sexp_bignum_fxrem (sexp ctx, sexp a, sexp_sint_t b) {
sexp_uint_t len=sexp_bignum_hi(a), *data=sexp_bignum_data(a), q, b0; sexp_uint_t len=sexp_bignum_hi(a), *data=sexp_bignum_data(a), q, b0;
int i; int i;
sexp_luint_t n = 0; sexp_luint_t n = luint_from_uint(0);
if (b > 0) { if (b > 0) {
q = b - 1; q = b - 1;
if ((b & q) == 0) if ((b & q) == 0)
@ -239,18 +293,18 @@ sexp sexp_bignum_fxrem (sexp ctx, sexp a, sexp_sint_t b) {
return sexp_xtype_exception(ctx, NULL, "divide by zero", a); return sexp_xtype_exception(ctx, NULL, "divide by zero", a);
} }
for (i=len-1; i>=0; i--) { for (i=len-1; i>=0; i--) {
n = (n << sizeof(sexp_uint_t)*8) + data[i]; n = luint_add(luint_shl(n, sizeof(sexp_uint_t)*8), luint_from_uint(data[i]));
q = (sexp_uint_t)(n / b0); q = luint_to_uint(luint_div_uint(n, b0));
n -= (sexp_luint_t)q * b0; n = luint_sub(n, luint_mul_uint(luint_from_uint(q), b0));
} }
return sexp_make_fixnum(sexp_bignum_sign(a) * (sexp_sint_t)n); return sexp_make_fixnum(sexp_bignum_sign(a) * (sexp_sint_t)luint_to_uint(n));
} }
sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init, sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init,
signed char sign, sexp_uint_t base) { signed char sign, sexp_uint_t base) {
int c, digit; int c, digit;
sexp_gc_var1(res); sexp_gc_var3(res, tmp, imag);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve3(ctx, res, tmp, imag);
res = sexp_make_bignum(ctx, SEXP_INIT_BIGNUM_SIZE); res = sexp_make_bignum(ctx, SEXP_INIT_BIGNUM_SIZE);
sexp_bignum_sign(res) = sign; sexp_bignum_sign(res) = sign;
sexp_bignum_data(res)[0] = init; sexp_bignum_data(res)[0] = init;
@ -264,9 +318,32 @@ sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init,
if (c=='.' || c=='e' || c=='E') { if (c=='.' || c=='e' || c=='E') {
if (base != 10) { if (base != 10) {
res = sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in); res = sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in);
} else { } else if (c=='.') {
if (c!='.') sexp_push_char(ctx, c, in); /* push the e back */
res = sexp_read_float_tail(ctx, in, sexp_bignum_to_double(res), (sign==-1)); res = sexp_read_float_tail(ctx, in, sexp_bignum_to_double(res), (sign==-1));
} else {
tmp = sexp_read_number(ctx, in, base, 0);
#if SEXP_USE_COMPLEX
if (sexp_complexp(tmp)) {
imag = sexp_complex_imag(tmp);
tmp = sexp_complex_real(tmp);
} else {
imag = SEXP_ZERO;
}
#endif
if (sexp_exceptionp(tmp)) {
res = tmp;
} else if (sexp_fixnump(tmp) && labs(sexp_unbox_fixnum(tmp)) < 100*1024*1024) {
tmp = sexp_expt(ctx, SEXP_TEN, tmp);
res = sexp_mul(ctx, res, tmp);
} else {
tmp = sexp_exact_to_inexact(ctx, NULL, 2, tmp);
tmp = sexp_expt(ctx, SEXP_TEN, tmp);
res = sexp_mul(ctx, res, tmp);
}
#if SEXP_USE_COMPLEX
if (imag != SEXP_ZERO && !sexp_exceptionp(res))
res = sexp_make_complex(ctx, res, imag);
#endif
} }
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
} else if (c=='/') { } else if (c=='/') {
@ -287,7 +364,7 @@ sexp sexp_read_bignum (sexp ctx, sexp in, sexp_uint_t init,
} else { } else {
sexp_push_char(ctx, c, in); sexp_push_char(ctx, c, in);
} }
sexp_gc_release1(ctx); sexp_gc_release3(ctx);
return sexp_bignum_normalize(res); return sexp_bignum_normalize(res);
} }
@ -524,38 +601,38 @@ sexp sexp_bignum_quot_rem (sexp ctx, sexp *rem, sexp a, sexp b) {
sexp_bignum_data(x)[off] = 0; sexp_bignum_data(x)[off] = 0;
if (off > 0) sexp_bignum_data(x)[off-1] = 0; if (off > 0) sexp_bignum_data(x)[off-1] = 0;
off = alen - blen + 1; off = alen - blen + 1;
dn = (((sexp_luint_t)sexp_bignum_data(a1)[alen-1] dn = luint_add_uint(luint_shl(luint_from_uint(sexp_bignum_data(a1)[alen-1])
<< (sizeof(sexp_uint_t)*8)) , (sizeof(sexp_uint_t)*8))
+ sexp_bignum_data(a1)[alen-2]); , sexp_bignum_data(a1)[alen-2]);
dd = (((sexp_luint_t)sexp_bignum_data(b1)[blen-1] dd = luint_add_uint(luint_shl(luint_from_uint(sexp_bignum_data(b1)[blen-1])
<< (sizeof(sexp_uint_t)*8)) , (sizeof(sexp_uint_t)*8))
+ sexp_bignum_data(b1)[blen-2]); , sexp_bignum_data(b1)[blen-2]);
if (alen > 2 && blen > 2 && if (alen > 2 && blen > 2 &&
sexp_bignum_data(a1)[alen-1] < ((sexp_luint_t)1<<(sizeof(sexp_uint_t)*4)) && luint_lt(luint_from_uint(sexp_bignum_data(a1)[alen-1]), luint_shl(luint_from_uint(1), (sizeof(sexp_uint_t)*4))) &&
sexp_bignum_data(b1)[blen-1] < ((sexp_luint_t)1<<(sizeof(sexp_uint_t)*4))) { luint_lt(luint_from_uint(sexp_bignum_data(b1)[blen-1]), luint_shl(luint_from_uint(1), (sizeof(sexp_uint_t)*4)))) {
dn = (dn << (sizeof(sexp_uint_t)*4)) dn = luint_add_uint(luint_shl(dn, (sizeof(sexp_uint_t)*4))
+ (sexp_bignum_data(a1)[alen-3] >> (sizeof(sexp_uint_t)*4)); , (sexp_bignum_data(a1)[alen-3] >> (sizeof(sexp_uint_t)*4)));
dd = (dd << (sizeof(sexp_uint_t)*4)) dd = luint_add_uint(luint_shl(dd, (sizeof(sexp_uint_t)*4))
+ (sexp_bignum_data(b1)[blen-3] >> (sizeof(sexp_uint_t)*4)); , (sexp_bignum_data(b1)[blen-3] >> (sizeof(sexp_uint_t)*4)));
} }
d = dn / dd; d = luint_div(dn, dd);
if (d == 0) { if (luint_eq(d, luint_from_uint(0))) {
dn = (((sexp_luint_t)sexp_bignum_data(a1)[alen-1] dn = luint_add_uint(luint_shl(luint_from_uint(sexp_bignum_data(a1)[alen-1])
<< (sizeof(sexp_uint_t)*8)) , (sizeof(sexp_uint_t)*8))
+ sexp_bignum_data(a1)[alen-2]); , sexp_bignum_data(a1)[alen-2]);
dd = sexp_bignum_data(b1)[blen-1]; dd = luint_from_uint(sexp_bignum_data(b1)[blen-1]);
if (sexp_bignum_data(a1)[alen-1] < ((sexp_luint_t)1<<(sizeof(sexp_uint_t)*4)) && if (luint_lt(luint_from_uint(sexp_bignum_data(a1)[alen-1]), (luint_shl(luint_from_uint(1), (sizeof(sexp_uint_t)*4)))) &&
sexp_bignum_data(b1)[blen-1] < ((sexp_luint_t)1<<(sizeof(sexp_uint_t)*4))) { luint_lt(luint_from_uint(sexp_bignum_data(b1)[blen-1]), (luint_shl(luint_from_uint(1), (sizeof(sexp_uint_t)*4))))) {
dn = (dn << (sizeof(sexp_uint_t)*4)) dn = luint_add_uint(luint_shl(dn, (sizeof(sexp_uint_t)*4))
+ (sexp_bignum_data(a1)[alen-3] >> (sizeof(sexp_uint_t)*4)); , (sexp_bignum_data(a1)[alen-3] >> (sizeof(sexp_uint_t)*4)));
dd = (dd << (sizeof(sexp_uint_t)*4)) dd = luint_add_uint(luint_shl(dd, (sizeof(sexp_uint_t)*4))
+ (sexp_bignum_data(b1)[blen-2] >> (sizeof(sexp_uint_t)*4)); , (sexp_bignum_data(b1)[blen-2] >> (sizeof(sexp_uint_t)*4)));
} }
d = dn / dd; d = luint_div(dn, dd);
off--; off--;
} }
dhi = d >> (sizeof(sexp_uint_t)*8); dhi = luint_to_uint(luint_shr(d, (sizeof(sexp_uint_t)*8)));
dlo = d & (((sexp_luint_t)1<<(sizeof(sexp_uint_t)*8))-1); dlo = luint_to_uint(luint_and(d, luint_sub(luint_shl(luint_from_uint(1), (sizeof(sexp_uint_t)*8)), luint_from_uint(1))));
sexp_bignum_data(x)[off] = dhi; sexp_bignum_data(x)[off] = dhi;
if (off > 0) sexp_bignum_data(x)[off-1] = dlo; if (off > 0) sexp_bignum_data(x)[off-1] = dlo;
/* update quotient q and remainder a1 estimates */ /* update quotient q and remainder a1 estimates */
@ -608,14 +685,21 @@ sexp sexp_bignum_remainder (sexp ctx, sexp a, sexp b) {
} }
sexp sexp_bignum_expt (sexp ctx, sexp a, sexp b) { sexp sexp_bignum_expt (sexp ctx, sexp a, sexp b) {
sexp_sint_t e = sexp_unbox_fx_abs(b); sexp_sint_t e = sexp_unbox_fixnum(b);
sexp_sint_t abs_e;
if (e < 0)
abs_e = -e;
else
abs_e = e;
sexp_gc_var2(res, acc); sexp_gc_var2(res, acc);
sexp_gc_preserve2(ctx, res, acc); sexp_gc_preserve2(ctx, res, acc);
res = sexp_fixnum_to_bignum(ctx, SEXP_ONE); res = sexp_fixnum_to_bignum(ctx, SEXP_ONE);
acc = sexp_copy_bignum(ctx, NULL, a, 0); acc = sexp_copy_bignum(ctx, NULL, a, 0);
for (; e; e>>=1, acc=sexp_bignum_mul(ctx, NULL, acc, acc)) for (; abs_e; abs_e>>=1, acc=sexp_bignum_mul(ctx, NULL, acc, acc))
if (e & 1) if (abs_e & 1)
res = sexp_bignum_mul(ctx, NULL, res, acc); res = sexp_bignum_mul(ctx, NULL, res, acc);
if (e < 0)
res = sexp_div(ctx, sexp_fixnum_to_bignum(ctx, SEXP_ONE), res);
sexp_gc_release2(ctx); sexp_gc_release2(ctx);
return sexp_bignum_normalize(res); return sexp_bignum_normalize(res);
} }
@ -695,12 +779,25 @@ sexp sexp_bignum_sqrt (sexp ctx, sexp a, sexp* rem_out) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
double sexp_ratio_to_double (sexp rat) { double sexp_ratio_to_double (sexp ctx, sexp rat) {
sexp_gc_var1(quot);
sexp num = sexp_ratio_numerator(rat), den = sexp_ratio_denominator(rat); sexp num = sexp_ratio_numerator(rat), den = sexp_ratio_denominator(rat);
return (sexp_bignump(num) ? sexp_bignum_to_double(num) double res = (sexp_bignump(num) ? sexp_bignum_to_double(num)
: sexp_fixnum_to_double(num)) : sexp_fixnum_to_double(num))
/ (sexp_bignump(den) ? sexp_bignum_to_double(den) / (sexp_bignump(den) ? sexp_bignum_to_double(den)
: sexp_fixnum_to_double(den)); : sexp_fixnum_to_double(den));
if (!isfinite(res)) {
sexp_gc_preserve1(ctx, quot);
if (sexp_unbox_fixnum(sexp_compare(ctx, sexp_ratio_numerator(rat), sexp_ratio_denominator(rat))) < 0) {
quot = sexp_quotient(ctx, sexp_ratio_denominator(rat), sexp_ratio_numerator(rat));
res = 1 / sexp_to_double(ctx, quot);
} else {
quot = sexp_quotient(ctx, sexp_ratio_numerator(rat), sexp_ratio_denominator(rat));
res = sexp_to_double(ctx, quot);
}
sexp_gc_release1(ctx);
}
return res;
} }
sexp sexp_double_to_ratio (sexp ctx, double f) { sexp sexp_double_to_ratio (sexp ctx, double f) {
@ -730,6 +827,41 @@ sexp sexp_double_to_ratio (sexp ctx, double f) {
return res; return res;
} }
/*
* For conversion that does not introduce round-off error,
* no matter what FLT_RADIX is.
*/
sexp sexp_double_to_ratio_2 (sexp ctx, double f) {
int sign,i;
sexp_gc_var3(res, whole, scale);
if (f == trunc(f))
return sexp_bignum_normalize(sexp_double_to_bignum(ctx, f));
sexp_gc_preserve3(ctx, res, whole, scale);
whole = sexp_double_to_bignum(ctx, trunc(f));
res = sexp_fixnum_to_bignum(ctx, SEXP_ZERO);
scale = SEXP_ONE;
sign = (f < 0 ? -1 : 1);
f = fabs(f-trunc(f));
while(f) {
res = sexp_bignum_fxmul(ctx, NULL, res, FLT_RADIX, 0);
scale = sexp_mul(ctx, scale, sexp_make_fixnum(FLT_RADIX));
f *= FLT_RADIX;
i = trunc(f);
if (i) {
f -= i;
res = sexp_bignum_fxadd(ctx, res, i);
}
}
sexp_bignum_sign(res) = sign;
res = sexp_bignum_normalize(res);
scale = sexp_bignum_normalize(scale);
res = sexp_make_ratio(ctx, res, scale);
res = sexp_ratio_normalize(ctx, res, SEXP_FALSE);
res = sexp_add(ctx, res, whole);
sexp_gc_release3(ctx);
return res;
}
sexp sexp_ratio_add (sexp ctx, sexp a, sexp b) { sexp sexp_ratio_add (sexp ctx, sexp a, sexp b) {
sexp_gc_var3(res, num, den); sexp_gc_var3(res, num, den);
sexp_gc_preserve3(ctx, res, num, den); sexp_gc_preserve3(ctx, res, num, den);
@ -786,7 +918,7 @@ sexp sexp_ratio_round (sexp ctx, sexp a) {
r = sexp_mul(ctx, r, SEXP_TWO); r = sexp_mul(ctx, r, SEXP_TWO);
if (sexp_exact_negativep(r)) {sexp_negate(r);} if (sexp_exact_negativep(r)) {sexp_negate(r);}
if (sexp_unbox_fixnum(sexp_compare(ctx, r, sexp_ratio_denominator(a))) > 0) if (sexp_unbox_fixnum(sexp_compare(ctx, r, sexp_ratio_denominator(a))) > 0)
q = sexp_add(ctx, q, (sexp_exact_positivep(q) ? SEXP_ONE : SEXP_NEG_ONE)); q = sexp_add(ctx, q, (sexp_exact_negativep(sexp_ratio_numerator(a)) ? SEXP_NEG_ONE : SEXP_ONE));
} }
sexp_gc_release2(ctx); sexp_gc_release2(ctx);
return q; return q;
@ -818,6 +950,21 @@ sexp sexp_ratio_ceiling (sexp ctx, sexp a) {
#endif #endif
double sexp_to_double (sexp ctx, sexp x) {
if (sexp_flonump(x))
return sexp_flonum_value(x);
else if (sexp_fixnump(x))
return sexp_fixnum_to_double(x);
else if (sexp_bignump(x))
return sexp_bignum_to_double(x);
#if SEXP_USE_RATIOS
else if (sexp_ratiop(x))
return sexp_ratio_to_double(ctx, x);
#endif
else
return 0.0;
}
/************************ complex numbers ****************************/ /************************ complex numbers ****************************/
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
@ -852,8 +999,8 @@ sexp sexp_complex_sub (sexp ctx, sexp a, sexp b) {
sexp_gc_var2(res, tmp); sexp_gc_var2(res, tmp);
sexp_gc_preserve2(ctx, res, tmp); sexp_gc_preserve2(ctx, res, tmp);
tmp = sexp_complex_copy(ctx, b); tmp = sexp_complex_copy(ctx, b);
sexp_negate(sexp_complex_real(tmp)); sexp_negate_maybe_ratio(sexp_complex_real(tmp));
sexp_negate(sexp_complex_imag(tmp)); sexp_negate_maybe_ratio(sexp_complex_imag(tmp));
res = sexp_complex_add(ctx, a, tmp); res = sexp_complex_add(ctx, a, tmp);
sexp_gc_release2(ctx); sexp_gc_release2(ctx);
return res; return res;
@ -899,21 +1046,6 @@ sexp sexp_complex_div (sexp ctx, sexp a, sexp b) {
return sexp_complex_normalize(res); return sexp_complex_normalize(res);
} }
static double sexp_to_double (sexp x) {
if (sexp_flonump(x))
return sexp_flonum_value(x);
else if (sexp_fixnump(x))
return sexp_fixnum_to_double(x);
else if (sexp_bignump(x))
return sexp_bignum_to_double(x);
#if SEXP_USE_RATIOS
else if (sexp_ratiop(x))
return sexp_ratio_to_double(x);
#endif
else
return 0.0;
}
static sexp sexp_to_complex (sexp ctx, sexp x) { static sexp sexp_to_complex (sexp ctx, sexp x) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
sexp_gc_var1(tmp); sexp_gc_var1(tmp);
@ -924,7 +1056,7 @@ static sexp sexp_to_complex (sexp ctx, sexp x) {
} else if (sexp_ratiop(x)) { } else if (sexp_ratiop(x)) {
sexp_gc_preserve1(ctx, tmp); sexp_gc_preserve1(ctx, tmp);
tmp = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); tmp = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
sexp_complex_real(tmp) = sexp_make_flonum(ctx, sexp_to_double(x)); sexp_complex_real(tmp) = sexp_make_flonum(ctx, sexp_to_double(ctx, x));
sexp_gc_release1(ctx); sexp_gc_release1(ctx);
return tmp; return tmp;
#endif #endif
@ -934,8 +1066,8 @@ static sexp sexp_to_complex (sexp ctx, sexp x) {
} }
sexp sexp_complex_exp (sexp ctx, sexp z) { sexp sexp_complex_exp (sexp ctx, sexp z) {
double e2x = exp(sexp_to_double(sexp_complex_real(z))), double e2x = exp(sexp_to_double(ctx, sexp_complex_real(z))),
y = sexp_to_double(sexp_complex_imag(z)); y = sexp_to_double(ctx, sexp_complex_imag(z));
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
@ -946,8 +1078,8 @@ sexp sexp_complex_exp (sexp ctx, sexp z) {
} }
sexp sexp_complex_log (sexp ctx, sexp z) { sexp sexp_complex_log (sexp ctx, sexp z) {
double x = sexp_to_double(sexp_complex_real(z)), double x = sexp_to_double(ctx, sexp_complex_real(z)),
y = sexp_to_double(sexp_complex_imag(z)); y = sexp_to_double(ctx, sexp_complex_imag(z));
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
@ -971,21 +1103,21 @@ sexp sexp_complex_expt (sexp ctx, sexp a, sexp b) {
#if SEXP_USE_MATH #if SEXP_USE_MATH
sexp sexp_complex_sqrt (sexp ctx, sexp z) { sexp sexp_complex_sqrt (sexp ctx, sexp z) {
double x = sexp_to_double(sexp_complex_real(z)), double x = sexp_to_double(ctx, sexp_complex_real(z)),
y = sexp_to_double(sexp_complex_imag(z)), r; y = sexp_to_double(ctx, sexp_complex_imag(z)), r;
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
r = sqrt(x*x + y*y); r = sqrt(x*x + y*y);
res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
sexp_complex_real(res) = sexp_make_flonum(ctx, sqrt((x+r)/2)); sexp_complex_real(res) = sexp_make_flonum(ctx, sqrt((x+r)/2));
sexp_complex_imag(res) = sexp_make_flonum(ctx, ((y<0||(y==0&&1/y<0))?-1:1)*sqrt((-x+r)/2)); sexp_complex_imag(res) = sexp_make_flonum(ctx, ((y<-0.0)?-1:1)*sqrt((-x+r)/2));
sexp_gc_release1(ctx); sexp_gc_release1(ctx);
return res; return res;
} }
sexp sexp_complex_sin (sexp ctx, sexp z) { sexp sexp_complex_sin (sexp ctx, sexp z) {
double x = sexp_to_double(sexp_complex_real(z)), double x = sexp_to_double(ctx, sexp_complex_real(z)),
y = sexp_to_double(sexp_complex_imag(z)); y = sexp_to_double(ctx, sexp_complex_imag(z));
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
@ -996,8 +1128,8 @@ sexp sexp_complex_sin (sexp ctx, sexp z) {
} }
sexp sexp_complex_cos (sexp ctx, sexp z) { sexp sexp_complex_cos (sexp ctx, sexp z) {
double x = sexp_to_double(sexp_complex_real(z)), double x = sexp_to_double(ctx, sexp_complex_real(z)),
y = sexp_to_double(sexp_complex_imag(z)); y = sexp_to_double(ctx, sexp_complex_imag(z));
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO); res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
@ -1211,7 +1343,7 @@ sexp sexp_add (sexp ctx, sexp a, sexp b) {
break; break;
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_FLO_RAT: case SEXP_NUM_FLO_RAT:
r = sexp_make_flonum(ctx, sexp_flonum_value(a) + sexp_ratio_to_double(b)); r = sexp_make_flonum(ctx, sexp_flonum_value(a) + sexp_ratio_to_double(ctx, b));
break; break;
case SEXP_NUM_FIX_RAT: case SEXP_NUM_FIX_RAT:
case SEXP_NUM_BIG_RAT: case SEXP_NUM_BIG_RAT:
@ -1271,7 +1403,7 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) {
r = sexp_fx_sub(a, b); /* VM catches this case */ r = sexp_fx_sub(a, b); /* VM catches this case */
break; break;
case SEXP_NUM_FIX_FLO: case SEXP_NUM_FIX_FLO:
r = sexp_make_flonum(ctx, sexp_fixnum_to_double(a)-sexp_flonum_value(b)); r = sexp_make_flonum(ctx, a==SEXP_ZERO ? -sexp_flonum_value(b) : sexp_fixnum_to_double(a)-sexp_flonum_value(b));
break; break;
case SEXP_NUM_FIX_BIG: case SEXP_NUM_FIX_BIG:
tmp1 = sexp_fixnum_to_bignum(ctx, a); tmp1 = sexp_fixnum_to_bignum(ctx, a);
@ -1300,10 +1432,10 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) {
break; break;
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_FLO_RAT: case SEXP_NUM_FLO_RAT:
r = sexp_make_flonum(ctx, sexp_flonum_value(a) - sexp_ratio_to_double(b)); r = sexp_make_flonum(ctx, sexp_flonum_value(a) - sexp_ratio_to_double(ctx, b));
break; break;
case SEXP_NUM_RAT_FLO: case SEXP_NUM_RAT_FLO:
r = sexp_make_flonum(ctx, sexp_ratio_to_double(a) - sexp_flonum_value(b)); r = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, a) - sexp_flonum_value(b));
break; break;
case SEXP_NUM_RAT_FIX: case SEXP_NUM_RAT_FIX:
case SEXP_NUM_RAT_BIG: case SEXP_NUM_RAT_BIG:
@ -1321,21 +1453,17 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) {
sexp_negate_exact(sexp_ratio_numerator(tmp2)); sexp_negate_exact(sexp_ratio_numerator(tmp2));
r = sexp_ratio_add(ctx, a, tmp2); r = sexp_ratio_add(ctx, a, tmp2);
if (negatep) { if (negatep) {
if (sexp_ratiop(r)) { sexp_negate_maybe_ratio(r);
sexp_negate_exact(sexp_ratio_numerator(r));
} else {
sexp_negate_exact(r);
}
} }
break; break;
#endif #endif
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_RAT_CPX: case SEXP_NUM_RAT_CPX:
a = tmp1 = sexp_make_flonum(ctx, sexp_ratio_to_double(a)); a = tmp1 = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, a));
goto complex_sub; goto complex_sub;
case SEXP_NUM_CPX_RAT: case SEXP_NUM_CPX_RAT:
b = tmp1 = sexp_make_flonum(ctx, sexp_ratio_to_double(b)); b = tmp1 = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, b));
/* ... FALLTHROUGH ... */ /* ... FALLTHROUGH ... */
#endif #endif
case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_FLO:
@ -1357,10 +1485,10 @@ sexp sexp_sub (sexp ctx, sexp a, sexp b) {
if (negatep) { if (negatep) {
if (sexp_complexp(r)) { if (sexp_complexp(r)) {
r = sexp_complex_copy(ctx, r); r = sexp_complex_copy(ctx, r);
sexp_negate(sexp_complex_real(r)); sexp_negate_maybe_ratio(sexp_complex_real(r));
sexp_negate(sexp_complex_imag(r)); sexp_negate_maybe_ratio(sexp_complex_imag(r));
} else { } else {
sexp_negate(r); sexp_negate_maybe_ratio(r);
} }
} }
break; break;
@ -1386,11 +1514,11 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) {
r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a);
break; break;
case SEXP_NUM_FIX_FIX: case SEXP_NUM_FIX_FIX:
prod = (sexp_lsint_t)sexp_unbox_fixnum(a) * sexp_unbox_fixnum(b); prod = lsint_mul_sint(lsint_from_sint(sexp_unbox_fixnum(a)), sexp_unbox_fixnum(b));
if ((prod < SEXP_MIN_FIXNUM) || (prod > SEXP_MAX_FIXNUM)) if (!lsint_is_fixnum(prod))
r = sexp_mul(ctx, tmp=sexp_fixnum_to_bignum(ctx, a), b); r = sexp_mul(ctx, tmp=sexp_fixnum_to_bignum(ctx, a), b);
else else
r = sexp_make_fixnum(prod); r = sexp_make_fixnum(lsint_to_sint(prod));
break; break;
case SEXP_NUM_FIX_FLO: case SEXP_NUM_FIX_FLO:
r = (a==SEXP_ZERO ? a : sexp_make_flonum(ctx, sexp_fixnum_to_double(a)*sexp_flonum_value(b))); r = (a==SEXP_ZERO ? a : sexp_make_flonum(ctx, sexp_fixnum_to_double(a)*sexp_flonum_value(b)));
@ -1411,7 +1539,7 @@ sexp sexp_mul (sexp ctx, sexp a, sexp b) {
break; break;
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_FLO_RAT: case SEXP_NUM_FLO_RAT:
r = sexp_make_flonum(ctx, sexp_flonum_value(a) * sexp_ratio_to_double(b)); r = sexp_make_flonum(ctx, sexp_flonum_value(a) * sexp_ratio_to_double(ctx, b));
break; break;
case SEXP_NUM_FIX_RAT: case SEXP_NUM_FIX_RAT:
case SEXP_NUM_BIG_RAT: case SEXP_NUM_BIG_RAT:
@ -1518,10 +1646,10 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) {
break; break;
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_FLO_RAT: case SEXP_NUM_FLO_RAT:
r = sexp_make_flonum(ctx, sexp_flonum_value(a) / sexp_ratio_to_double(b)); r = sexp_make_flonum(ctx, sexp_flonum_value(a) / sexp_ratio_to_double(ctx, b));
break; break;
case SEXP_NUM_RAT_FLO: case SEXP_NUM_RAT_FLO:
r = sexp_make_flonum(ctx, sexp_ratio_to_double(a) / sexp_flonum_value(b)); r = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, a) / sexp_flonum_value(b));
break; break;
case SEXP_NUM_RAT_FIX: case SEXP_NUM_RAT_FIX:
case SEXP_NUM_RAT_BIG: case SEXP_NUM_RAT_BIG:
@ -1539,7 +1667,7 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) {
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_CPX_RAT: case SEXP_NUM_CPX_RAT:
b = tmp = sexp_make_flonum(ctx, sexp_ratio_to_double(b)); b = tmp = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, b));
/* ... FALLTHROUGH ... */ /* ... FALLTHROUGH ... */
#endif #endif
case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_FLO:
@ -1550,7 +1678,7 @@ sexp sexp_div (sexp ctx, sexp a, sexp b) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_RAT_CPX: case SEXP_NUM_RAT_CPX:
if (sexp_ratiop(a)) if (sexp_ratiop(a))
a = tmp = sexp_make_flonum(ctx, sexp_ratio_to_double(a)); a = tmp = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, a));
/* ... FALLTHROUGH ... */ /* ... FALLTHROUGH ... */
#endif #endif
case SEXP_NUM_FLO_CPX: case SEXP_NUM_FLO_CPX:
@ -1634,6 +1762,9 @@ sexp sexp_quotient (sexp ctx, sexp a, sexp b) {
break; break;
case SEXP_NUM_FIX_FIX: case SEXP_NUM_FIX_FIX:
r = sexp_fx_div(a, b); r = sexp_fx_div(a, b);
if ((sexp_sint_t)a < 0 && (sexp_sint_t)b < 0 && (sexp_sint_t)r < 0) {
r = sexp_quotient(ctx, tmp=sexp_fixnum_to_bignum(ctx, a), b);
}
break; break;
case SEXP_NUM_FIX_BIG: case SEXP_NUM_FIX_BIG:
r = SEXP_ZERO; r = SEXP_ZERO;
@ -1667,8 +1798,11 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_FLO_RAT: case SEXP_NUM_FLO_RAT:
#endif #endif
if (sexp_flonum_value(a) != trunc(sexp_flonum_value(a))) { if (isinf(sexp_flonum_value(a)) ||
sexp_flonum_value(a) != trunc(sexp_flonum_value(a))) {
r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a); r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, a);
} else if (bt == SEXP_NUM_FLO && isinf(sexp_flonum_value(b))) {
r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b);
} else { } else {
tmp = sexp_bignum_normalize(sexp_double_to_bignum(ctx, sexp_flonum_value(a))); tmp = sexp_bignum_normalize(sexp_double_to_bignum(ctx, sexp_flonum_value(a)));
tmp = sexp_remainder(ctx, tmp, b); tmp = sexp_remainder(ctx, tmp, b);
@ -1691,7 +1825,8 @@ sexp sexp_remainder (sexp ctx, sexp a, sexp b) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_RAT_FLO: case SEXP_NUM_RAT_FLO:
#endif #endif
if (sexp_flonum_value(b) != trunc(sexp_flonum_value(b))) { if (isinf(sexp_flonum_value(b)) ||
sexp_flonum_value(b) != trunc(sexp_flonum_value(b))) {
r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b); r = sexp_type_exception(ctx, NULL, SEXP_FIXNUM, b);
} else { } else {
tmp = sexp_bignum_normalize(sexp_double_to_bignum(ctx, sexp_flonum_value(b))); tmp = sexp_bignum_normalize(sexp_double_to_bignum(ctx, sexp_flonum_value(b)));
@ -1732,16 +1867,16 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) {
sexp_gc_preserve1(ctx, tmp); sexp_gc_preserve1(ctx, tmp);
if (at > bt) { if (at > bt) {
r = sexp_compare(ctx, b, a); r = sexp_compare(ctx, b, a);
sexp_negate(r); if (!sexp_exceptionp(r)) { sexp_negate(r); }
} else { } else {
switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) { switch ((at * SEXP_NUM_NUMBER_TYPES) + bt) {
case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX: case SEXP_NUM_NOT_NOT: case SEXP_NUM_NOT_FIX:
case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG: case SEXP_NUM_NOT_FLO: case SEXP_NUM_NOT_BIG:
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
case SEXP_NUM_CPX_CPX: case SEXP_NUM_CPX_FIX: case SEXP_NUM_CPX_CPX: case SEXP_NUM_FIX_CPX:
case SEXP_NUM_CPX_FLO: case SEXP_NUM_CPX_BIG: case SEXP_NUM_FLO_CPX: case SEXP_NUM_BIG_CPX:
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
case SEXP_NUM_CPX_RAT: case SEXP_NUM_RAT_CPX:
#endif #endif
#endif #endif
r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a); r = sexp_type_exception(ctx, NULL, SEXP_NUMBER, a);
@ -1750,9 +1885,13 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) {
r = sexp_make_fixnum(sexp_unbox_fixnum(a) - sexp_unbox_fixnum(b)); r = sexp_make_fixnum(sexp_unbox_fixnum(a) - sexp_unbox_fixnum(b));
break; break;
case SEXP_NUM_FIX_FLO: case SEXP_NUM_FIX_FLO:
f = sexp_fixnum_to_double(a); if (isinf(sexp_flonum_value(b))) {
g = sexp_flonum_value(b); r = sexp_flonum_value(b) > 0 ? SEXP_NEG_ONE : SEXP_ONE;
r = sexp_make_fixnum(f < g ? -1 : f == g ? 0 : 1); } else if (isnan(sexp_flonum_value(b))) {
r = sexp_xtype_exception(ctx, NULL, "can't compare NaN", b);
} else {
r = sexp_compare(ctx, a, tmp=sexp_inexact_to_exact(ctx, NULL, 1, b));
}
break; break;
case SEXP_NUM_FIX_BIG: case SEXP_NUM_FIX_BIG:
if ((sexp_bignum_hi(b) > 1) || if ((sexp_bignum_hi(b) > 1) ||
@ -1764,6 +1903,11 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) {
case SEXP_NUM_FLO_FLO: case SEXP_NUM_FLO_FLO:
f = sexp_flonum_value(a); f = sexp_flonum_value(a);
g = sexp_flonum_value(b); g = sexp_flonum_value(b);
if (isnan(f))
r = sexp_xtype_exception(ctx, NULL, "can't compare NaN", a);
else if (isnan(g))
r = sexp_xtype_exception(ctx, NULL, "can't compare NaN", b);
else
r = sexp_make_fixnum(f < g ? -1 : f == g ? 0 : 1); r = sexp_make_fixnum(f < g ? -1 : f == g ? 0 : 1);
break; break;
case SEXP_NUM_FLO_BIG: case SEXP_NUM_FLO_BIG:
@ -1789,8 +1933,7 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) {
} else if (isnan(f)) { } else if (isnan(f)) {
r = sexp_xtype_exception(ctx, NULL, "can't compare NaN", a); r = sexp_xtype_exception(ctx, NULL, "can't compare NaN", a);
} else { } else {
g = sexp_ratio_to_double(b); r = sexp_compare(ctx, tmp=sexp_inexact_to_exact(ctx, NULL, 1, a), b);
r = sexp_make_fixnum(f < g ? -1 : f == g ? 0 : 1);
} }
break; break;
case SEXP_NUM_FIX_RAT: case SEXP_NUM_FIX_RAT:
@ -1801,6 +1944,9 @@ sexp sexp_compare (sexp ctx, sexp a, sexp b) {
r = sexp_ratio_compare(ctx, a, b); r = sexp_ratio_compare(ctx, a, b);
break; break;
#endif #endif
default:
r = sexp_xtype_exception(ctx, NULL, "unknown comparison", a);
break;
} }
} }
sexp_gc_release1(ctx); sexp_gc_release1(ctx);

View file

@ -0,0 +1,12 @@
;; Don't import this - it's temporarily used to compute optimized
;; char-set representations.
(define-library (chibi char-set width)
(import (chibi) (chibi iset) (chibi char-set))
(include "width.scm")
(export
char-set:zero-width
char-set:full-width
char-set:ambiguous-width
))

View file

@ -1 +0,0 @@
LD_LIBRARY_PATH=.: DYLD_LIBRARY_PATH=.: CHIBI_MODULE_PATH=lib ./chibi-scheme "$@"

View file

@ -0,0 +1,10 @@
execute_process(
COMMAND find ${LIBDIR} -name "*.sld"
COMMAND ${EXEC} ${GENMETA} ${VERSION}
OUTPUT_FILE ${OUT}
RESULT_VARIABLE error)
if(error)
message(FATAL_ERROR "${error}")
endif()

View file

@ -0,0 +1,2 @@
include(${CMAKE_CURRENT_LIST_DIR}/chibi-scheme-targets.cmake)

View file

@ -0,0 +1,14 @@
# pkg-config
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_FULL_BINDIR@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
version=@CMAKE_PROJECT_VERSION@
Name: chibi-scheme
URL: http://synthcode.com/scheme/chibi/
Description: Minimal Scheme Implementation for use as an Extension Language
Version: ${version}
Libs: -L${libdir} -lchibi-scheme
Libs.private: -dl -lm
Cflags: -I${includedir}

View file

@ -52,4 +52,4 @@ Alex Shinn (alexshinn @ gmail . com)
.PP .PP
The chibi-scheme home-page: The chibi-scheme home-page:
.BR .BR
http://code.google.com/p/chibi-scheme/ https://github.com/ashinn/chibi-scheme/

View file

@ -42,4 +42,4 @@ Alex Shinn (alexshinn @ gmail . com)
.PP .PP
The chibi-scheme home-page: The chibi-scheme home-page:
.BR .BR
http://code.google.com/p/chibi-scheme/ https://github.com/ashinn/chibi-scheme/

View file

@ -139,7 +139,7 @@ need not be exported) with a single argument of the list of command-line
arguments as in SRFI-22. The name "main" can be overridden with the -r arguments as in SRFI-22. The name "main" can be overridden with the -r
option. option.
.I [module] .I [module]
may be omitted, in which case it default to chibi.repl. Thus may be omitted, in which case it defaults to chibi.repl. Thus
.I chibi-scheme -R .I chibi-scheme -R
is the recommended means to obtain the advanced REPL. is the recommended means to obtain the advanced REPL.
.TP .TP
@ -225,13 +225,17 @@ Loads the Scheme heap from
.I image-file .I image-file
instead of compiling the init file on the fly. instead of compiling the init file on the fly.
This feature is still experimental. This feature is still experimental.
.TP
.BI -b
Makes stdio nonblocking (blocking by default). Only available when
lightweight threads are enabled.
.SH ENVIRONMENT .SH ENVIRONMENT
.TP .TP
.B CHIBI_MODULE_PATH .B CHIBI_MODULE_PATH
A colon separated list of directories to search for module A colon separated list of directories to search for module
files, inserted before the system default load paths. chibi-scheme files, inserted before the system default load paths. chibi-scheme
searchs for modules in directories in the following order: searches for modules in directories in the following order:
.TP .TP
directories included with the -I path option directories included with the -I path option
@ -242,8 +246,14 @@ searchs for modules in directories in the following order:
.TP .TP
directories included with -A path option directories included with -A path option
If CHIBI_MODULE_PATH is unset, the directoriese "./lib", and "." are If CHIBI_MODULE_PATH is unset, the directories "./lib", and "." are
search in order. searched in order. Set to empty to only consider -I, system
directories and -A.
.TP
.B CHIBI_IGNORE_SYSTEM_PATH
If set to anything but "0", system directories (as listed above) are
not included in the search paths.
.SH AUTHORS .SH AUTHORS
.PP .PP

View file

@ -4,7 +4,7 @@
\author{Alex Shinn} \author{Alex Shinn}
\centered{\smaller{Minimal Scheme Implementation for use as an Extension Language}} \centered{\smaller{Minimal Scheme Implementation for use as an Extension Language}}
\centered{\url{http://synthcode.com/wiki/chibi-scheme}} \centered{\url{https://github.com/ashinn/chibi-scheme}}
\section{Introduction} \section{Introduction}
@ -28,8 +28,8 @@ standard modules. You can choose whichever layer suits your needs
best and customize the rest. Adding your own primitives or wrappers best and customize the rest. Adding your own primitives or wrappers
around existing C libraries is easy with the C FFI. around existing C libraries is easy with the C FFI.
Chibi is known to build and run on 32 and 64-bit Linux, FreeBSD, Chibi is known to build and run on 32 and 64-bit Linux, OpenBSD, FreeBSD,
DragonFly, OS X, iOS, Windows (under Cygwin) and Plan9. DragonFlyBSD, OS X, iOS, Windows (under Cygwin) and Plan9.
\section{Installation} \section{Installation}
@ -69,6 +69,13 @@ To compile a static executable, use
\command{make chibi-scheme-static SEXP_USE_DL=0} \command{make chibi-scheme-static SEXP_USE_DL=0}
Note this static executable has none of the external binary libraries
included, which means among other things you can't load the
\scheme{(scheme base)} default language. You need to specify the
\scheme{(chibi)} or other Scheme-only language to run:
\command{./chibi-scheme-static -q}
To compile a static executable with all C libraries statically To compile a static executable with all C libraries statically
included, first you need to create a clibs.c file, which can be done included, first you need to create a clibs.c file, which can be done
with: with:
@ -79,7 +86,8 @@ or edited manually. Be sure to run this with a non-static
chibi-scheme. Then you can make the static executable with: chibi-scheme. Then you can make the static executable with:
\command{ \command{
make -B chibi-scheme-static SEXP_USE_DL=0 CPPFLAGS=-DSEXP_USE_STATIC_LIBS make -B chibi-scheme-static SEXP_USE_DL=0 \
CPPFLAGS="-DSEXP_USE_STATIC_LIBS -DSEXP_USE_STATIC_LIBS_NO_INCLUDE=0"
} }
By default files are installed in /usr/local. You can optionally By default files are installed in /usr/local. You can optionally
@ -112,6 +120,7 @@ are listed below.
\item{\ccode{SEXP_USE_RATIOS} - use exact ratios (enabled by default)} \item{\ccode{SEXP_USE_RATIOS} - use exact ratios (enabled by default)}
\item{\ccode{SEXP_USE_COMPLEX} - use complex numbers (enabled by default)} \item{\ccode{SEXP_USE_COMPLEX} - use complex numbers (enabled by default)}
\item{\ccode{SEXP_USE_UTF8_STRINGS} - Unicode support (enabled by default)} \item{\ccode{SEXP_USE_UTF8_STRINGS} - Unicode support (enabled by default)}
\item{\ccode{SEXP_USE_STRING_INDEX_TABLE} - precompute offsets for O(1) \scheme{string-ref}}
\item{\ccode{SEXP_USE_NO_FEATURES} - disable almost all features} \item{\ccode{SEXP_USE_NO_FEATURES} - disable almost all features}
] ]
@ -127,6 +136,8 @@ documentation system described in
build this manual. \ccode{chibi-ffi} is a tool to build wrappers for build this manual. \ccode{chibi-ffi} is a tool to build wrappers for
C libraries, described in the FFI section below. C libraries, described in the FFI section below.
See the examples directory for some sample programs.
\section{Default Language} \section{Default Language}
\subsection{Scheme Standard} \subsection{Scheme Standard}
@ -137,9 +148,10 @@ superset of
\hyperlink["http://www.schemers.org/Documents/Standards/R5RS/HTML/"]{R5RS}. \hyperlink["http://www.schemers.org/Documents/Standards/R5RS/HTML/"]{R5RS}.
The reader defaults to case-sensitive, like R6RS and R7RS but unlike The reader defaults to case-sensitive, like R6RS and R7RS but unlike
R5RS. The default configuration includes the full numeric tower: R5RS. You can specify the -f option on the command-line to enable
fixnums, flonums, bignums, exact rationals and complex numbers, though case-folding. The default configuration includes the full numeric
this can be customized at compile time. tower: fixnums, flonums, bignums, exact rationals and complex numbers,
though this can be customized at compile time.
Full continuations are supported, but currently continuations don't Full continuations are supported, but currently continuations don't
take C code into account. This means that you can call from Scheme to take C code into account. This means that you can call from Scheme to
@ -153,13 +165,14 @@ currently unspecified.
In R7RS (and R6RS) semantics it is impossible to use two macros from In R7RS (and R6RS) semantics it is impossible to use two macros from
different modules which both use the same auxiliary keywords (like different modules which both use the same auxiliary keywords (like
\scheme{else} in \scheme{cond} forms) without renaming one of the \scheme{else} in \scheme{cond} forms) without renaming one of the
keywords. By default Chibi considers all top-level bindings keywords. To minimize conflicts Chibi offers a special module named
effectively unbound when matching auxiliary keywords, so this case \scheme{(auto)} which can export any identifier requested with
will "just work". This decision was made because the chance of \scheme{only}, e.g. \scheme{(import (only (auto) foo))} will import
different modules using the same keywords seems more likely than user an auxiliary syntax \scheme{foo} binding. Separate modules can use
code unintentionally matching a top-level keyword with a different this to get the same binding without needing to know about each other
binding, however if you want to use R7RS semantics you can compile in advance. This is a Chibi-specific extension so is non-portable, but
with \ccode{SEXP_USE_STRICT_TOPLEVEL_BINDINGS=1}. you can always define a static \scheme{(auto)} module exporting a list
of all known bindings for other implementations.
\scheme{load} is extended to accept an optional environment argument, like \scheme{load} is extended to accept an optional environment argument, like
\scheme{eval}. You can also \scheme{load} shared libraries in addition to \scheme{eval}. You can also \scheme{load} shared libraries in addition to
@ -179,11 +192,12 @@ other languages.
\subsection{Module System} \subsection{Module System}
Chibi uses the R7RS module system natively, which is a simple static Chibi supports the R7RS module system natively, which is a simple
module system in the style of the static module system. The Chibi implementation is actually a
\hyperlink["http://s48.org/"]{Scheme48} module system. As with most hierarchy of languages in the style of the
features this is optional, and can be ignored or completely disabled \hyperlink["http://s48.org/"]{Scheme48} module system, allowing easy
at compile time. extension of the module system itself. As with most features this is
optional, and can be ignored or completely disabled at compile time.
Modules names are hierarchical lists of symbols or numbers. A module Modules names are hierarchical lists of symbols or numbers. A module
definition uses the following form: definition uses the following form:
@ -201,7 +215,8 @@ where \var{<library-declarations>} can be any of
(begin <expr> ...) ;; inline Scheme code (begin <expr> ...) ;; inline Scheme code
(include <file> ...) ;; load one or more files (include <file> ...) ;; load one or more files
(include-ci <file> ...) ;; as include, with case-folding (include-ci <file> ...) ;; as include, with case-folding
(include-shared <file> ...) ;; dynamic load a library (include-shared <file> ...) ;; dynamic load a library (non-R7RS)
(alias-for <library>) ;; a library alias (non-R7RS)
} }
\var{<import-spec>} can either be a module name or any of \var{<import-spec>} can either be a module name or any of
@ -210,13 +225,23 @@ where \var{<library-declarations>} can be any of
(only <import-spec> <id> ...) (only <import-spec> <id> ...)
(except <import-spec> <id> ...) (except <import-spec> <id> ...)
(rename <import-spec> (<from-id> <to-id>) ...) (rename <import-spec> (<from-id> <to-id>) ...)
(prefix <prefix-id> <import-spec>) (prefix <import-spec> <prefix-id>)
(drop-prefix <import-spec> <prefix-id>) ;; non-R7RS
} }
These forms perform basic selection and renaming of individual These forms perform basic selection and renaming of individual
identifiers from the given module. They may be composed to perform identifiers from the given module. They may be composed to perform
combined selection and renaming. combined selection and renaming.
Note while the repl provides default bindings as a convenience,
programs have strict semantics as in R7RS and must start with at least
one import, e.g.
\schemeblock{
(import (scheme base))
(write-string "Hello world!\n")
}
Some modules can be statically included in the initial configuration, Some modules can be statically included in the initial configuration,
and even more may be included in image files, however in general and even more may be included in image files, however in general
modules are searched for in a module load path. The definition of the modules are searched for in a module load path. The definition of the
@ -225,7 +250,7 @@ module \scheme{(foo bar baz)} is searched for in the file
installed directories, \scheme{"."} and \scheme{"./lib"}. Additional installed directories, \scheme{"."} and \scheme{"./lib"}. Additional
directories can be specified with the command-line options \ccode{-I} directories can be specified with the command-line options \ccode{-I}
and \ccode{-A} (see the command-line options below) or with the and \ccode{-A} (see the command-line options below) or with the
\scheme{add-modue-directory} procedure at runtime. You can search for \scheme{add-module-directory} procedure at runtime. You can search for
a module file with \scheme{(find-module-file <file>)}, or load it with a module file with \scheme{(find-module-file <file>)}, or load it with
\scheme{(load-module-file <file> <env>)}. \scheme{(load-module-file <file> <env>)}.
@ -285,23 +310,31 @@ constructors:
\subsection{Unicode} \subsection{Unicode}
Chibi supports Unicode strings, encoding them as utf8. This provides easy Chibi supports Unicode strings and I/O natively. Case mappings and
interoperability with many C libraries, but means that \scheme{string-ref} and comparisons, character properties, formatting and regular expressions
\scheme{string-set!} are O(n), so they should be avoided in are all Unicode aware, supporting the latest version 13.0 of the
performance-sensitive code. Unicode standard.
Internally strings are encoded as UTF-8. This provides easy
interoperability with many C libraries, but means that
\scheme{string-ref} and \scheme{string-set!} are O(n), so they should
be avoided in performance-sensitive code (unless you compile Chibi
with SEXP_USE_STRING_INDEX_TABLE).
In general you should use high-level APIs such as \scheme{string-map} In general you should use high-level APIs such as \scheme{string-map}
to ensure fast string iteration. String ports also provide a simple to ensure fast string iteration. String ports also provide a simple
way to efficiently iterate and construct strings, by looping over an and portable way to efficiently iterate and construct strings, by
input string or accumulating characters in an output string. looping over an input string or accumulating characters in an output
string.
The \scheme{in-string} and \scheme{in-string-reverse} iterators in the The \scheme{in-string} and \scheme{in-string-reverse} iterators in the
\scheme{(chibi loop)} module will also iterate over strings \scheme{(chibi loop)} module will also iterate over strings
efficiently while hiding the low-level details. efficiently while hiding the low-level details.
In the event that you do need a low-level interface, such as when In the event that you do need a low-level interface, such as when
writing your own iterator protocol, you should use the following writing your own iterator protocol, you should use string cursors.
string cursor API instead of indexes. \scheme{(srfi 130)} provides a portable API for this, or you can use
\scheme{(chibi string)} which builds on the following core procedures:
\itemlist[ \itemlist[
\item{\scheme{(string-cursor-start str)} \item{\scheme{(string-cursor-start str)}
@ -337,9 +370,10 @@ To use Chibi-Scheme in a program you need to link against the
\ccode{#include <chibi/eval.h>} \ccode{#include <chibi/eval.h>}
All definitions begin with a "sexp_" prefix, or "SEXP_" for constants. All definitions begin with a "sexp_" prefix, or "SEXP_" for constants
In addition to the prototypes and utility macros, this includes the (deliberately chosen not to conflict with other Scheme implementations
following type definitions: which typically use "scm_"). In addition to the prototypes and
utility macros, this includes the following type definitions:
\itemlist[ \itemlist[
\item{\ctype{sexp} - an s-expression, used to represent all Scheme objects} \item{\ctype{sexp} - an s-expression, used to represent all Scheme objects}
@ -373,6 +407,7 @@ void dostuff(sexp ctx) {
int main(int argc, char** argv) { int main(int argc, char** argv) {
sexp ctx; sexp ctx;
sexp_scheme_init();
ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0); ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0);
sexp_load_standard_env(ctx, NULL, SEXP_SEVEN); sexp_load_standard_env(ctx, NULL, SEXP_SEVEN);
sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1); sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1);
@ -400,7 +435,7 @@ temporary values we may generate, which is what the
\cmacro{sexp_gc_var2}, \cmacro{sexp_gc_preserve2} and \cmacro{sexp_gc_var2}, \cmacro{sexp_gc_preserve2} and
\cmacro{sexp_gc_release2} macros do (there are similar macros for \cmacro{sexp_gc_release2} macros do (there are similar macros for
values 1-6). Precise GCs prevent a class of memory leaks (and values 1-6). Precise GCs prevent a class of memory leaks (and
potential attackes based thereon), but if you prefer convenience then potential attacks based thereon), but if you prefer convenience then
Chibi can be compiled with a conservative GC and you can ignore these. Chibi can be compiled with a conservative GC and you can ignore these.
The interesting part is then the calls to \cfun{sexp_load}, The interesting part is then the calls to \cfun{sexp_load},
@ -522,6 +557,11 @@ Returns the current binding of \var{sym} in \var{env}, or \var{dflt} if there
is no binding. is no binding.
}} }}
\item{\ccode{sexp_env_import(sexp ctx, sexp to, sexp from, sexp ls, sexp immutp)}
\p{
Imports the bindings from environment \var{from} into environment \var{to}. \var{ls} is the list of bindings to import - if it is \scheme{#f} then import all bindings. If \var{immutp} is true the imported bindings are immutable and cannot be redefined.
}}
\item{\ccode{sexp_parameter_ref(sexp ctx, sexp param)} \item{\ccode{sexp_parameter_ref(sexp ctx, sexp param)}
\p{ \p{
Returns the current dynamic value of the parameter \var{param} in the Returns the current dynamic value of the parameter \var{param} in the
@ -626,13 +666,15 @@ sexp_release_object(ctx, obj)
Decrement the absolute reference count for \var{obj}. Decrement the absolute reference count for \var{obj}.
\subsection{API Index} \subsection{C API Index}
The above sections describe most everything you need for embedding in The above sections describe most everything you need for embedding in
a typical application, notably creating environments and evaluating a typical application, notably creating environments and evaluating
code from sexps, strings or files. The following sections expand on code from sexps, strings or files. The following sections expand on
additional macros and utilities for inspecting, accessing and creating additional macros and utilities for inspecting, accessing and creating
different Scheme types, and for performing port and string I/O. different Scheme types, and for performing port and string I/O. It is
incomplete - see the macros and SEXP_API annotated functions in the
include files (sexp.h, eval.h, bignum.h) for more bindings.
Being able to convert from C string to sexp, evaluate it, and convert Being able to convert from C string to sexp, evaluate it, and convert
the result back to a C string forms the basis of the C API. Because the result back to a C string forms the basis of the C API. Because
@ -660,10 +702,13 @@ need to check manually before applying the predicate.
\item{\ccode{sexp_fixnump(obj)} - \var{obj} is an immediate integer} \item{\ccode{sexp_fixnump(obj)} - \var{obj} is an immediate integer}
\item{\ccode{sexp_flonump(obj)} - \var{obj} is an inexact real} \item{\ccode{sexp_flonump(obj)} - \var{obj} is an inexact real}
\item{\ccode{sexp_bignump(obj)} - \var{obj} is a heap-allocated integer} \item{\ccode{sexp_bignump(obj)} - \var{obj} is a heap-allocated integer}
\item{\ccode{sexp_integerp(obj)} - \var{obj} is an integer} \item{\ccode{sexp_integerp(obj)} - \var{obj} is an integer (or flonum truncating without loss)}
\item{\ccode{sexp_ratiop(obj)} - \var{obj} is an exact rational (with SEXP_USE_RATIOS)}
\item{\ccode{sexp_complexp(obj)} - \var{obj} is a complex number (with SEXP_USE_COMPLEX)}
\item{\ccode{sexp_numberp(obj)} - \var{obj} is any kind of number} \item{\ccode{sexp_numberp(obj)} - \var{obj} is any kind of number}
\item{\ccode{sexp_charp(obj)} - \var{obj} is a character} \item{\ccode{sexp_charp(obj)} - \var{obj} is a character}
\item{\ccode{sexp_stringp(obj)} - \var{obj} is a string} \item{\ccode{sexp_stringp(obj)} - \var{obj} is a string}
\item{\ccode{sexp_string_cursorp(obj)} - \var{obj} is a string cursor}
\item{\ccode{sexp_bytesp(obj)} - \var{obj} is a bytevector} \item{\ccode{sexp_bytesp(obj)} - \var{obj} is a bytevector}
\item{\ccode{sexp_symbolp(obj)} - \var{obj} is a symbol} \item{\ccode{sexp_symbolp(obj)} - \var{obj} is a symbol}
\item{\ccode{sexp_idp(obj)} - \var{obj} is a symbol or hygienic identifier} \item{\ccode{sexp_idp(obj)} - \var{obj} is a symbol or hygienic identifier}
@ -721,7 +766,7 @@ check. The runtime does not prevent embedded NULLs inside strings,
however data after the NULL may be ignored. however data after the NULL may be ignored.
By default (unless you compile with -DSEXP_USE_UTF8_STRING=0), strings By default (unless you compile with -DSEXP_USE_UTF8_STRING=0), strings
are interpreted as utf8 encoded on the Scheme side, as describe in are interpreted as UTF-8 encoded on the Scheme side, as describe in
section Unicode above. In many cases you can ignore this on the C section Unicode above. In many cases you can ignore this on the C
side and just treat the string as an opaque sequence of bytes. side and just treat the string as an opaque sequence of bytes.
However, if you need to you can use the following macros to safely However, if you need to you can use the following macros to safely
@ -739,7 +784,7 @@ compiled with:
\item{\ccode{sexp sexp_substring_cursor(sexp ctx, sexp s, sexp i, sexp j)} - returns the substring between raw offsets \var{i} and \var{j}} \item{\ccode{sexp sexp_substring_cursor(sexp ctx, sexp s, sexp i, sexp j)} - returns the substring between raw offsets \var{i} and \var{j}}
] ]
When UTF8 support is not compiled in the cursor and non-cursor When UTF-8 support is not compiled in the cursor and non-cursor
variants are equivalent. variants are equivalent.
\subsubsection{Accessors} \subsubsection{Accessors}
@ -755,8 +800,12 @@ once.
\item{\ccode{sexp_unbox_boolean(obj)} - 1 if \var{obj} is \scheme{#t}, 0 otherwise} \item{\ccode{sexp_unbox_boolean(obj)} - 1 if \var{obj} is \scheme{#t}, 0 otherwise}
\item{\ccode{sexp_make_fixnum(n)} - creates a new fixnum representing int \var{n}} \item{\ccode{sexp_make_fixnum(n)} - creates a new fixnum representing int \var{n}}
\item{\ccode{sexp_unbox_fixnum(obj)} - converts a fixnum to a C integer} \item{\ccode{sexp_unbox_fixnum(obj)} - converts a fixnum to a C integer}
\item{\ccode{sexp_make_flonum(sexp ctx, float f)} - creates a new floating point value}
\item{\ccode{sexp_flonum_value(obj)} - converts a flonum to a C float}
\item{\ccode{sexp_make_character(ch)} - creates a new character representing char \var{ch}} \item{\ccode{sexp_make_character(ch)} - creates a new character representing char \var{ch}}
\item{\ccode{sexp_unbox_character(obj)} - converts a character to a C char} \item{\ccode{sexp_unbox_character(obj)} - converts a character to a C char}
\item{\ccode{sexp sexp_make_string_cursor(int offset)} - creates a string cursor for the given byte offset}
\item{\ccode{int sexp_unbox_string_cursor(sexp sc)} - returns the offset for the given string cursor}
\item{\ccode{sexp_car(pair)} - the car of \var{pair}} \item{\ccode{sexp_car(pair)} - the car of \var{pair}}
\item{\ccode{sexp_cdr(pair)} - the cdr of \var{pair}} \item{\ccode{sexp_cdr(pair)} - the cdr of \var{pair}}
\item{\ccode{sexp_ratio_numerator(q)} - the numerator of the ratio \var{q}} \item{\ccode{sexp_ratio_numerator(q)} - the numerator of the ratio \var{q}}
@ -785,6 +834,7 @@ Any of these may fail and return the OOM exception object.
\item{\ccode{sexp_cons(sexp ctx, sexp obj1, sexp obj2)} - create a new pair whose car is \var{obj1} and whose cdr is \var{obj2}} \item{\ccode{sexp_cons(sexp ctx, sexp obj1, sexp obj2)} - create a new pair whose car is \var{obj1} and whose cdr is \var{obj2}}
\item{\ccode{sexp_list1(sexp ctx, sexp obj)} - alias for sexp_cons(ctx, obj, SEXP_NULL)} \item{\ccode{sexp_list1(sexp ctx, sexp obj)} - alias for sexp_cons(ctx, obj, SEXP_NULL)}
\item{\ccode{sexp_list2(sexp ctx, sexp obj1, sexp obj2)} - create a list of two elements} \item{\ccode{sexp_list2(sexp ctx, sexp obj1, sexp obj2)} - create a list of two elements}
\item{\ccode{sexp_list3(sexp ctx, sexp obj1, sexp obj2, sexp obj3)} - create a list of three elements}
\item{\ccode{sexp_make_string(sexp ctx, sexp len, sexp ch)} - create a new Scheme string of \var{len} characters, all initialized to \var{ch}} \item{\ccode{sexp_make_string(sexp ctx, sexp len, sexp ch)} - create a new Scheme string of \var{len} characters, all initialized to \var{ch}}
\item{\ccode{sexp_c_string(sexp ctx, const char* str, int len)} - create a new Scheme string copying the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).} \item{\ccode{sexp_c_string(sexp ctx, const char* str, int len)} - create a new Scheme string copying the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).}
\item{\ccode{sexp_intern(sexp ctx, const char* str, int len)} - interns a symbol from the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).} \item{\ccode{sexp_intern(sexp ctx, const char* str, int len)} - interns a symbol from the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).}
@ -810,7 +860,7 @@ Any of these may fail and return the OOM exception object.
\item{\ccode{sexp_write_to_string(sexp ctx, sexp obj)} - return a Scheme string representation of \var{obj}} \item{\ccode{sexp_write_to_string(sexp ctx, sexp obj)} - return a Scheme string representation of \var{obj}}
\item{\ccode{sexp_open_input_string(sexp ctx, sexp str)} - equivalent to \scheme{open-input-string}} \item{\ccode{sexp_open_input_string(sexp ctx, sexp str)} - equivalent to \scheme{open-input-string}}
\item{\ccode{sexp_open_output_string(sexp ctx)} - equivalent to \scheme{open-output-string}} \item{\ccode{sexp_open_output_string(sexp ctx)} - equivalent to \scheme{open-output-string}}
\item{\ccode{sexp_get_output_string(sexp ctx, sexp port)} - equivalent to \scheme{open-output-string}} \item{\ccode{sexp_get_output_string(sexp ctx, sexp port)} - equivalent to \scheme{get-output-string}}
] ]
\subsubsection{Utilities} \subsubsection{Utilities}
@ -823,7 +873,7 @@ Any of these may fail and return the OOM exception object.
\item{\ccode{sexp_assq(sexp ctx, sexp x, sexp ls)} - \scheme{assq}} \item{\ccode{sexp_assq(sexp ctx, sexp x, sexp ls)} - \scheme{assq}}
\item{\ccode{sexp_reverse(sexp ctx, sexp ls)} - \scheme{reverse}} \item{\ccode{sexp_reverse(sexp ctx, sexp ls)} - \scheme{reverse}}
\item{\ccode{sexp_nreverse(sexp ctx, sexp ls)} - \scheme{reverse!}} \item{\ccode{sexp_nreverse(sexp ctx, sexp ls)} - \scheme{reverse!}}
\item{\ccode{sexp_append2(sexp ctx, sexp ls)} - \scheme{append} for two arguments} \item{\ccode{sexp_append2(sexp ctx, sexp ls1, sexp ls2)} - \scheme{append} for two arguments}
\item{\ccode{sexp_copy_list(sexp ctx, sexp ls)} - return a shallow copy of \var{ls}} \item{\ccode{sexp_copy_list(sexp ctx, sexp ls)} - return a shallow copy of \var{ls}}
\item{\ccode{sexp_list_to_vector(sexp ctx, sexp ls)} - \scheme{list->vector}} \item{\ccode{sexp_list_to_vector(sexp ctx, sexp ls)} - \scheme{list->vector}}
\item{\ccode{sexp_symbol_to_string(sexp ctx, sexp sym)} - \scheme{symbol->string}} \item{\ccode{sexp_symbol_to_string(sexp ctx, sexp sym)} - \scheme{symbol->string}}
@ -903,6 +953,39 @@ to any inherited from the parent type \var{parent}. If \var{parent} is false,
inherits from the default \var{object} record type. inherits from the default \var{object} record type.
}} }}
\item{\ccode{sexp sexp_register_c_type(sexp ctx, sexp name, sexp finalizer)}
\p{
Shortcut to defines a new type as a wrapper around a C pointer.
Returns the type object, which can be used with sexp_make_cpointer to
wrap instances of the type. The finalizer may be sexp_finalize_c_type
in which case managed pointers are freed as if allocated with malloc,
NULL in which case the pointers are never freed, or otherwise a
procedure of one argument which should release any resources.
}}
\item{\ccode{sexp sexp_make_cpointer(sexp ctx, sexp_uint_t type_tag, void* value, sexp parent, int freep)}
\p{
Creates a new instance of the type indicated by type_tag wrapping
value. If parent is provided, references to the child will also
preserve the parent, important e.g. to preserve an enclosing struct
when wrapped references to nested structs are still in use. If freep
is true, then when reclaimed by the GC the finalizer for this type,
if any, will be called on the instance.
You can retrieve the tag from a type object with sexp_type_tag(type).
}}
\item{\ccode{sexp sexp_lookup_type(sexp ctx, sexp name, sexp tag_or_id)}
\p{
Returns the type whose name matches the string \var{name}. If
\var{tag_or_id} is an integer, it is taken as the tag and requires the
numeric type tag (as from sexp_type_tag) to also match.
}
\p{If \var{tag_or_id} is a string, it is taken as the unique id of the
type, and must match sexp_type_id(type). However, currently
sexp_type_id(type) is never set.
}}
] ]
See the C FFI for an easy way to automate adding bindings for C See the C FFI for an easy way to automate adding bindings for C
@ -1177,7 +1260,7 @@ snow-fort):
\item{\hyperlink["http://srfi.schemers.org/srfi-8/srfi-8.html"]{(srfi 8) - receive}} \item{\hyperlink["http://srfi.schemers.org/srfi-8/srfi-8.html"]{(srfi 8) - receive}}
\item{\hyperlink["http://srfi.schemers.org/srfi-9/srfi-9.html"]{(srfi 9) - define-record-type}} \item{\hyperlink["http://srfi.schemers.org/srfi-9/srfi-9.html"]{(srfi 9) - define-record-type}}
\item{\hyperlink["http://srfi.schemers.org/srfi-11/srfi-11.html"]{(srfi 11) - let-values/let*-values}} \item{\hyperlink["http://srfi.schemers.org/srfi-11/srfi-11.html"]{(srfi 11) - let-values/let*-values}}
\item{\hyperlink["http://srfi.schemers.org/srfi-11/srfi-14.html"]{(srfi 14) - character-set library}} \item{\hyperlink["http://srfi.schemers.org/srfi-14/srfi-14.html"]{(srfi 14) - character-set library}}
\item{\hyperlink["http://srfi.schemers.org/srfi-16/srfi-16.html"]{(srfi 16) - case-lambda}} \item{\hyperlink["http://srfi.schemers.org/srfi-16/srfi-16.html"]{(srfi 16) - case-lambda}}
\item{\hyperlink["http://srfi.schemers.org/srfi-18/srfi-18.html"]{(srfi 18) - multi-threading support}} \item{\hyperlink["http://srfi.schemers.org/srfi-18/srfi-18.html"]{(srfi 18) - multi-threading support}}
\item{\hyperlink["http://srfi.schemers.org/srfi-22/srfi-22.html"]{(srfi 22) - running scheme scripts on Unix}} \item{\hyperlink["http://srfi.schemers.org/srfi-22/srfi-22.html"]{(srfi 22) - running scheme scripts on Unix}}
@ -1191,6 +1274,7 @@ snow-fort):
\item{\hyperlink["http://srfi.schemers.org/srfi-46/srfi-46.html"]{(srfi 46) - basic syntax-rules extensions}} \item{\hyperlink["http://srfi.schemers.org/srfi-46/srfi-46.html"]{(srfi 46) - basic syntax-rules extensions}}
\item{\hyperlink["http://srfi.schemers.org/srfi-55/srfi-55.html"]{(srfi 55) - require-extension}} \item{\hyperlink["http://srfi.schemers.org/srfi-55/srfi-55.html"]{(srfi 55) - require-extension}}
\item{\hyperlink["http://srfi.schemers.org/srfi-62/srfi-62.html"]{(srfi 62) - s-expression comments}} \item{\hyperlink["http://srfi.schemers.org/srfi-62/srfi-62.html"]{(srfi 62) - s-expression comments}}
\item{\hyperlink["http://srfi.schemers.org/srfi-64/srfi-64.html"]{(srfi 64) - a scheme API for test suites}}
\item{\hyperlink["http://srfi.schemers.org/srfi-69/srfi-69.html"]{(srfi 69) - basic hash tables}} \item{\hyperlink["http://srfi.schemers.org/srfi-69/srfi-69.html"]{(srfi 69) - basic hash tables}}
\item{\hyperlink["http://srfi.schemers.org/srfi-95/srfi-95.html"]{(srfi 95) - sorting and merging}} \item{\hyperlink["http://srfi.schemers.org/srfi-95/srfi-95.html"]{(srfi 95) - sorting and merging}}
\item{\hyperlink["http://srfi.schemers.org/srfi-98/srfi-98.html"]{(srfi 98) - environment access}} \item{\hyperlink["http://srfi.schemers.org/srfi-98/srfi-98.html"]{(srfi 98) - environment access}}
@ -1214,13 +1298,25 @@ snow-fort):
\item{\hyperlink["http://srfi.schemers.org/srfi-135/srfi-135.html"]{(srfi 135) - immutable texts}} \item{\hyperlink["http://srfi.schemers.org/srfi-135/srfi-135.html"]{(srfi 135) - immutable texts}}
\item{\hyperlink["http://srfi.schemers.org/srfi-139/srfi-139.html"]{(srfi 139) - syntax parameters}} \item{\hyperlink["http://srfi.schemers.org/srfi-139/srfi-139.html"]{(srfi 139) - syntax parameters}}
\item{\hyperlink["http://srfi.schemers.org/srfi-141/srfi-141.html"]{(srfi 141) - integer division}} \item{\hyperlink["http://srfi.schemers.org/srfi-141/srfi-141.html"]{(srfi 141) - integer division}}
\item{\hyperlink["http://srfi.schemers.org/srfi-143/srfi-142.html"]{(srfi 142) - bitwise operations}}
\item{\hyperlink["http://srfi.schemers.org/srfi-143/srfi-143.html"]{(srfi 143) - fixnums}} \item{\hyperlink["http://srfi.schemers.org/srfi-143/srfi-143.html"]{(srfi 143) - fixnums}}
\item{\hyperlink["http://srfi.schemers.org/srfi-144/srfi-144.html"]{(srfi 144) - flonums}} \item{\hyperlink["http://srfi.schemers.org/srfi-144/srfi-144.html"]{(srfi 144) - flonums}}
\item{\hyperlink["http://srfi.schemers.org/srfi-145/srfi-145.html"]{(srfi 145) - assumptions}} \item{\hyperlink["http://srfi.schemers.org/srfi-145/srfi-145.html"]{(srfi 145) - assumptions}}
\item{\hyperlink["http://srfi.schemers.org/srfi-147/srfi-147.html"]{(srfi 147) - custom macro transformers}} \item{\hyperlink["http://srfi.schemers.org/srfi-147/srfi-147.html"]{(srfi 147) - custom macro transformers}}
\item{\hyperlink["http://srfi.schemers.org/srfi-151/srfi-151.html"]{(srfi 151) - bitwise operators}} \item{\hyperlink["http://srfi.schemers.org/srfi-151/srfi-151.html"]{(srfi 151) - bitwise operators}}
\item{\hyperlink["http://srfi.schemers.org/srfi-154/srfi-154.html"]{(srfi 154) - first-class dynamic extents}} \item{\hyperlink["http://srfi.schemers.org/srfi-154/srfi-154.html"]{(srfi 154) - first-class dynamic extents}}
\item{\hyperlink["http://srfi.schemers.org/srfi-159/srfi-159.html"]{(srfi 159) - combinator formatting}} \item{\hyperlink["http://srfi.schemers.org/srfi-158/srfi-158.html"]{(srfi 158) - generators and accumulators}}
\item{\hyperlink["http://srfi.schemers.org/srfi-160/srfi-160.html"]{(srfi 160) - homogeneous numeric vector libraries}}
\item{\hyperlink["http://srfi.schemers.org/srfi-165/srfi-165.html"]{(srfi 165) - the environment Monad}}
\item{\hyperlink["http://srfi.schemers.org/srfi-166/srfi-166.html"]{(srfi 166) - monadic formatting}}
\item{\hyperlink["http://srfi.schemers.org/srfi-179/srfi-179.html"]{(srfi 179) - nonempty intervals and generalized arrays}}
\item{\hyperlink["http://srfi.schemers.org/srfi-188/srfi-188.html"]{(srfi 188) - splicing binding constructs for syntactic keywords}}
\item{\hyperlink["http://srfi.schemers.org/srfi-193/srfi-193.html"]{(srfi 193) - command-line}}
\item{\hyperlink["http://srfi.schemers.org/srfi-211/srfi-211.html"]{(srfi 211) - scheme macro libaries}}
\item{\hyperlink["http://srfi.schemers.org/srfi-219/srfi-219.html"]{(srfi 219) - define higher-order lambda}}
\item{\hyperlink["http://srfi.schemers.org/srfi-227/srfi-227.html"]{(srfi 227) - optional arguments}}
\item{\hyperlink["http://srfi.schemers.org/srfi-229/srfi-229.html"]{(srfi 229) - tagged procedures}}
\item{\hyperlink["http://srfi.schemers.org/srfi-231/srfi-231.html"]{(srfi 231) - intervals and generalized arrays}}
] ]
@ -1233,10 +1329,30 @@ namespace.
\item{\hyperlink["lib/chibi/ast.html"]{(chibi ast) - Abstract Syntax Tree and other internal data types}} \item{\hyperlink["lib/chibi/ast.html"]{(chibi ast) - Abstract Syntax Tree and other internal data types}}
\item{\hyperlink["lib/chibi/assert.html"]{(chibi assert) - A nicer assert macro}}
\item{\hyperlink["lib/chibi/base64.html"]{(chibi base64) - Base64 encoding and decoding}}
\item{\hyperlink["lib/chibi/binary-record.html"]{(chibi binary-record) - Record types with binary serialization}}
\item{\hyperlink["lib/chibi/bytevector.html"]{(chibi bytevector) - Bytevector Utilities}}
\item{\hyperlink["lib/chibi/config.html"]{(chibi config) - General configuration management}} \item{\hyperlink["lib/chibi/config.html"]{(chibi config) - General configuration management}}
\item{\hyperlink["lib/chibi/crypto/md5.html"]{(chibi crypto md5) - MD5 hash}}
\item{\hyperlink["lib/chibi/crypto/rsa.html"]{(chibi crypto rsa) - RSA public key encryption}}
\item{\hyperlink["lib/chibi/crypto/sha2.html"]{(chibi crypto sha2) - SHA-2 hash}}
\item{\hyperlink["lib/chibi/diff.html"]{(chibi diff) - LCS Algorithm and diff utilities}}
\item{\hyperlink["lib/chibi/disasm.html"]{(chibi disasm) - Disassembler for the virtual machine}} \item{\hyperlink["lib/chibi/disasm.html"]{(chibi disasm) - Disassembler for the virtual machine}}
\item{\hyperlink["lib/chibi/doc.html"]{(chibi doc) - Chibi documentation utilities}}
\item{\hyperlink["lib/chibi/edit-distance.html"]{(chibi edit-distance) - A levenshtein distance implementation}}
\item{\hyperlink["lib/chibi/equiv.html"]{(chibi equiv) - A version of \scheme{equal?} which is guaranteed to terminate}} \item{\hyperlink["lib/chibi/equiv.html"]{(chibi equiv) - A version of \scheme{equal?} which is guaranteed to terminate}}
\item{\hyperlink["lib/chibi/filesystem.html"]{(chibi filesystem) - Interface to the filesystem and file descriptor objects}} \item{\hyperlink["lib/chibi/filesystem.html"]{(chibi filesystem) - Interface to the filesystem and file descriptor objects}}
@ -1247,16 +1363,36 @@ namespace.
\item{\hyperlink["lib/chibi/io.html"]{(chibi io) - Various I/O extensions and custom ports}} \item{\hyperlink["lib/chibi/io.html"]{(chibi io) - Various I/O extensions and custom ports}}
\item{\hyperlink["lib/chibi/iset/base.html"]{(chibi iset base) - Compact integer sets}}
\item{\hyperlink["lib/chibi/iset/base.html"]{(chibi iset base) - Compact integer sets}}
\item{\hyperlink["lib/chibi/iset/constructors.html"]{(chibi iset constructors) - Compact integer set construction}}
\item{\hyperlink["lib/chibi/iset/iterators.html"]{(chibi iset iterators) - Iterating over compact integer sets}}
\item{\hyperlink["lib/chibi/json.html"]{(chibi json) - JSON reading and writing}}
\item{\hyperlink["lib/chibi/loop.html"]{(chibi loop) - Fast and extensible loop syntax}} \item{\hyperlink["lib/chibi/loop.html"]{(chibi loop) - Fast and extensible loop syntax}}
\item{\hyperlink["lib/chibi/match.html"]{(chibi match) - Intuitive and widely supported pattern matching syntax}} \item{\hyperlink["lib/chibi/match.html"]{(chibi match) - Intuitive and widely supported pattern matching syntax}}
\item{\hyperlink["lib/chibi/math/prime.html"]{(chibi math prime) - Prime number utilities}}
\item{\hyperlink["lib/chibi/memoize.html"]{(chibi memoize) - Procedure memoization}}
\item{\hyperlink["lib/chibi/mime.html"]{(chibi mime) - Parse MIME files into SXML}} \item{\hyperlink["lib/chibi/mime.html"]{(chibi mime) - Parse MIME files into SXML}}
\item{\hyperlink["lib/chibi/modules.html"]{(chibi modules) - Introspection for the module system itself}} \item{\hyperlink["lib/chibi/modules.html"]{(chibi modules) - Introspection for the module system itself}}
\item{\hyperlink["lib/chibi/net.html"]{(chibi net) - Simple networking interface}} \item{\hyperlink["lib/chibi/net.html"]{(chibi net) - Simple networking interface}}
\item{\hyperlink["lib/chibi/net/http-server.html"]{(chibi net http-server) - Simple http-server with servlet support}}
\item{\hyperlink["lib/chibi/net/servlet.html"]{(chibi net servlet) - HTTP servlets for http-server or CGI}}
\item{\hyperlink["lib/chibi/optional.html"]{(chibi optional) - Syntax to support optional and named keyword arguments}}
\item{\hyperlink["lib/chibi/parse.html"]{(chibi parse) - Parser combinators with convenient syntax}} \item{\hyperlink["lib/chibi/parse.html"]{(chibi parse) - Parser combinators with convenient syntax}}
\item{\hyperlink["lib/chibi/pathname.html"]{(chibi pathname) - Utilities to decompose and manipulate pathnames}} \item{\hyperlink["lib/chibi/pathname.html"]{(chibi pathname) - Utilities to decompose and manipulate pathnames}}
@ -1265,16 +1401,22 @@ namespace.
\item{\hyperlink["lib/chibi/repl.html"]{(chibi repl) - A full-featured Read/Eval/Print Loop}} \item{\hyperlink["lib/chibi/repl.html"]{(chibi repl) - A full-featured Read/Eval/Print Loop}}
\item{\hyperlink["lib/chibi/shell.html"]{(chibi shell) - Process combinators with high-level pipeline syntax in the spirit of SCSH.}}
\item{\hyperlink["lib/chibi/show.html"]{(chibi show) - Monadic formatting.}}
\item{\hyperlink["lib/chibi/scribble.html"]{(chibi scribble) - A parser for the scribble syntax used to write this manual}} \item{\hyperlink["lib/chibi/scribble.html"]{(chibi scribble) - A parser for the scribble syntax used to write this manual}}
\item{\hyperlink["lib/chibi/show.html"]{(chibi show) - A combinator formatting library}} \item{\hyperlink["lib/chibi/string.html"]{(chibi string) - Cursor-based string library (predecessor to SRFI 130)}}
\item{\hyperlink["lib/chibi/show/base.scm"]{(chibi show base) - Base combinator formatting}}
\item{\hyperlink["lib/chibi/stty.html"]{(chibi stty) - A high-level interface to ioctl}} \item{\hyperlink["lib/chibi/stty.html"]{(chibi stty) - A high-level interface to ioctl}}
\item{\hyperlink["lib/chibi/sxml.html"]{(chibi sxml) - SXML utilities}}
\item{\hyperlink["lib/chibi/system.html"]{(chibi system) - Access to the host system and current user information}} \item{\hyperlink["lib/chibi/system.html"]{(chibi system) - Access to the host system and current user information}}
\item{\hyperlink["lib/chibi/temp-file.html"]{(chibi temp-file) - Temporary file and directory creation}}
\item{\hyperlink["lib/chibi/test.html"]{(chibi test) - A simple unit testing framework}} \item{\hyperlink["lib/chibi/test.html"]{(chibi test) - A simple unit testing framework}}
\item{\hyperlink["lib/chibi/time.html"]{(chibi time) - An interface to the current system time}} \item{\hyperlink["lib/chibi/time.html"]{(chibi time) - An interface to the current system time}}
@ -1292,7 +1434,7 @@ namespace.
\section{Snow Package Manager} \section{Snow Package Manager}
Beyond the distributed modules, Chibi comes with a package manager Beyond the distributed modules, Chibi comes with a package manager
based on \hyperlink["http://trac.sacrideo.us/wg/wiki/Snow"]{Snow2} based on \hyperlink["https://small.r7rs.org/wiki/Snow/"]{Snow2}
which can be used to share R7RS libraries. Packages are distributed which can be used to share R7RS libraries. Packages are distributed
as tar gzipped files called "snowballs," and may contain multiple as tar gzipped files called "snowballs," and may contain multiple
libraries. The program is installed as \scheme{snow-chibi}. The libraries. The program is installed as \scheme{snow-chibi}. The
@ -1306,7 +1448,9 @@ with image files on your platform you can run
By default \scheme{snow-chibi} looks for packages in the public By default \scheme{snow-chibi} looks for packages in the public
repository \hyperlink["http://snow-fort.org/"]{http://snow-fort.org/}, repository \hyperlink["http://snow-fort.org/"]{http://snow-fort.org/},
though you can customize this with the \scheme{--repository-uri} option. though you can customize this with the \scheme{--repository-uri} or
\scheme{--repo} option (e.g. "http://snow-fort.org/s/repo.scm").
Packages can be browsed on the site, but you can also search and query Packages can be browsed on the site, but you can also search and query
from the command-line tool. from the command-line tool.
@ -1338,6 +1482,11 @@ older version, a warning is printed.}}
The basic package management functionality, installing upgrading and The basic package management functionality, installing upgrading and
removing packages. removing packages.
By default the packages will be managed for Chibi. You can specify
what Scheme implementation to install, upgrade... with
\scheme{--implementations} or \scheme{--impls} option. Specify "all"
to manage all supported implementations.
\itemlist[ \itemlist[
\item{install names ... - install packages \item{install names ... - install packages
@ -1346,8 +1495,10 @@ use the dotted shorthand. Explicit names for packages are optional,
as a package can always be referred to by the name of any library it as a package can always be referred to by the name of any library it
contains. If multiple packages provide libraries with the same name, contains. If multiple packages provide libraries with the same name,
you will be asked to confirm which implementation to install.} you will be asked to confirm which implementation to install.}
\p{You can also bypass the repository and install a manually downloaded \p{You can also bypass the repository and install a manually downloaded
snowball by giving a path to that file instead of a name.}} snowball by giving a path to that file instead of a name. No package
dependencies will be checked for install in this case}}
\item{upgrade names ... - upgrade installed packages \item{upgrade names ... - upgrade installed packages
\p{Upgrade the packages if new versions are available. \p{Upgrade the packages if new versions are available.
@ -1369,6 +1520,10 @@ update with this command.}}
Creating packages can be done with the \scheme{package} command, Creating packages can be done with the \scheme{package} command,
though other commands allow for uploading to public repositories. though other commands allow for uploading to public repositories.
By default the public repository is
\hyperlink["http://snow-fort.org/"]{http://snow-fort.org/} but you can
customize this with the \scheme{--host} option.
\itemlist[ \itemlist[
\item{package files ... - create a package \item{package files ... - create a package
@ -1466,10 +1621,12 @@ command tells you which you currently have installed. The following
are currently supported: are currently supported:
\itemlist[ \itemlist[
\item{chibi - native support as of version 0.7.3} \item{chibi - version >= 0.7.3}
\item{chicken - version >= 4.9.0 with the \scheme{r7rs} egg} \item{chicken - version >= 4.9.0 with the \scheme{r7rs} egg}
\item{cyclone - version >= 0.5.3}
\item{foment - version >= 0.4} \item{foment - version >= 0.4}
\item{gauche - version >= 0.9.4} \item{gauche - version >= 0.9.4}
\item{kawa - version >= 2.0; you need to add the install dir to the search path, e.g. \scheme{-Dkawa.import.path=/usr/local/share/kawa}} \item{kawa - version >= 2.0; you need to add the install dir to the search path, e.g. \scheme{-Dkawa.import.path=/usr/local/share/kawa}}
\item{larceny - version 0.98; you need to add "lib/Snow" to the paths in startup.sch} \item{larceny - version 0.98; you need to add "lib/Snow" to the paths in startup.sch}
\item{sagittarius - version >= 0.98}
] ]

290
eval.c
View file

@ -45,7 +45,9 @@ void sexp_warn (sexp ctx, const char *msg, sexp x) {
if (sexp_oportp(out)) { if (sexp_oportp(out)) {
sexp_write_string(ctx, strictp ? "ERROR: " : "WARNING: ", out); sexp_write_string(ctx, strictp ? "ERROR: " : "WARNING: ", out);
sexp_write_string(ctx, msg, out); sexp_write_string(ctx, msg, out);
if (x != SEXP_UNDEF) {
sexp_write(ctx, x, out); sexp_write(ctx, x, out);
}
sexp_write_char(ctx, '\n', out); sexp_write_char(ctx, '\n', out);
if (strictp) sexp_stack_trace(ctx, out); if (strictp) sexp_stack_trace(ctx, out);
} }
@ -206,7 +208,7 @@ sexp sexp_env_exports_op (sexp ctx, sexp self, sexp_sint_t n, sexp env) {
res = SEXP_NULL; res = SEXP_NULL;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_RENAME_BINDINGS
for (ls=sexp_env_renames(env); sexp_pairp(ls); ls=sexp_env_next_cell(ls)) for (ls=sexp_env_renames(env); sexp_pairp(ls); ls=sexp_env_next_cell(ls))
sexp_push(ctx, res, sexp_cadr(ls)); sexp_push(ctx, res, sexp_car(ls));
#endif #endif
for (ls=sexp_env_bindings(env); sexp_pairp(ls); ls=sexp_env_next_cell(ls)) for (ls=sexp_env_bindings(env); sexp_pairp(ls); ls=sexp_env_next_cell(ls))
if (sexp_env_value(ls) != SEXP_UNDEF) if (sexp_env_value(ls) != SEXP_UNDEF)
@ -221,7 +223,7 @@ sexp sexp_extend_env (sexp ctx, sexp env, sexp vars, sexp value) {
e = sexp_alloc_type(ctx, env, SEXP_ENV); e = sexp_alloc_type(ctx, env, SEXP_ENV);
sexp_env_parent(e) = env; sexp_env_parent(e) = env;
sexp_env_bindings(e) = SEXP_NULL; sexp_env_bindings(e) = SEXP_NULL;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_STABLE_ABI || SEXP_USE_RENAME_BINDINGS
sexp_env_renames(e) = SEXP_NULL; sexp_env_renames(e) = SEXP_NULL;
#endif #endif
for ( ; sexp_pairp(vars); vars = sexp_cdr(vars)) for ( ; sexp_pairp(vars); vars = sexp_cdr(vars))
@ -241,7 +243,7 @@ sexp sexp_extend_synclo_env (sexp ctx, sexp env) {
e2 = e2 ? (sexp_env_parent(e2) = sexp_alloc_type(ctx, env, SEXP_ENV)) : e; e2 = e2 ? (sexp_env_parent(e2) = sexp_alloc_type(ctx, env, SEXP_ENV)) : e;
sexp_env_bindings(e2) = sexp_env_bindings(e1); sexp_env_bindings(e2) = sexp_env_bindings(e1);
sexp_env_syntactic_p(e2) = 1; sexp_env_syntactic_p(e2) = 1;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_STABLE_ABI || SEXP_USE_RENAME_BINDINGS
sexp_env_renames(e2) = sexp_env_renames(e1); sexp_env_renames(e2) = sexp_env_renames(e1);
#endif #endif
} }
@ -361,6 +363,17 @@ sexp sexp_complete_bytecode (sexp ctx) {
#if SEXP_USE_FULL_SOURCE_INFO #if SEXP_USE_FULL_SOURCE_INFO
if (sexp_bytecode_source(bc) && sexp_pairp(sexp_bytecode_source(bc))) { if (sexp_bytecode_source(bc) && sexp_pairp(sexp_bytecode_source(bc))) {
sexp_bytecode_source(bc) = sexp_nreverse(ctx, sexp_bytecode_source(bc)); sexp_bytecode_source(bc) = sexp_nreverse(ctx, sexp_bytecode_source(bc));
/* omit the leading -1 source marker for the bytecode if the next */
/* entry is in the same file */
if (sexp_pairp(sexp_cdr(sexp_bytecode_source(bc))) &&
sexp_pairp(sexp_car(sexp_bytecode_source(bc))) &&
sexp_pairp(sexp_cdar(sexp_bytecode_source(bc))) &&
sexp_pairp(sexp_cadr(sexp_bytecode_source(bc))) &&
sexp_pairp(sexp_cdr(sexp_cadr(sexp_bytecode_source(bc)))) &&
sexp_cadr(sexp_car(sexp_bytecode_source(bc)))
== sexp_cadr(sexp_cadr(sexp_bytecode_source(bc)))) {
sexp_bytecode_source(bc) = sexp_cdr(sexp_bytecode_source(bc));
}
sexp_bytecode_source(bc) = sexp_list_to_vector(ctx, sexp_bytecode_source(bc)); sexp_bytecode_source(bc) = sexp_list_to_vector(ctx, sexp_bytecode_source(bc));
} }
#endif #endif
@ -384,6 +397,7 @@ static sexp sexp_make_macro (sexp ctx, sexp p, sexp e) {
sexp mac = sexp_alloc_type(ctx, macro, SEXP_MACRO); sexp mac = sexp_alloc_type(ctx, macro, SEXP_MACRO);
sexp_macro_env(mac) = e; sexp_macro_env(mac) = e;
sexp_macro_proc(mac) = p; sexp_macro_proc(mac) = p;
sexp_macro_aux(mac) = SEXP_FALSE;
return mac; return mac;
} }
@ -397,10 +411,12 @@ sexp sexp_make_synclo_op (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp fv,
sexp_synclo_env(res) = sexp_synclo_env(expr); sexp_synclo_env(res) = sexp_synclo_env(expr);
sexp_synclo_free_vars(res) = sexp_synclo_free_vars(expr); sexp_synclo_free_vars(res) = sexp_synclo_free_vars(expr);
sexp_synclo_expr(res) = sexp_synclo_expr(expr); sexp_synclo_expr(res) = sexp_synclo_expr(expr);
sexp_synclo_rename(res) = sexp_synclo_rename(expr);
} else { } else {
sexp_synclo_env(res) = env; sexp_synclo_env(res) = env;
sexp_synclo_free_vars(res) = fv; sexp_synclo_free_vars(res) = fv;
sexp_synclo_expr(res) = expr; sexp_synclo_expr(res) = expr;
sexp_synclo_rename(res) = SEXP_FALSE;
} }
return res; return res;
} }
@ -486,16 +502,19 @@ static void sexp_init_eval_context_bytecodes (sexp ctx) {
#endif #endif
void sexp_init_eval_context_globals (sexp ctx) { void sexp_init_eval_context_globals (sexp ctx) {
const char* no_sys_path;
const char* user_path; const char* user_path;
ctx = sexp_make_child_context(ctx, NULL); ctx = sexp_make_child_context(ctx, NULL);
#if ! SEXP_USE_NATIVE_X86 #if ! SEXP_USE_NATIVE_X86
sexp_init_eval_context_bytecodes(ctx); sexp_init_eval_context_bytecodes(ctx);
#endif #endif
sexp_global(ctx, SEXP_G_MODULE_PATH) = SEXP_NULL; sexp_global(ctx, SEXP_G_MODULE_PATH) = SEXP_NULL;
sexp_add_path(ctx, sexp_default_module_path);
user_path = getenv(SEXP_MODULE_PATH_VAR); user_path = getenv(SEXP_MODULE_PATH_VAR);
if (!user_path) user_path = sexp_default_user_module_path; if (!user_path) user_path = sexp_default_user_module_path;
sexp_add_path(ctx, user_path); sexp_add_path(ctx, user_path);
no_sys_path = getenv(SEXP_NO_SYSTEM_PATH_VAR);
if (!no_sys_path || strcmp(no_sys_path, "0")==0)
sexp_add_path(ctx, sexp_default_module_path);
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR) sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR)
= sexp_user_exception(ctx, SEXP_FALSE, "I/O would block", SEXP_NULL); = sexp_user_exception(ctx, SEXP_FALSE, "I/O would block", SEXP_NULL);
@ -593,30 +612,28 @@ sexp sexp_syntactic_closure_expr_op (sexp ctx, sexp self, sexp_sint_t n, sexp x)
return (sexp_synclop(x) ? sexp_synclo_expr(x) : x); return (sexp_synclop(x) ? sexp_synclo_expr(x) : x);
} }
#if SEXP_USE_READER_LABELS static int sexp_contains_syntax_p_bound(sexp x, int depth) {
static int sexp_cyclic_synclop(sexp x) { int i;
sexp ls1, ls2; sexp ls1, ls2;
if (!sexp_pairp(x)) if (sexp_synclop(x))
return 0;
for (ls1=x, ls2=sexp_id_name(sexp_cdr(ls1));
sexp_pairp(ls2) && sexp_pairp(sexp_id_name(sexp_cdr(ls2)));
ls1=sexp_id_name(sexp_cdr(ls1)),
ls2=sexp_id_name(sexp_cdr(sexp_id_name(sexp_cdr(ls2))))) {
if (ls1 == ls2 || ls1 == sexp_id_name(sexp_car(ls2)))
return 1; return 1;
if (depth <= 0)
return 0;
if (sexp_pairp(x)) {
for (i=0, ls1=x, ls2=x; sexp_pairp(ls1); ls1=sexp_cdr(ls1), ls2=(i++ & 1 ? sexp_cdr(ls2) : ls2)) {
if (sexp_contains_syntax_p_bound(sexp_car(ls1), depth-1))
return 1;
if (i > 0 && (ls1 == ls2 || ls1 == sexp_car(ls2)))
return 0; /* cycle, no synclo found, assume none */
} }
for (ls1=x, ls2=sexp_id_name(sexp_car(ls1)); return sexp_contains_syntax_p_bound(ls1, depth-1);
sexp_pairp(ls2) && sexp_pairp(sexp_id_name(sexp_car(ls2))); } else if (sexp_vectorp(x)) {
ls1=sexp_id_name(sexp_car(ls1)), for (i = 0; i < sexp_vector_length(x); ++i)
ls2=sexp_id_name(sexp_car(sexp_id_name(sexp_car(ls2))))) { if (sexp_contains_syntax_p_bound(sexp_vector_ref(x, sexp_make_fixnum(i)), depth-1))
if (ls1 == ls2 || ls1 == sexp_id_name(sexp_cdr(ls2)))
return 1; return 1;
} }
return 0; return 0;
} }
#else
#define sexp_cyclic_synclop(x) 0
#endif
sexp sexp_strip_synclos_bound (sexp ctx, sexp x, int depth) { sexp sexp_strip_synclos_bound (sexp ctx, sexp x, int depth) {
int i; int i;
@ -624,7 +641,7 @@ sexp sexp_strip_synclos_bound (sexp ctx, sexp x, int depth) {
if (depth <= 0) return x; if (depth <= 0) return x;
sexp_gc_preserve3(ctx, res, kar, kdr); sexp_gc_preserve3(ctx, res, kar, kdr);
x = sexp_id_name(x); x = sexp_id_name(x);
if (sexp_pairp(x) && !sexp_cyclic_synclop(x)) { if (sexp_pairp(x)) {
kar = sexp_strip_synclos_bound(ctx, sexp_car(x), depth-1); kar = sexp_strip_synclos_bound(ctx, sexp_car(x), depth-1);
kdr = sexp_strip_synclos_bound(ctx, sexp_cdr(x), depth-1); kdr = sexp_strip_synclos_bound(ctx, sexp_cdr(x), depth-1);
res = sexp_cons(ctx, kar, kdr); res = sexp_cons(ctx, kar, kdr);
@ -641,11 +658,15 @@ sexp sexp_strip_synclos_bound (sexp ctx, sexp x, int depth) {
} }
sexp sexp_strip_synclos (sexp ctx, sexp self, sexp_sint_t n, sexp x) { sexp sexp_strip_synclos (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
if (!sexp_contains_syntax_p_bound(x, SEXP_STRIP_SYNCLOS_BOUND))
return x;
return sexp_strip_synclos_bound(ctx, x, SEXP_STRIP_SYNCLOS_BOUND); return sexp_strip_synclos_bound(ctx, x, SEXP_STRIP_SYNCLOS_BOUND);
} }
sexp sexp_identifier_eq_op (sexp ctx, sexp self, sexp_sint_t n, sexp e1, sexp id1, sexp e2, sexp id2) { sexp sexp_identifier_eq_op (sexp ctx, sexp self, sexp_sint_t n, sexp e1, sexp id1, sexp e2, sexp id2) {
sexp cell1, cell2; sexp cell1, cell2;
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e1);
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e2);
cell1 = sexp_env_cell(ctx, e1, id1, 0); cell1 = sexp_env_cell(ctx, e1, id1, 0);
cell2 = sexp_env_cell(ctx, e2, id2, 0); cell2 = sexp_env_cell(ctx, e2, id2, 0);
if (cell1 && (cell1 == cell2)) if (cell1 && (cell1 == cell2))
@ -746,6 +767,26 @@ static sexp analyze_seq (sexp ctx, sexp ls, int depth, int defok) {
return res; return res;
} }
static sexp analyze_macro_once (sexp ctx, sexp x, sexp op, int depth) {
sexp res;
sexp_gc_var1(tmp);
sexp_gc_preserve1(ctx, tmp);
tmp = sexp_cons(ctx, sexp_macro_env(op), SEXP_NULL);
tmp = sexp_cons(ctx, sexp_context_env(ctx), tmp);
tmp = sexp_cons(ctx, x, tmp);
res = sexp_exceptionp(tmp) ? tmp : sexp_make_child_context(ctx, sexp_context_lambda(ctx));
if (!sexp_exceptionp(res) && !sexp_exceptionp(sexp_context_exception(ctx)))
res = sexp_apply(res, sexp_macro_proc(op), tmp);
if (sexp_pairp(sexp_car(tmp)) && sexp_pair_source(sexp_car(tmp))) {
if (sexp_pairp(res))
sexp_pair_source(res) = sexp_pair_source(sexp_car(tmp));
else if (sexp_exceptionp(res) && sexp_not(sexp_exception_source(x)))
sexp_exception_source(res) = sexp_pair_source(sexp_car(tmp));
}
sexp_gc_release1(ctx);
return res;
}
static sexp analyze_var_ref (sexp ctx, sexp x, sexp *varenv) { static sexp analyze_var_ref (sexp ctx, sexp x, sexp *varenv) {
sexp env = sexp_context_env(ctx), res; sexp env = sexp_context_env(ctx), res;
sexp_gc_var1(cell); sexp_gc_var1(cell);
@ -765,14 +806,23 @@ static sexp analyze_var_ref (sexp ctx, sexp x, sexp *varenv) {
static sexp analyze_set (sexp ctx, sexp x, int depth) { static sexp analyze_set (sexp ctx, sexp x, int depth) {
sexp res, varenv; sexp res, varenv;
sexp_gc_var2(ref, value); sexp_gc_var4(ref, value, cell, op);
sexp_gc_preserve2(ctx, ref, value); sexp_gc_preserve4(ctx, ref, value, cell, op);
if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x)) if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x))
&& sexp_nullp(sexp_cdddr(x)) && sexp_idp(sexp_cadr(x)))) { && sexp_nullp(sexp_cdddr(x)) && sexp_idp(sexp_cadr(x)))) {
res = sexp_compile_error(ctx, "bad set! syntax", x); res = sexp_compile_error(ctx, "bad set! syntax", x);
} else {
cell = sexp_env_cell(ctx, sexp_context_env(ctx), sexp_cadr(x), 0);
op = cell ? sexp_cdr(cell) : NULL;
if (op && sexp_macrop(op)) {
if (!sexp_procedure_variable_transformer_p(sexp_macro_proc(op))) {
res = sexp_compile_error(ctx, "can't mutate a syntax keyword", sexp_cadr(x));
} else {
res = analyze_macro_once(ctx, x, op, depth);
}
} else { } else {
ref = analyze_var_ref(ctx, sexp_cadr(x), &varenv); ref = analyze_var_ref(ctx, sexp_cadr(x), &varenv);
if (sexp_lambdap(sexp_ref_loc(ref))) if (sexp_refp(ref) && sexp_lambdap(sexp_ref_loc(ref)))
sexp_insert(ctx, sexp_lambda_sv(sexp_ref_loc(ref)), sexp_ref_name(ref)); sexp_insert(ctx, sexp_lambda_sv(sexp_ref_loc(ref)), sexp_ref_name(ref));
value = analyze(ctx, sexp_caddr(x), depth, 0); value = analyze(ctx, sexp_caddr(x), depth, 0);
if (sexp_exceptionp(ref)) { if (sexp_exceptionp(ref)) {
@ -787,25 +837,33 @@ static sexp analyze_set (sexp ctx, sexp x, int depth) {
sexp_set_source(res) = sexp_pair_source(x); sexp_set_source(res) = sexp_pair_source(x);
} }
} }
sexp_gc_release2(ctx); }
sexp_gc_release4(ctx);
return res; return res;
} }
#define sexp_return(res, val) do {res=val; goto cleanup;} while (0) #define sexp_return(res, val) do {res=val; goto cleanup;} while (0)
static sexp analyze_lambda (sexp ctx, sexp x, int depth) { static sexp analyze_lambda (sexp ctx, sexp x, int depth) {
int trailing_non_procs; int trailing_non_procs, verify_duplicates_p;
sexp name, ls, ctx3; sexp name, ls, ctx3;
sexp_gc_var6(res, body, tmp, value, defs, ctx2); sexp_gc_var6(res, body, tmp, value, defs, ctx2);
sexp_gc_preserve6(ctx, res, body, tmp, value, defs, ctx2); sexp_gc_preserve6(ctx, res, body, tmp, value, defs, ctx2);
/* verify syntax */ /* verify syntax */
if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x)))) if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x))))
sexp_return(res, sexp_compile_error(ctx, "bad lambda syntax", x)); sexp_return(res, sexp_compile_error(ctx, "bad lambda syntax", x));
verify_duplicates_p = sexp_length_unboxed(sexp_cadr(x)) < 100;
for (ls=sexp_cadr(x); sexp_pairp(ls); ls=sexp_cdr(ls)) for (ls=sexp_cadr(x); sexp_pairp(ls); ls=sexp_cdr(ls))
if (! sexp_idp(sexp_car(ls))) if (! sexp_idp(sexp_car(ls)))
sexp_return(res, sexp_compile_error(ctx, "non-symbol parameter", x)); sexp_return(res, sexp_compile_error(ctx, "non-symbol parameter", x));
else if (sexp_truep(sexp_memq(ctx, sexp_car(ls), sexp_cdr(ls)))) else if (verify_duplicates_p && sexp_truep(sexp_memq(ctx, sexp_car(ls), sexp_cdr(ls))))
sexp_return(res, sexp_compile_error(ctx, "duplicate parameter", x)); sexp_return(res, sexp_compile_error(ctx, "duplicate parameter", x));
if (! sexp_nullp(ls)) { /* verify rest param */
if (! sexp_idp(ls))
sexp_return(res, sexp_compile_error(ctx, "non-symbol parameter", x));
else if (sexp_truep(sexp_memq(ctx, ls, sexp_cadr(x))))
sexp_return(res, sexp_compile_error(ctx, "duplicate parameter", x));
}
/* build lambda and analyze body */ /* build lambda and analyze body */
res = sexp_make_lambda(ctx, tmp=sexp_copy_list(ctx, sexp_cadr(x))); res = sexp_make_lambda(ctx, tmp=sexp_copy_list(ctx, sexp_cadr(x)));
if (sexp_exceptionp(res)) sexp_return(res, res); if (sexp_exceptionp(res)) sexp_return(res, res);
@ -870,14 +928,23 @@ static sexp analyze_if (sexp ctx, sexp x, int depth) {
sexp_gc_var3(test, pass, fail); sexp_gc_var3(test, pass, fail);
sexp_gc_preserve3(ctx, test, pass, fail); sexp_gc_preserve3(ctx, test, pass, fail);
if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x)))) { if (! (sexp_pairp(sexp_cdr(x)) && sexp_pairp(sexp_cddr(x)))) {
res = sexp_compile_error(ctx, "bad if syntax", x); res = sexp_compile_error(ctx, "not enough args to if", x);
} else if (sexp_pairp(sexp_cdddr(x)) && sexp_cdr(sexp_cdddr(x)) != SEXP_NULL) {
res = sexp_compile_error(ctx, "too many args to if", x);
} else { } else {
test = analyze(ctx, sexp_cadr(x), depth, 0); test = analyze(ctx, sexp_cadr(x), depth, 0);
if (sexp_exceptionp(test)) {
res = test;
} else {
pass = analyze(ctx, sexp_caddr(x), depth, 0); pass = analyze(ctx, sexp_caddr(x), depth, 0);
if (sexp_exceptionp(pass)) {
res = pass;
} else {
fail_expr = sexp_pairp(sexp_cdddr(x)) ? sexp_cadddr(x) : SEXP_VOID; fail_expr = sexp_pairp(sexp_cdddr(x)) ? sexp_cadddr(x) : SEXP_VOID;
fail = analyze(ctx, fail_expr, depth, 0); fail = analyze(ctx, fail_expr, depth, 0);
res = (sexp_exceptionp(test) ? test : sexp_exceptionp(pass) ? pass : res = sexp_exceptionp(fail) ? fail : sexp_make_cnd(ctx, test, pass, fail);
sexp_exceptionp(fail) ? fail : sexp_make_cnd(ctx, test, pass, fail)); }
}
if (sexp_cndp(res)) sexp_cnd_source(res) = sexp_pair_source(x); if (sexp_cndp(res)) sexp_cnd_source(res) = sexp_pair_source(x);
} }
sexp_gc_release3(ctx); sexp_gc_release3(ctx);
@ -995,7 +1062,7 @@ static sexp analyze_let_syntax_aux (sexp ctx, sexp x, int recp, int depth) {
sexp_env_syntactic_p(env) = 1; sexp_env_syntactic_p(env) = 1;
sexp_env_parent(env) = sexp_context_env(ctx); sexp_env_parent(env) = sexp_context_env(ctx);
sexp_env_bindings(env) = SEXP_NULL; sexp_env_bindings(env) = SEXP_NULL;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_STABLE_ABI || SEXP_USE_RENAME_BINDINGS
sexp_env_renames(env) = SEXP_NULL; sexp_env_renames(env) = SEXP_NULL;
#endif #endif
ctx2 = sexp_make_child_context(ctx, sexp_context_lambda(ctx)); ctx2 = sexp_make_child_context(ctx, sexp_context_lambda(ctx));
@ -1035,8 +1102,13 @@ static sexp analyze (sexp ctx, sexp object, int depth, int defok) {
} else if (sexp_idp(sexp_car(x))) { } else if (sexp_idp(sexp_car(x))) {
if (! cell) { if (! cell) {
res = analyze_app(ctx, x, depth); res = analyze_app(ctx, x, depth);
if (sexp_exceptionp(res)) if (sexp_exceptionp(res)) {
sexp_warn(ctx, "exception inside undefined operator: ", sexp_car(x)); sexp_warn(ctx, "exception inside undefined operator: ", sexp_car(x));
/* the common case of no imports */
if (!sexp_env_parent(sexp_context_env(ctx))) {
sexp_warn(ctx, "did you forget to import a language? e.g. (import (scheme base))", SEXP_UNDEF);
}
}
} else { } else {
op = sexp_cdr(cell); op = sexp_cdr(cell);
if (sexp_corep(op)) { if (sexp_corep(op)) {
@ -1048,7 +1120,12 @@ static sexp analyze (sexp ctx, sexp object, int depth, int defok) {
: sexp_compile_error(ctx, "unexpected define", x); : sexp_compile_error(ctx, "unexpected define", x);
break; break;
case SEXP_CORE_SET: case SEXP_CORE_SET:
res = analyze_set(ctx, x, depth); break; x = analyze_set(ctx, x, depth);
if (!sexp_exceptionp(x) && !sexp_setp(x))
goto loop;
else
res = x;
break;
case SEXP_CORE_LAMBDA: case SEXP_CORE_LAMBDA:
res = analyze_lambda(ctx, x, depth); break; res = analyze_lambda(ctx, x, depth); break;
case SEXP_CORE_IF: case SEXP_CORE_IF:
@ -1079,14 +1156,7 @@ static sexp analyze (sexp ctx, sexp object, int depth, int defok) {
res = sexp_compile_error(ctx, "unknown core form", op); break; res = sexp_compile_error(ctx, "unknown core form", op); break;
} }
} else if (sexp_macrop(op)) { } else if (sexp_macrop(op)) {
tmp = sexp_cons(ctx, sexp_macro_env(op), SEXP_NULL); x = analyze_macro_once(ctx, x, op, depth);
tmp = sexp_cons(ctx, sexp_context_env(ctx), tmp);
tmp = sexp_cons(ctx, x, tmp);
x = sexp_exceptionp(tmp) ? tmp : sexp_make_child_context(ctx, sexp_context_lambda(ctx));
if (!sexp_exceptionp(x) && !sexp_exceptionp(sexp_context_exception(ctx)))
x = sexp_apply(x, sexp_macro_proc(op), tmp);
if (sexp_exceptionp(x) && sexp_not(sexp_exception_source(x)))
sexp_exception_source(x) = sexp_pair_source(sexp_car(tmp));
goto loop; goto loop;
} else if (sexp_opcodep(op)) { } else if (sexp_opcodep(op)) {
res = sexp_length(ctx, sexp_cdr(x)); res = sexp_length(ctx, sexp_cdr(x));
@ -1118,7 +1188,14 @@ static sexp analyze (sexp ctx, sexp object, int depth, int defok) {
sexp_warn(ctx, "invalid operator in application: ", x); sexp_warn(ctx, "invalid operator in application: ", x);
} }
} else if (sexp_idp(x)) { } else if (sexp_idp(x)) {
cell = sexp_env_cell(ctx, sexp_context_env(ctx), x, 0);
op = cell ? sexp_cdr(cell) : NULL;
if (op && sexp_macrop(op)) {
x = analyze_macro_once(ctx, x, op, depth);
goto loop;
} else {
res = analyze_var_ref(ctx, x, NULL); res = analyze_var_ref(ctx, x, NULL);
}
} else if (sexp_synclop(x)) { } else if (sexp_synclop(x)) {
tmp = sexp_make_child_context(ctx, sexp_context_lambda(ctx)); tmp = sexp_make_child_context(ctx, sexp_context_lambda(ctx));
if (sexp_pairp(sexp_synclo_free_vars(x))) { if (sexp_pairp(sexp_synclo_free_vars(x))) {
@ -1296,27 +1373,60 @@ sexp sexp_get_port_fileno (sexp ctx, sexp self, sexp_sint_t n, sexp port) {
return sexp_make_fixnum(fd); return sexp_make_fixnum(fd);
return SEXP_FALSE; return SEXP_FALSE;
} }
sexp sexp_stream_portp_op (sexp ctx, sexp self, sexp_sint_t n, sexp port) {
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, port);
return sexp_make_boolean(sexp_stream_portp(port));
}
#endif #endif
#if SEXP_USE_STATIC_LIBS #if SEXP_USE_STATIC_LIBS
#if SEXP_USE_STATIC_LIBS_NO_INCLUDE #if SEXP_USE_STATIC_LIBS_EMPTY
struct sexp_library_entry_t* sexp_static_libraries = NULL;
#elif SEXP_USE_STATIC_LIBS_NO_INCLUDE
extern struct sexp_library_entry_t* sexp_static_libraries; extern struct sexp_library_entry_t* sexp_static_libraries;
#else #else
#include "clibs.c" #include "clibs.c"
#endif #endif
void sexp_add_static_libraries(struct sexp_library_entry_t* libraries)
{
struct sexp_library_entry_t *entry, *table;
if (!sexp_static_libraries) {
sexp_static_libraries = libraries;
return;
}
for (table = sexp_static_libraries; ;
table = (struct sexp_library_entry_t*)entry->init) {
for (entry = &table[0]; entry->name; entry++)
;
if (!entry->init) {
entry->init = (sexp_init_proc)libraries;
return;
}
}
}
static struct sexp_library_entry_t *sexp_find_static_library(const char *file) static struct sexp_library_entry_t *sexp_find_static_library(const char *file)
{ {
size_t base_len; size_t base_len;
struct sexp_library_entry_t *entry; struct sexp_library_entry_t *entry, *table;
if(!sexp_static_libraries)
return NULL;
if (file[0] == '.' && file[1] == '/') if (file[0] == '.' && file[1] == '/')
file += 2; file += 2;
base_len = strlen(file) - strlen(sexp_so_extension); base_len = strlen(file) - strlen(sexp_so_extension);
if (strcmp(file + base_len, sexp_so_extension)) if (strcmp(file + base_len, sexp_so_extension))
return NULL; return NULL;
for (entry = &sexp_static_libraries[0]; entry->name; entry++) for (table = sexp_static_libraries;
table;
table = (struct sexp_library_entry_t*)entry->init) {
for (entry = &table[0]; entry->name; entry++)
if (! strncmp(file, entry->name, base_len)) if (! strncmp(file, entry->name, base_len))
return entry; return entry;
}
return NULL; return NULL;
} }
#else #else
@ -1466,10 +1576,10 @@ sexp sexp_register_optimization (sexp ctx, sexp self, sexp_sint_t n, sexp f, sex
#endif #endif
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
#define maybe_convert_ratio(z) \ #define maybe_convert_ratio(ctx, z) \
else if (sexp_ratiop(z)) d = sexp_ratio_to_double(z); else if (sexp_ratiop(z)) d = sexp_ratio_to_double(ctx, z);
#else #else
#define maybe_convert_ratio(z) #define maybe_convert_ratio(ctx, z)
#endif #endif
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
@ -1487,7 +1597,7 @@ sexp sexp_register_optimization (sexp ctx, sexp self, sexp_sint_t n, sexp f, sex
d = sexp_flonum_value(z); \ d = sexp_flonum_value(z); \
else if (sexp_fixnump(z)) \ else if (sexp_fixnump(z)) \
d = (double)sexp_unbox_fixnum(z); \ d = (double)sexp_unbox_fixnum(z); \
maybe_convert_ratio(z) \ maybe_convert_ratio(ctx, z) \
maybe_convert_bignum(z) \ maybe_convert_bignum(z) \
maybe_convert_complex(z, f) \ maybe_convert_complex(z, f) \
else \ else \
@ -1503,7 +1613,7 @@ sexp sexp_register_optimization (sexp ctx, sexp self, sexp_sint_t n, sexp f, sex
d = sexp_flonum_value(z); \ d = sexp_flonum_value(z); \
else if (sexp_fixnump(z)) \ else if (sexp_fixnump(z)) \
d = (double)sexp_unbox_fixnum(z); \ d = (double)sexp_unbox_fixnum(z); \
maybe_convert_ratio(z) \ maybe_convert_ratio(ctx, z) \
maybe_convert_bignum(z) \ maybe_convert_bignum(z) \
maybe_convert_complex(z, f) \ maybe_convert_complex(z, f) \
else \ else \
@ -1566,7 +1676,7 @@ sexp sexp_log (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
d = sexp_flonum_value(z); d = sexp_flonum_value(z);
else if (sexp_fixnump(z)) else if (sexp_fixnump(z))
d = (double)sexp_unbox_fixnum(z); d = (double)sexp_unbox_fixnum(z);
maybe_convert_ratio(z) maybe_convert_ratio(ctx, z)
maybe_convert_bignum(z) maybe_convert_bignum(z)
else else
return sexp_type_exception(ctx, self, SEXP_NUMBER, z); return sexp_type_exception(ctx, self, SEXP_NUMBER, z);
@ -1592,8 +1702,8 @@ sexp sexp_inexact_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
if (sexp_flonump(z)) if (sexp_flonump(z))
d = sexp_flonum_value(z); d = sexp_flonum_value(z);
else if (sexp_fixnump(z)) else if (sexp_fixnump(z))
d = (double)sexp_unbox_fixnum(z); d = (double)sexp_unbox_fixnum(z); /* may be larger or smaller than z */
maybe_convert_ratio(z) /* XXXX add ratio sqrt */ maybe_convert_ratio(ctx, z) /* TODO: add ratio sqrt */
maybe_convert_complex(z, sexp_complex_sqrt) maybe_convert_complex(z, sexp_complex_sqrt)
else else
return sexp_type_exception(ctx, self, SEXP_NUMBER, z); return sexp_type_exception(ctx, self, SEXP_NUMBER, z);
@ -1633,6 +1743,11 @@ sexp sexp_exact_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
if (!sexp_exceptionp(res)) { if (!sexp_exceptionp(res)) {
rem = sexp_mul(ctx, res, res); rem = sexp_mul(ctx, res, res);
rem = sexp_sub(ctx, z, rem); rem = sexp_sub(ctx, z, rem);
if (sexp_negativep(rem)) {
res = sexp_sub(ctx, res, SEXP_ONE);
rem = sexp_mul(ctx, res, res);
rem = sexp_sub(ctx, z, rem);
}
res = sexp_cons(ctx, res, rem); res = sexp_cons(ctx, res, rem);
} }
} }
@ -1642,8 +1757,10 @@ sexp sexp_exact_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
#endif #endif
sexp sexp_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) { sexp sexp_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS || SEXP_USE_RATIOS
sexp_gc_var2(res, rem); sexp_gc_var2(res, rem);
#endif
#if SEXP_USE_BIGNUMS
if (sexp_bignump(z)) { if (sexp_bignump(z)) {
sexp_gc_preserve2(ctx, res, rem); sexp_gc_preserve2(ctx, res, rem);
res = sexp_bignum_sqrt(ctx, z, &rem); res = sexp_bignum_sqrt(ctx, z, &rem);
@ -1653,6 +1770,20 @@ sexp sexp_sqrt (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
sexp_gc_release2(ctx); sexp_gc_release2(ctx);
return res; return res;
} }
#endif
#if SEXP_USE_RATIOS
if (sexp_ratiop(z)) {
sexp_gc_preserve2(ctx, res, rem);
res = sexp_sqrt(ctx, self, n, sexp_ratio_numerator(z));
rem = sexp_sqrt(ctx, self, n, sexp_ratio_denominator(z));
if (sexp_exactp(res) && sexp_exactp(rem)) {
res = sexp_make_ratio(ctx, res, rem);
} else {
res = sexp_inexact_sqrt(ctx, self, n, z);
}
sexp_gc_release2(ctx);
return res;
}
#endif #endif
return sexp_inexact_sqrt(ctx, self, n, z); return sexp_inexact_sqrt(ctx, self, n, z);
} }
@ -1710,7 +1841,7 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
if (sexp_fixnump(e)) { if (sexp_fixnump(e)) {
return sexp_generic_expt(ctx, x, sexp_unbox_fixnum(e)); return sexp_generic_expt(ctx, x, sexp_unbox_fixnum(e));
} else { } else {
x1 = sexp_ratio_to_double(x); x1 = sexp_ratio_to_double(ctx, x);
} }
} }
#endif #endif
@ -1722,7 +1853,7 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
e1 = sexp_flonum_value(e); e1 = sexp_flonum_value(e);
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
else if (sexp_ratiop(e)) else if (sexp_ratiop(e))
e1 = sexp_ratio_to_double(e); e1 = sexp_ratio_to_double(ctx, e);
#endif #endif
else else
return sexp_type_exception(ctx, self, SEXP_FIXNUM, e); return sexp_type_exception(ctx, self, SEXP_FIXNUM, e);
@ -1730,7 +1861,7 @@ sexp sexp_expt_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp e) {
if ((f*1000.0 > SEXP_MAX_FIXNUM) || (f*1000.0 < SEXP_MIN_FIXNUM) if ((f*1000.0 > SEXP_MAX_FIXNUM) || (f*1000.0 < SEXP_MIN_FIXNUM)
|| (! sexp_fixnump(x)) || (! sexp_fixnump(e)) || (e1 < 0.0)) { || (! sexp_fixnump(x)) || (! sexp_fixnump(e)) || (e1 < 0.0)) {
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS
if (sexp_fixnump(x) && sexp_fixnump(e) && (e1 >= 0.0)) { if (sexp_fixnump(x) && sexp_fixnump(e)) {
sexp_gc_preserve1(ctx, tmp); sexp_gc_preserve1(ctx, tmp);
tmp = sexp_fixnum_to_bignum(ctx, x); tmp = sexp_fixnum_to_bignum(ctx, x);
res = sexp_bignum_expt(ctx, tmp, e); res = sexp_bignum_expt(ctx, tmp, e);
@ -1784,7 +1915,7 @@ sexp sexp_exact_to_inexact (sexp ctx, sexp self, sexp_sint_t n, sexp i) {
#endif #endif
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
else if (sexp_ratiop(i)) else if (sexp_ratiop(i))
res = sexp_make_flonum(ctx, sexp_ratio_to_double(i)); res = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, i));
#endif #endif
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
else if (sexp_complexp(i)) { else if (sexp_complexp(i)) {
@ -1811,13 +1942,13 @@ sexp sexp_inexact_to_exact (sexp ctx, sexp self, sexp_sint_t n, sexp z) {
res = sexp_xtype_exception(ctx, self, "exact: not a finite number", z); res = sexp_xtype_exception(ctx, self, "exact: not a finite number", z);
} else if (sexp_flonum_value(z) != trunc(sexp_flonum_value(z))) { } else if (sexp_flonum_value(z) != trunc(sexp_flonum_value(z))) {
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
res = sexp_double_to_ratio(ctx, sexp_flonum_value(z)); res = sexp_double_to_ratio_2(ctx, sexp_flonum_value(z));
#else #else
res = sexp_xtype_exception(ctx, self, "exact: not an integer", z); res = sexp_xtype_exception(ctx, self, "exact: not an integer", z);
#endif #endif
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS
} else if ((sexp_flonum_value(z) > SEXP_MAX_FIXNUM) } else if ((sexp_flonum_value(z) > (double)SEXP_MAX_FIXNUM)
|| sexp_flonum_value(z) < SEXP_MIN_FIXNUM) { || sexp_flonum_value(z) < (double)SEXP_MIN_FIXNUM) {
res = sexp_double_to_bignum(ctx, sexp_flonum_value(z)); res = sexp_double_to_bignum(ctx, sexp_flonum_value(z));
#endif #endif
} else { } else {
@ -1916,7 +2047,7 @@ void sexp_string_utf8_set (sexp ctx, sexp str, sexp index, sexp ch) {
p = (unsigned char*)sexp_string_data(str) + i; p = (unsigned char*)sexp_string_data(str) + i;
old_len = sexp_utf8_initial_byte_count(*p); old_len = sexp_utf8_initial_byte_count(*p);
new_len = sexp_utf8_char_byte_count(c); new_len = sexp_utf8_char_byte_count(c);
if (old_len != new_len) { /* resize bytes if needed */ if (sexp_copy_on_writep(str) || old_len != new_len) { /* resize bytes if needed */
len = sexp_string_size(str)+(new_len-old_len); len = sexp_string_size(str)+(new_len-old_len);
b = sexp_make_bytes(ctx, sexp_make_fixnum(len), SEXP_VOID); b = sexp_make_bytes(ctx, sexp_make_fixnum(len), SEXP_VOID);
if (! sexp_exceptionp(b)) { if (! sexp_exceptionp(b)) {
@ -1927,8 +2058,17 @@ void sexp_string_utf8_set (sexp ctx, sexp str, sexp index, sexp ch) {
p = q + i; p = q + i;
} }
sexp_string_size(str) += new_len - old_len; sexp_string_size(str) += new_len - old_len;
sexp_copy_on_writep(str) = 0;
} }
sexp_utf8_encode_char(p, new_len, c); sexp_utf8_encode_char(p, new_len, c);
if (old_len != new_len) {
#if SEXP_USE_STRING_INDEX_TABLE
sexp_update_string_index_lookup(ctx, str);
#elif SEXP_USE_STRING_REF_CACHE
sexp_cached_char_idx(str) = 0;
sexp_cached_cursor(str) = sexp_make_string_cursor(0);
#endif
}
} }
sexp sexp_string_utf8_index_set (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp i, sexp ch) { sexp sexp_string_utf8_index_set (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp i, sexp ch) {
@ -1936,6 +2076,8 @@ sexp sexp_string_utf8_index_set (sexp ctx, sexp self, sexp_sint_t n, sexp str, s
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str); sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, i); sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, i);
sexp_assert_type(ctx, sexp_charp, SEXP_CHAR, ch); sexp_assert_type(ctx, sexp_charp, SEXP_CHAR, ch);
if (sexp_immutablep(str))
return sexp_xtype_exception(ctx, self, "string-set!: immutable string", str);
off = sexp_string_index_to_cursor(ctx, self, n, str, i); off = sexp_string_index_to_cursor(ctx, self, n, str, i);
if (sexp_exceptionp(off)) return off; if (sexp_exceptionp(off)) return off;
if (sexp_unbox_string_cursor(off) >= (sexp_sint_t)sexp_string_size(str)) if (sexp_unbox_string_cursor(off) >= (sexp_sint_t)sexp_string_size(str))
@ -2160,7 +2302,7 @@ sexp sexp_make_env_op (sexp ctx, sexp self, sexp_sint_t n) {
sexp_env_lambda(e) = NULL; sexp_env_lambda(e) = NULL;
sexp_env_parent(e) = NULL; sexp_env_parent(e) = NULL;
sexp_env_bindings(e) = SEXP_NULL; sexp_env_bindings(e) = SEXP_NULL;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_STABLE_ABI || SEXP_USE_RENAME_BINDINGS
sexp_env_renames(e) = SEXP_NULL; sexp_env_renames(e) = SEXP_NULL;
#endif #endif
return e; return e;
@ -2180,6 +2322,8 @@ sexp sexp_make_null_env_op (sexp ctx, sexp self, sexp_sint_t n, sexp version) {
return e; return e;
} }
extern struct sexp_opcode_struct* sexp_primitive_opcodes; /* from opcodes.c */
sexp sexp_make_primitive_env_op (sexp ctx, sexp self, sexp_sint_t n, sexp version) { sexp sexp_make_primitive_env_op (sexp ctx, sexp self, sexp_sint_t n, sexp version) {
int i; int i;
sexp_gc_var4(e, op, sym, name); sexp_gc_var4(e, op, sym, name);
@ -2263,6 +2407,10 @@ sexp sexp_load_module_file (sexp ctx, const char *file, sexp env) {
return res; return res;
} }
sexp sexp_current_environment (sexp ctx, sexp self, sexp_sint_t n) {
return sexp_context_env(ctx);
}
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
sexp sexp_current_module_path_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) { sexp sexp_current_module_path_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
if (sexp_pairp(x) && sexp_stringp(sexp_car(x))) { if (sexp_pairp(x) && sexp_stringp(sexp_car(x))) {
@ -2280,9 +2428,6 @@ sexp sexp_load_module_file_op (sexp ctx, sexp self, sexp_sint_t n, sexp file, se
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env); sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
return sexp_load_module_file(ctx, sexp_string_data(file), env); return sexp_load_module_file(ctx, sexp_string_data(file), env);
} }
sexp sexp_current_environment (sexp ctx, sexp self, sexp_sint_t n) {
return sexp_context_env(ctx);
}
sexp sexp_set_current_environment (sexp ctx, sexp self, sexp_sint_t n, sexp env) { sexp sexp_set_current_environment (sexp ctx, sexp self, sexp_sint_t n, sexp env) {
sexp oldenv; sexp oldenv;
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env); sexp_assert_type(ctx, sexp_envp, SEXP_ENV, env);
@ -2400,9 +2545,9 @@ sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) {
= sexp_env_ref(ctx, e, sym=sexp_intern(ctx, "current-exception-handler", -1), SEXP_FALSE); = sexp_env_ref(ctx, e, sym=sexp_intern(ctx, "current-exception-handler", -1), SEXP_FALSE);
/* load init-7.scm */ /* load init-7.scm */
len = strlen(sexp_init_file); len = strlen(sexp_init_file);
strncpy(init_file, sexp_init_file, len); strncpy(init_file, sexp_init_file, len+1);
init_file[len] = (char)sexp_unbox_fixnum(version) + '0'; init_file[len] = (char)sexp_unbox_fixnum(version) + '0';
strncpy(init_file + len + 1, sexp_init_file_suffix, strlen(sexp_init_file_suffix)); strncpy(init_file + len + 1, sexp_init_file_suffix, strlen(sexp_init_file_suffix)+1);
init_file[len + 1 + strlen(sexp_init_file_suffix)] = 0; init_file[len + 1 + strlen(sexp_init_file_suffix)] = 0;
tmp = sexp_load_module_file(ctx, init_file, e); tmp = sexp_load_module_file(ctx, init_file, e);
sexp_set_parameter(ctx, e, sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL), e); sexp_set_parameter(ctx, e, sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL), e);
@ -2440,10 +2585,19 @@ sexp sexp_make_standard_env_op (sexp ctx, sexp self, sexp_sint_t n, sexp version
sexp_gc_preserve1(ctx, env); sexp_gc_preserve1(ctx, env);
env = sexp_make_primitive_env(ctx, version); env = sexp_make_primitive_env(ctx, version);
if (! sexp_exceptionp(env)) env = sexp_load_standard_env(ctx, env, SEXP_SEVEN); if (! sexp_exceptionp(env)) env = sexp_load_standard_env(ctx, env, SEXP_SEVEN);
if (sexp_envp(env)) sexp_immutablep(env) = 1;
sexp_gc_release1(ctx); sexp_gc_release1(ctx);
return env; return env;
} }
sexp sexp_make_immutable_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
if (sexp_pointerp(x)) {
sexp_immutablep(x) = 1;
return SEXP_TRUE;
}
return SEXP_FALSE;
}
sexp sexp_env_parent_op (sexp ctx, sexp self, sexp_sint_t n, sexp e) { sexp sexp_env_parent_op (sexp ctx, sexp self, sexp_sint_t n, sexp e) {
sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e); sexp_assert_type(ctx, sexp_envp, SEXP_ENV, e);
return sexp_env_parent(e) ? sexp_env_parent(e) : SEXP_FALSE; return sexp_env_parent(e) ? sexp_env_parent(e) : SEXP_FALSE;

3
examples/hello.scm Normal file
View file

@ -0,0 +1,3 @@
(import (scheme base))
(write-string "Hello world!\n")

36
examples/simple-http-client.scm Executable file
View file

@ -0,0 +1,36 @@
#! /usr/bin/env chibi-scheme
; Simple HTTP client
; Retrieves the contents of the URL argument:
; Usage:
; simple-http-client.scm [URL]
;
; Example:
; simple-http-client.scm http://localhost:8000
(import (chibi) (chibi net) (chibi net http) (chibi io))
(if (> (length (command-line)) 1)
(let ((url (car (cdr (command-line)))))
(if (> (string-length url) 0)
(begin
(display (read-string 65536 (http-get url)))
(newline))))
(let ((progname (car (command-line))))
(display "Retrieve the contents of a URL.")
(newline)
(display "Usage:")
(newline)
(newline)
(display progname)
(display " [URL]")
(newline)))

16
examples/simple-http-server.scm Executable file
View file

@ -0,0 +1,16 @@
#! /usr/bin/env chibi-scheme
; Simple HTTP server
; Returns a minimal HTML page with a single number incremented
; every request. Binds to localhost port 8000.
(import (chibi) (chibi net http-server) (chibi net servlet) (chibi sxml))
(let ((count 0))
(run-http-server
8000
(lambda (cfg request next restart)
(set! count (+ 1 count))
(servlet-write request (sxml->xml `(html (body
(p "Count: \n")
(p ,count))))))))

173
gc.c
View file

@ -37,14 +37,52 @@ static sexp_heap sexp_heap_last (sexp_heap h) {
return h; return h;
} }
#if !SEXP_USE_FIXED_CHUNK_SIZE_HEAPS && !SEXP_USE_MALLOC
static size_t sexp_heap_total_size (sexp_heap h) { static size_t sexp_heap_total_size (sexp_heap h) {
size_t total_size = 0; size_t total_size = 0;
for (; h; h=h->next) for (; h; h=h->next)
total_size += h->size; total_size += h->size;
return total_size; return total_size;
} }
#endif
#if ! SEXP_USE_GLOBAL_HEAP #if ! SEXP_USE_GLOBAL_HEAP
#if SEXP_USE_DEBUG_GC
void sexp_debug_heap_stats (sexp_heap heap) {
sexp_free_list ls;
size_t available = 0;
for (ls=heap->free_list; ls; ls=ls->next)
available += ls->size;
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
sexp_debug_printf("free heap: %p (chunk size: %lu): %ld / %ld used (%.2f%%)", heap, heap->chunk_size, heap->size - available, heap->size, 100*(heap->size - available) / (float)heap->size);
#else
sexp_debug_printf("free heap: %p: %ld / %ld used (%.2f%%)", heap, heap->size - available, heap->size, 100*(heap->size - available) / (float)heap->size);
#endif
if (heap->next)
sexp_debug_heap_stats(heap->next);
}
#endif
#if SEXP_USE_TRACK_ALLOC_TIMES
void sexp_debug_alloc_times(sexp ctx) {
double mean = (double) sexp_context_alloc_usecs(ctx) / sexp_context_alloc_count(ctx);
double var = (double) sexp_context_alloc_usecs_sq(ctx) / sexp_context_alloc_count(ctx) - mean*mean;
fprintf(stderr, SEXP_BANNER("alloc: mean: %0.3lfμs var: %0.3lfμs (%ld times)"), mean, var, sexp_context_alloc_count(ctx));
}
#endif
#if SEXP_USE_TRACK_ALLOC_SIZES
void sexp_debug_alloc_sizes(sexp ctx) {
int i;
fprintf(stderr, "alloc size histogram: {");
for (i=0; i<SEXP_ALLOC_HISTOGRAM_BUCKETS; ++i) {
if ((i+1)*sexp_heap_align(1)<100 || sexp_context_alloc_histogram(ctx)[i]>0)
fprintf(stderr, " %ld:%ld", (i+1)*sexp_heap_align(1), sexp_context_alloc_histogram(ctx)[i]);
}
fprintf(stderr, "}\n");
}
#endif
void sexp_free_heap (sexp_heap heap) { void sexp_free_heap (sexp_heap heap) {
#if SEXP_USE_MMAP_GC #if SEXP_USE_MMAP_GC
munmap(heap, sexp_heap_pad_size(heap->size)); munmap(heap, sexp_heap_pad_size(heap->size));
@ -99,7 +137,7 @@ SEXP_API sexp_uint_t sexp_allocated_bytes (sexp ctx, sexp x) {
res = sexp_type_size_of_object(t, x) + SEXP_GC_PAD; res = sexp_type_size_of_object(t, x) + SEXP_GC_PAD;
#if SEXP_USE_DEBUG_GC #if SEXP_USE_DEBUG_GC
if (res == 0) { if (res == 0) {
fprintf(stderr, SEXP_BANNER("%p zero-size object: %p"), ctx, x); fprintf(stderr, SEXP_BANNER("%p zero-size object: %p (type tag: %d)"), ctx, x, sexp_pointer_tag(x));
return 1; return 1;
} }
#endif #endif
@ -187,7 +225,35 @@ int sexp_valid_object_p (sexp ctx, sexp x) {
#define sexp_gc_pass_ctx(x) #define sexp_gc_pass_ctx(x)
#endif #endif
void sexp_mark_one (sexp_gc_pass_ctx(sexp ctx) sexp* types, sexp x) { static void sexp_mark_stack_push (sexp ctx, sexp *start, sexp *end) {
struct sexp_mark_stack_ptr_t *stack = sexp_context_mark_stack(ctx);
struct sexp_mark_stack_ptr_t **ptr = &sexp_context_mark_stack_ptr(ctx);
struct sexp_mark_stack_ptr_t *old = *ptr;
if (old == NULL) {
*ptr = stack;
} else if (old >= stack && old + 1 < stack + SEXP_MARK_STACK_COUNT) {
(*ptr)++;
} else {
*ptr = malloc(sizeof(**ptr));
}
(*ptr)->start = start;
(*ptr)->end = end;
(*ptr)->prev = old;
}
static void sexp_mark_stack_pop (sexp ctx) {
struct sexp_mark_stack_ptr_t *stack = sexp_context_mark_stack(ctx);
struct sexp_mark_stack_ptr_t *old = sexp_context_mark_stack_ptr(ctx);
sexp_context_mark_stack_ptr(ctx) = old->prev;
if (!(old >= stack && old < stack + SEXP_MARK_STACK_COUNT)) {
free(old);
}
}
static void sexp_mark_one (sexp ctx, sexp* types, sexp x) {
sexp_sint_t len; sexp_sint_t len;
sexp t, *p, *q; sexp t, *p, *q;
struct sexp_gc_var_t *saves; struct sexp_gc_var_t *saves;
@ -197,26 +263,42 @@ void sexp_mark_one (sexp_gc_pass_ctx(sexp ctx) sexp* types, sexp x) {
sexp_markedp(x) = 1; sexp_markedp(x) = 1;
if (sexp_contextp(x)) { if (sexp_contextp(x)) {
for (saves=sexp_context_saves(x); saves; saves=saves->next) for (saves=sexp_context_saves(x); saves; saves=saves->next)
if (saves->var) sexp_mark_one(sexp_gc_pass_ctx(ctx) types, *(saves->var)); if (saves->var) sexp_mark_one(ctx, types, *(saves->var));
} }
t = types[sexp_pointer_tag(x)]; t = types[sexp_pointer_tag(x)];
len = sexp_type_num_slots_of_object(t, x) - 1; len = sexp_type_num_slots_of_object(t, x) - 1;
if (len >= 0) { if (len >= 0) {
p = (sexp*) (((char*)x) + sexp_type_field_base(t)); p = (sexp*) (((char*)x) + sexp_type_field_base(t));
q = p + len; q = p + len;
while (p < q && ! (*q && sexp_pointerp(*q))) while (p < q && (*q && sexp_pointerp(*q) ? sexp_markedp(*q) : 1))
q--; /* skip trailing immediates */ q--; /* skip trailing immediates */
while (p < q && *q == q[-1]) while (p < q && *q == q[-1])
q--; /* skip trailing duplicates */ q--; /* skip trailing duplicates */
while (p < q) if (p < q) {
sexp_mark_one(sexp_gc_pass_ctx(ctx) types, *p++); sexp_mark_stack_push(ctx, p, q);
x = *p; }
x = *q;
goto loop; goto loop;
} }
} }
static void sexp_mark_one_start (sexp ctx, sexp* types, sexp x) {
struct sexp_mark_stack_ptr_t **ptr = &sexp_context_mark_stack_ptr(ctx);
sexp *p, *q;
sexp_mark_one(ctx, types, x);
while (*ptr) {
p = (*ptr)->start;
q = (*ptr)->end;
sexp_mark_stack_pop(ctx);
while (p < q) {
sexp_mark_one(ctx, types, *p++);
}
}
}
void sexp_mark (sexp ctx, sexp x) { void sexp_mark (sexp ctx, sexp x) {
sexp_mark_one(sexp_gc_pass_ctx(ctx) sexp_vector_data(sexp_global(ctx, SEXP_G_TYPES)), x); sexp_mark_one_start(ctx, sexp_vector_data(sexp_global(ctx, SEXP_G_TYPES)), x);
} }
#if SEXP_USE_CONSERVATIVE_GC #if SEXP_USE_CONSERVATIVE_GC
@ -483,11 +565,11 @@ sexp sexp_gc (sexp ctx, size_t *sum_freed) {
sexp_reset_weak_references(ctx); sexp_reset_weak_references(ctx);
finalized = sexp_finalize(ctx); finalized = sexp_finalize(ctx);
res = sexp_sweep(ctx, sum_freed); res = sexp_sweep(ctx, sum_freed);
++sexp_context_gc_count(ctx);
#if SEXP_USE_TIME_GC #if SEXP_USE_TIME_GC
getrusage(RUSAGE_SELF, &end); getrusage(RUSAGE_SELF, &end);
gc_usecs = (end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000 + gc_usecs = (end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000 +
end.ru_utime.tv_usec - start.ru_utime.tv_usec; end.ru_utime.tv_usec - start.ru_utime.tv_usec;
++sexp_context_gc_count(ctx);
sexp_context_gc_usecs(ctx) += gc_usecs; sexp_context_gc_usecs(ctx) += gc_usecs;
sexp_debug_printf("%p (freed: %lu max_freed: %lu finalized: %lu time: %luus)", sexp_debug_printf("%p (freed: %lu max_freed: %lu finalized: %lu time: %luus)",
ctx, (sum_freed ? *sum_freed : 0), sexp_unbox_fixnum(res), ctx, (sum_freed ? *sum_freed : 0), sexp_unbox_fixnum(res),
@ -500,12 +582,13 @@ sexp_heap sexp_make_heap (size_t size, size_t max_size, size_t chunk_size) {
sexp_free_list free, next; sexp_free_list free, next;
sexp_heap h; sexp_heap h;
#if SEXP_USE_MMAP_GC #if SEXP_USE_MMAP_GC
h = mmap(NULL, sexp_heap_pad_size(size), PROT_READ|PROT_WRITE|PROT_EXEC, h = mmap(NULL, sexp_heap_pad_size(size), PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, 0, 0); MAP_ANON|MAP_PRIVATE, -1, 0);
if (h == MAP_FAILED) return NULL;
#else #else
h = sexp_malloc(sexp_heap_pad_size(size)); h = sexp_malloc(sexp_heap_pad_size(size));
#endif
if (! h) return NULL; if (! h) return NULL;
#endif
h->size = size; h->size = size;
h->max_size = max_size; h->max_size = max_size;
h->chunk_size = chunk_size; h->chunk_size = chunk_size;
@ -534,26 +617,38 @@ int sexp_grow_heap (sexp ctx, size_t size, size_t chunk_size) {
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS #if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
for (tmp=sexp_context_heap(ctx); tmp; tmp=tmp->next) for (tmp=sexp_context_heap(ctx); tmp; tmp=tmp->next)
if (tmp->chunk_size == size) { if (tmp->chunk_size == size) {
while (tmp->next && tmp->next->chunk_size == size)
tmp = tmp->next;
h = tmp; h = tmp;
chunk_size = size; chunk_size = size;
break; break;
} }
#endif #endif
cur_size = h->size; cur_size = h->size;
new_size = sexp_heap_align(((cur_size > size) ? cur_size : size) * 2); new_size = (size_t) ceil(SEXP_GROW_HEAP_FACTOR * (double) (sexp_heap_align(((cur_size > size) ? cur_size : size))));
tmp = sexp_make_heap(new_size, h->max_size, chunk_size); tmp = sexp_make_heap(new_size, h->max_size, chunk_size);
if (tmp) {
tmp->next = h->next; tmp->next = h->next;
h->next = tmp; h->next = tmp;
}
return (h->next != NULL); return (h->next != NULL);
} }
void* sexp_try_alloc (sexp ctx, size_t size) { void* sexp_try_alloc (sexp ctx, size_t size) {
sexp_free_list ls1, ls2, ls3; sexp_free_list ls1, ls2, ls3;
sexp_heap h; sexp_heap h;
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
int found_fixed = 0;
#endif
for (h=sexp_context_heap(ctx); h; h=h->next) { for (h=sexp_context_heap(ctx); h; h=h->next) {
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS #if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
if (h->chunk_size && h->chunk_size != size) if (h->chunk_size) {
if (h->chunk_size != size)
continue; continue;
found_fixed = 1;
} else if (found_fixed) { /* don't use a non-fixed heap */
return NULL;
}
#endif #endif
for (ls1=h->free_list, ls2=ls1->next; ls2; ls1=ls2, ls2=ls2->next) { for (ls1=h->free_list, ls2=ls1->next; ls2; ls1=ls2, ls2=ls2->next) {
if (ls2->size >= size) { if (ls2->size >= size) {
@ -580,15 +675,53 @@ void* sexp_try_alloc (sexp ctx, size_t size) {
return NULL; return NULL;
} }
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
int sexp_find_fixed_chunk_heap_usage(sexp ctx, size_t size, size_t* sum_freed, size_t* total_size) {
sexp_heap h;
sexp_free_list ls;
size_t avail=0, total=0;
for (h=sexp_context_heap(ctx); h; h=h->next) {
if (h->chunk_size == size || !h->chunk_size) {
for (; h && (h->chunk_size == size || !h->chunk_size); h=h->next) {
total += h->size;
for (ls=h->free_list; ls; ls=ls->next)
avail += ls->size;
}
*sum_freed = avail;
*total_size = total;
return h && h->chunk_size > 0;
}
}
return 0;
}
#endif
#if ! SEXP_USE_MALLOC
void* sexp_alloc (sexp ctx, size_t size) { void* sexp_alloc (sexp ctx, size_t size) {
void *res; void *res;
size_t max_freed, sum_freed, total_size; size_t max_freed, sum_freed, total_size=0;
sexp_heap h = sexp_context_heap(ctx); sexp_heap h = sexp_context_heap(ctx);
#if SEXP_USE_TRACK_ALLOC_SIZES
size_t size_bucket;
#endif
#if SEXP_USE_TRACK_ALLOC_TIMES
sexp_uint_t alloc_time;
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
size = sexp_heap_align(size) + SEXP_GC_PAD; size = sexp_heap_align(size) + SEXP_GC_PAD;
#if SEXP_USE_TRACK_ALLOC_SIZES
size_bucket = (size - SEXP_GC_PAD) / sexp_heap_align(1) - 1;
++sexp_context_alloc_histogram(ctx)[size_bucket >= SEXP_ALLOC_HISTOGRAM_BUCKETS ? SEXP_ALLOC_HISTOGRAM_BUCKETS-1 : size_bucket];
#endif
res = sexp_try_alloc(ctx, size); res = sexp_try_alloc(ctx, size);
if (! res) { if (! res) {
max_freed = sexp_unbox_fixnum(sexp_gc(ctx, &sum_freed)); max_freed = sexp_unbox_fixnum(sexp_gc(ctx, &sum_freed));
#if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
sexp_find_fixed_chunk_heap_usage(ctx, size, &sum_freed, &total_size);
#else
total_size = sexp_heap_total_size(sexp_context_heap(ctx)); total_size = sexp_heap_total_size(sexp_context_heap(ctx));
#endif
if (((max_freed < size) if (((max_freed < size)
|| ((total_size > sum_freed) || ((total_size > sum_freed)
&& (total_size - sum_freed) > (total_size*SEXP_GROW_HEAP_RATIO))) && (total_size - sum_freed) > (total_size*SEXP_GROW_HEAP_RATIO)))
@ -600,8 +733,16 @@ void* sexp_alloc (sexp ctx, size_t size) {
sexp_debug_printf("ran out of memory allocating %lu bytes => %p", size, res); sexp_debug_printf("ran out of memory allocating %lu bytes => %p", size, res);
} }
} }
#if SEXP_USE_TRACK_ALLOC_TIMES
gettimeofday(&end, NULL);
alloc_time = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
sexp_context_alloc_count(ctx) += 1;
sexp_context_alloc_usecs(ctx) += alloc_time;
sexp_context_alloc_usecs_sq(ctx) += alloc_time*alloc_time;
#endif
return res; return res;
} }
#endif
void sexp_gc_init (void) { void sexp_gc_init (void) {
@ -617,4 +758,4 @@ void sexp_gc_init (void) {
#endif #endif
} }
#endif #endif /* ! SEXP_USE_BOEHM && ! SEXP_USE_MALLOC */

View file

@ -7,7 +7,7 @@
#if SEXP_USE_IMAGE_LOADING #if SEXP_USE_IMAGE_LOADING
#define ERR_STR_SIZE 256 #define ERR_STR_SIZE 256
char gc_heap_err_str[ERR_STR_SIZE]; static char gc_heap_err_str[ERR_STR_SIZE];
static sexp_uint_t sexp_gc_allocated_bytes (sexp ctx, sexp *types, size_t types_cnt, sexp x) { static sexp_uint_t sexp_gc_allocated_bytes (sexp ctx, sexp *types, size_t types_cnt, sexp x) {
@ -55,7 +55,7 @@ sexp sexp_gc_heap_walk(sexp ctx,
return res; } return res; }
size = sexp_gc_allocated_bytes(ctx, t, t_cnt, p); size = sexp_gc_allocated_bytes(ctx, t, t_cnt, p);
if (size == 0) { if (size == 0) {
strcpy(gc_heap_err_str, "Heap element with a zero size detected"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "Heap element with a zero size detected");
goto done; goto done;
} }
} }
@ -68,7 +68,7 @@ sexp sexp_gc_heap_walk(sexp ctx,
} }
res = SEXP_TRUE; res = SEXP_TRUE;
done: done:
if (res != SEXP_TRUE) res = sexp_user_exception(ctx, NULL, gc_heap_err_str, NULL); if (res != SEXP_TRUE) res = sexp_user_exception(ctx, NULL, gc_heap_err_str, SEXP_NULL);
return res; return res;
} }
@ -145,7 +145,7 @@ static sexp sexp_gc_heap_pack_src_to_dst(void* adata, sexp srcp) {
imax = imid - 1; imax = imid - 1;
} }
} }
strcpy(gc_heap_err_str, "Source SEXP not found in src->dst mapping"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "Source SEXP not found in src->dst mapping");
return SEXP_FALSE; return SEXP_FALSE;
} }
@ -233,7 +233,7 @@ done:
} }
static sexp sexp_gc_heap_pack_adjust(sexp dstp, sexp* types, struct sexp_remap_state* state) { static sexp sexp_gc_heap_pack_adjust(sexp dstp, sexp* types, struct sexp_remap_state* state) {
sexp res = NULL; sexp res = SEXP_FALSE;
/* Adjust internal types which contain fields of sexp pointer(s) /* Adjust internal types which contain fields of sexp pointer(s)
within in the heap */ within in the heap */
if ((res = sexp_adjust_fields(dstp, types, sexp_gc_heap_pack_src_to_dst, state)) != SEXP_TRUE) { if ((res = sexp_adjust_fields(dstp, types, sexp_gc_heap_pack_src_to_dst, state)) != SEXP_TRUE) {
@ -260,7 +260,7 @@ static sexp_heap sexp_gc_packed_heap_make(size_t packed_size, size_t free_size)
size_t req_size = packed_size + free_size + sexp_free_chunk_size + 128; size_t req_size = packed_size + free_size + sexp_free_chunk_size + 128;
sexp_heap heap = sexp_make_heap(sexp_heap_align(req_size), 0, 0); sexp_heap heap = sexp_make_heap(sexp_heap_align(req_size), 0, 0);
if (!heap) { if (!heap) {
strcpy(gc_heap_err_str, "Could not allocate memory for heap"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "Could not allocate memory for heap");
return NULL; return NULL;
} }
sexp base = sexp_heap_first_block(heap); sexp base = sexp_heap_first_block(heap);
@ -418,7 +418,7 @@ sexp sexp_save_image (sexp ctx_in, const char* filename) {
done: done:
if (fp) fclose(fp); if (fp) fclose(fp);
if (heap) sexp_free_heap(heap); if (heap) sexp_free_heap(heap);
if (res != SEXP_TRUE) res = sexp_user_exception(ctx_in, NULL, gc_heap_err_str, NULL); if (res != SEXP_TRUE) res = sexp_user_exception(ctx_in, NULL, gc_heap_err_str, SEXP_NULL);
return res; return res;
} }
@ -573,11 +573,11 @@ static sexp load_image_callback_p2 (sexp ctx, sexp dstp, void *user) {
} }
int load_image_header(FILE *fp, struct sexp_image_header_t* header) { static int load_image_header(FILE *fp, struct sexp_image_header_t* header) {
if (!fp || !header) { return 0; } if (!fp || !header) { return 0; }
if (fread(header, sizeof(struct sexp_image_header_t), 1, fp) != 1) { if (fread(header, sizeof(struct sexp_image_header_t), 1, fp) != 1) {
strcpy(gc_heap_err_str, "couldn't read image header"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't read image header");
return 0; return 0;
} }
if (memcmp(header->magic, SEXP_IMAGE_MAGIC, sizeof(header->magic)) != 0) { if (memcmp(header->magic, SEXP_IMAGE_MAGIC, sizeof(header->magic)) != 0) {
@ -609,7 +609,7 @@ sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_
const char *mod_path, *colon, *end; const char *mod_path, *colon, *end;
char path[512]; char path[512];
FILE *fp; FILE *fp;
int i; int i, len;
sexp res = NULL, ctx = NULL, base, *ctx_globals, *ctx_types; sexp res = NULL, ctx = NULL, base, *ctx_globals, *ctx_types;
gc_heap_err_str[0] = 0; gc_heap_err_str[0] = 0;
@ -623,9 +623,10 @@ sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_
for (mod_path=all_paths[i]; *mod_path; mod_path=colon+1) { for (mod_path=all_paths[i]; *mod_path; mod_path=colon+1) {
colon = strchr(mod_path, ':'); colon = strchr(mod_path, ':');
end = colon ? colon : mod_path + strlen(mod_path); end = colon ? colon : mod_path + strlen(mod_path);
strncpy(path, mod_path, end-mod_path); snprintf(path, sizeof(path), "%s", mod_path);
if (end[-1] != '/') path[end-mod_path] = '/'; if (end[-1] != '/') path[end-mod_path] = '/';
strcpy(path + (end-mod_path) + (end[-1] == '/' ? 0 : 1), filename); len = (end-mod_path) + (end[-1] == '/' ? 0 : 1);
snprintf(path + len, sizeof(path) - len, "%s", filename);
fp = fopen(path, "rb"); fp = fopen(path, "rb");
if (fp || !colon) break; if (fp || !colon) break;
} }
@ -635,7 +636,7 @@ sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_
goto done; goto done;
} }
if (offset > 0 && fseek(fp, offset, SEEK_SET) < 0) { if (offset > 0 && fseek(fp, offset, SEEK_SET) < 0) {
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't seek to image offset: %s -> "PRIoff": %s\n", filename, offset, strerror(errno)); snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't seek to image offset: %s -> %"SEXP_PRIdOFF": %s\n", filename, offset, strerror(errno));
goto done; goto done;
} }
@ -707,6 +708,9 @@ sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uin
/****************** Debugging ************************/ /****************** Debugging ************************/
/* you can use (chibi heap-stats) without debug enabled */
#if SEXP_USE_DEBUG_GC
#define SEXP_CORE_TYPES_MAX 255 #define SEXP_CORE_TYPES_MAX 255
struct sexp_stats_entry { struct sexp_stats_entry {
@ -780,5 +784,6 @@ void sexp_gc_heap_stats_print(sexp ctx)
printf(" ========================================\n"); printf(" ========================================\n");
printf(" %6zu %7zu\n", total_count, total_size); printf(" %6zu %7zu\n", total_count, total_size);
} }
#endif
#endif /* SEXP_USE_IMAGE_LOADING */ #endif /* SEXP_USE_IMAGE_LOADING */

View file

@ -1,5 +1,5 @@
/* bignum.h -- header for bignum utilities */ /* bignum.h -- header for bignum utilities */
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */ /* Copyright (c) 2009-2020 Alex Shinn. All rights reserved. */
/* BSD-style license: http://synthcode.com/license.txt */ /* BSD-style license: http://synthcode.com/license.txt */
#ifndef SEXP_BIGNUM_H #ifndef SEXP_BIGNUM_H
@ -7,7 +7,23 @@
#include "chibi/eval.h" #include "chibi/eval.h"
#if (SEXP_64_BIT) && defined(__GNUC__) #if SEXP_USE_CUSTOM_LONG_LONGS
#ifdef PLAN9
#include <ape/stdint.h>
#else
#include <stdint.h>
#endif
typedef struct
{
uint64_t hi;
uint64_t lo;
} sexp_luint_t;
typedef struct
{
int64_t hi;
uint64_t lo;
} sexp_lsint_t;
#elif SEXP_64_BIT
typedef unsigned int uint128_t __attribute__((mode(TI))); typedef unsigned int uint128_t __attribute__((mode(TI)));
typedef int sint128_t __attribute__((mode(TI))); typedef int sint128_t __attribute__((mode(TI)));
typedef uint128_t sexp_luint_t; typedef uint128_t sexp_luint_t;
@ -17,6 +33,364 @@ typedef unsigned long long sexp_luint_t;
typedef long long sexp_lsint_t; typedef long long sexp_lsint_t;
#endif #endif
#if !SEXP_USE_CUSTOM_LONG_LONGS
#define sexp_lsint_fits_sint(x) ((sexp_sint_t)x == x)
#define sexp_luint_fits_uint(x) ((sexp_uint_t)x == x)
#define lsint_from_sint(v) ((sexp_lsint_t)v)
#define luint_from_uint(v) ((sexp_luint_t)v)
#define lsint_to_sint(v) ((sexp_sint_t)v)
#define luint_to_uint(v) ((sexp_uint_t)v)
#define lsint_to_sint_hi(v) ((sexp_sint_t) ((v) >> (8*sizeof(sexp_sint_t))))
#define luint_to_uint_hi(v) ((sexp_uint_t) ((v) >> (8*sizeof(sexp_uint_t))))
#define lsint_negate(v) (-((sexp_lsint_t)v))
#define luint_eq(a, b) (((sexp_luint_t)a)==((sexp_luint_t)b))
#define luint_lt(a, b) (((sexp_luint_t)a)<((sexp_luint_t)b))
#define lsint_lt_0(a) (((sexp_lsint_t)a)<0)
#define luint_shl(a, shift) (((sexp_luint_t)a)<<(shift))
#define luint_shr(a, shift) (((sexp_luint_t)a)>>(shift))
#define luint_add(a, b) (((sexp_luint_t)a)+((sexp_luint_t)b))
#define luint_add_uint(a, b) (((sexp_luint_t)a)+((sexp_uint_t)b))
#define luint_sub(a, b) (((sexp_luint_t)a)-((sexp_luint_t)b))
#define luint_mul_uint(a, b) (((sexp_luint_t)a)*((sexp_uint_t)b))
#define lsint_mul_sint(a, b) (((sexp_lsint_t)a)*((sexp_sint_t)b))
#define luint_div(a, b) (((sexp_luint_t)a)/((sexp_luint_t)b))
#define luint_div_uint(a, b) (((sexp_luint_t)a)/((sexp_luint_t)b))
#define luint_and(a, b) (((sexp_luint_t)a)&((sexp_luint_t)b))
#define luint_is_fixnum(x) (((sexp_luint_t)x)<=SEXP_MAX_FIXNUM)
#define lsint_is_fixnum(x) ((SEXP_MIN_FIXNUM <= ((sexp_lsint_t)x)) && (((sexp_lsint_t)x) <= SEXP_MAX_FIXNUM))
#else
static inline int lsint_lt_0(sexp_lsint_t a) {
return a.hi < 0;
}
static inline int sexp_lsint_fits_sint(sexp_lsint_t x) {
return x.hi == (((int64_t)x.lo)>>63) && ((sexp_sint_t)x.lo == x.lo);
}
static inline int sexp_luint_fits_uint(sexp_luint_t x) {
return x.hi == 0 && ((sexp_uint_t)x.lo == x.lo);
}
static inline sexp_luint_t luint_from_lsint(sexp_lsint_t v) {
sexp_luint_t result;
result.hi = v.hi;
result.lo = v.lo;
return result;
}
static inline sexp_lsint_t lsint_from_luint(sexp_luint_t v) {
sexp_lsint_t result;
result.hi = v.hi;
result.lo = v.lo;
return result;
}
static inline sexp_lsint_t lsint_from_sint(sexp_sint_t v) {
sexp_lsint_t result;
result.hi = v >> 63;
result.lo = v;
return result;
}
static inline sexp_luint_t luint_from_uint(sexp_uint_t v) {
sexp_luint_t result;
result.hi = 0;
result.lo = v;
return result;
}
static inline sexp_sint_t lsint_to_sint(sexp_lsint_t v) {
return v.lo;
}
static inline sexp_uint_t luint_to_uint(sexp_luint_t v) {
return v.lo;
}
static inline sexp_sint_t lsint_to_sint_hi(sexp_lsint_t v) {
#if SEXP_64_BIT
return v.hi;
#else
return v.lo >> 32;
#endif
}
static inline sexp_uint_t luint_to_uint_hi(sexp_luint_t v) {
#if SEXP_64_BIT
return v.hi;
#else
return v.lo >> 32;
#endif
}
static inline sexp_lsint_t lsint_negate(sexp_lsint_t v) {
sexp_luint_t a;
a.hi = ~v.hi;
a.lo = ~v.lo;
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
uint64_t aLoHi = a.lo >> 32;
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
uint64_t aHiHi = a.hi >> 32;
uint64_t carry;
uint64_t sumLoLo = aLoLo + 1;
carry = sumLoLo >> 32;
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
uint64_t sumLoHi = aLoHi + carry;
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
carry = sumLoHi >> 32;
uint64_t sumHiLo = aHiLo + carry;
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
carry = sumHiLo >> 32;
uint64_t sumHiHi = aHiHi + carry;
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
/* carry = sumHiHi >> 32; */
sexp_lsint_t result;
result.hi = (resultHiHi << 32) | resultHiLo;
result.lo = (resultLoHi << 32) | resultLoLo;
return result;
}
static inline int luint_eq(sexp_luint_t a, sexp_luint_t b) {
return (a.hi == b.hi) && (a.lo == b.lo);
}
static inline int luint_lt(sexp_luint_t a, sexp_luint_t b) {
if (a.hi < b.hi)
return 1;
else if (a.hi > b.hi)
return 0;
else
return a.lo < b.lo;
}
static inline sexp_luint_t luint_shl(sexp_luint_t v, size_t shift) {
if (shift == 0)
return v;
sexp_luint_t result;
if (shift >= 64) {
result.hi = v.lo << (shift - 64);
result.lo = 0;
} else {
result.hi = (v.hi << shift) | (v.lo >> (64-shift));
result.lo = v.lo << shift;
}
return result;
}
static inline sexp_luint_t luint_shr(sexp_luint_t v, size_t shift) {
if (shift == 0)
return v;
sexp_luint_t result;
if (shift >= 64) {
result.hi = 0;
result.lo = v.hi >> (shift - 64);
} else {
result.hi = v.hi >> shift;
result.lo = (v.lo >> shift) | (v.hi << (64-shift));
}
return result;
}
static inline sexp_luint_t luint_add(sexp_luint_t a, sexp_luint_t b) {
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
uint64_t aLoHi = a.lo >> 32;
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
uint64_t aHiHi = a.hi >> 32;
uint64_t bLoLo = b.lo & 0xFFFFFFFF;
uint64_t bLoHi = b.lo >> 32;
uint64_t bHiLo = b.hi & 0xFFFFFFFF;
uint64_t bHiHi = b.hi >> 32;
uint64_t carry;
uint64_t sumLoLo = (aLoLo + bLoLo);
carry = sumLoLo >> 32;
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
uint64_t sumLoHi = (aLoHi + bLoHi) + carry;
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
carry = sumLoHi >> 32;
uint64_t sumHiLo = (aHiLo + bHiLo) + carry;
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
carry = sumHiLo >> 32;
uint64_t sumHiHi = (aHiHi + bHiHi) + carry;
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
/* carry = sumHiHi >> 32; */
sexp_luint_t result;
result.hi = (resultHiHi << 32) | resultHiLo;
result.lo = (resultLoHi << 32) | resultLoLo;
return result;
}
static inline sexp_luint_t luint_add_uint(sexp_luint_t a, sexp_uint_t b) {
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
uint64_t aLoHi = a.lo >> 32;
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
uint64_t aHiHi = a.hi >> 32;
uint64_t bLoLo = b & 0xFFFFFFFF;
uint64_t bLoHi = b >> 32;
uint64_t carry;
uint64_t sumLoLo = (aLoLo + bLoLo);
carry = sumLoLo >> 32;
uint64_t resultLoLo = sumLoLo & 0xFFFFFFFF;
uint64_t sumLoHi = (aLoHi + bLoHi) + carry;
uint64_t resultLoHi = sumLoHi & 0xFFFFFFFF;
carry = sumLoHi >> 32;
uint64_t sumHiLo = aHiLo + carry;
uint64_t resultHiLo = sumHiLo & 0xFFFFFFFF;
carry = sumHiLo >> 32;
uint64_t sumHiHi = aHiHi + carry;
uint64_t resultHiHi = sumHiHi & 0xFFFFFFFF;
/* carry = sumHiHi >> 32; */
sexp_luint_t result;
result.hi = (resultHiHi << 32) | resultHiLo;
result.lo = (resultLoHi << 32) | resultLoLo;
return result;
}
static inline sexp_luint_t luint_sub(sexp_luint_t a, sexp_luint_t b) {
sexp_luint_t negB;
negB.hi = ~b.hi;
negB.lo = ~b.lo;
return luint_add(a, luint_add_uint(negB, 1));
}
static inline sexp_luint_t luint_mul_uint(sexp_luint_t a, sexp_uint_t b) {
uint64_t aLoLo = a.lo & 0xFFFFFFFF;
uint64_t aLoHi = a.lo >> 32;
uint64_t aHiLo = a.hi & 0xFFFFFFFF;
uint64_t aHiHi = a.hi >> 32;
uint64_t bLo = b & 0xFFFFFFFF;
uint64_t bHi = b >> 32;
sexp_luint_t resultBLo, resultBHi;
{
sexp_luint_t prodLoLo;
prodLoLo.hi = 0;
prodLoLo.lo = aLoLo * bLo;
sexp_luint_t prodLoHi;
prodLoHi.hi = (aLoHi * bLo) >> 32;
prodLoHi.lo = (aLoHi * bLo) << 32;
sexp_luint_t prodHiLo;
prodHiLo.hi = aHiLo * bLo;
prodHiLo.lo = 0;
sexp_luint_t prodHiHi;
prodHiHi.hi = (aHiHi * bLo) << 32;
prodHiHi.lo = 0;
resultBLo = luint_add(luint_add(luint_add(prodLoLo, prodLoHi), prodHiLo), prodHiHi);
}
{
sexp_luint_t prodLoLo;
prodLoLo.hi = 0;
prodLoLo.lo = aLoLo * bHi;
sexp_luint_t prodLoHi;
prodLoHi.hi = (aLoHi * bHi) >> 32;
prodLoHi.lo = (aLoHi * bHi) << 32;
sexp_luint_t prodHiLo;
prodHiLo.hi = aHiLo * bHi;
prodHiLo.lo = 0;
sexp_luint_t prodHiHi;
prodHiHi.hi = (aHiHi * bHi) << 32;
prodHiHi.lo = 0;
resultBHi = luint_add(luint_add(luint_add(prodLoLo, prodLoHi), prodHiLo), prodHiHi);
}
sexp_luint_t result = luint_add(resultBLo, luint_shl(resultBHi, 32));
return result;
}
static inline sexp_lsint_t lsint_mul_sint(sexp_lsint_t a, sexp_sint_t b) {
if (lsint_lt_0(a)) {
sexp_luint_t minusA = luint_from_lsint(lsint_negate(a));
if (b < 0)
return lsint_from_luint(luint_mul_uint(minusA, (sexp_uint_t)-b));
else
return lsint_negate(lsint_from_luint(luint_mul_uint(minusA, (sexp_uint_t)b)));
} else {
if (b < 0)
return lsint_negate(lsint_from_luint(luint_mul_uint(luint_from_lsint(a), (sexp_uint_t)-b)));
else
return lsint_from_luint(luint_mul_uint(luint_from_lsint(a), (sexp_uint_t)b));
}
}
static inline sexp_luint_t luint_div(sexp_luint_t a, sexp_luint_t b) {
if (luint_lt(a, b))
return luint_from_uint(0);
else if (luint_eq(a, b))
return luint_from_uint(1);
sexp_luint_t quotient = luint_from_uint(0);
sexp_luint_t remainder = luint_from_uint(0);
for (int i = 0; i < 128; i++) {
quotient = luint_shl(quotient, 1);
remainder = luint_shl(remainder, 1);
remainder.lo |= (a.hi >> 63) & 1;
a = luint_shl(a, 1);
if (!(luint_lt(remainder, b))) {
remainder = luint_sub(remainder, b);
quotient.lo |= 1;
}
}
return quotient;
}
static inline sexp_luint_t luint_div_uint(sexp_luint_t a, sexp_uint_t b) {
return luint_div(a, luint_from_uint(b));
}
static inline sexp_luint_t luint_and(sexp_luint_t a, sexp_luint_t b) {
sexp_luint_t result;
result.hi = a.hi & b.hi;
result.lo = a.lo & b.lo;
return result;
}
static inline int luint_is_fixnum(sexp_luint_t x) {
return (x.hi == 0) && (x.lo <= SEXP_MAX_FIXNUM);
}
static inline int lsint_is_fixnum(sexp_lsint_t x) {
if (x.hi > 0)
return 0;
else if (x.hi == 0)
return x.lo <= SEXP_MAX_FIXNUM;
else if (x.hi == -1)
return SEXP_MIN_FIXNUM <= x.lo;
else return 0;
}
#endif
SEXP_API sexp_sint_t sexp_bignum_compare (sexp a, sexp b); SEXP_API sexp_sint_t sexp_bignum_compare (sexp a, sexp b);
SEXP_API sexp sexp_compare (sexp ctx, sexp a, sexp b); SEXP_API sexp sexp_compare (sexp ctx, sexp a, sexp b);
SEXP_API sexp sexp_make_bignum (sexp ctx, sexp_uint_t len); SEXP_API sexp sexp_make_bignum (sexp ctx, sexp_uint_t len);
@ -26,6 +400,7 @@ SEXP_API sexp_uint_t sexp_bignum_hi (sexp a);
SEXP_API sexp sexp_fixnum_to_bignum (sexp ctx, sexp a); SEXP_API sexp sexp_fixnum_to_bignum (sexp ctx, sexp a);
SEXP_API double sexp_bignum_to_double (sexp a); SEXP_API double sexp_bignum_to_double (sexp a);
SEXP_API sexp sexp_double_to_bignum (sexp ctx, double f); SEXP_API sexp sexp_double_to_bignum (sexp ctx, double f);
SEXP_API double sexp_to_double (sexp ctx, sexp x);
SEXP_API sexp sexp_bignum_fxadd (sexp ctx, sexp a, sexp_uint_t b); SEXP_API sexp sexp_bignum_fxadd (sexp ctx, sexp a, sexp_uint_t b);
SEXP_API sexp sexp_bignum_fxsub (sexp ctx, sexp a, sexp_uint_t b); SEXP_API sexp sexp_bignum_fxsub (sexp ctx, sexp a, sexp_uint_t b);
SEXP_API sexp sexp_bignum_fxmul (sexp ctx, sexp d, sexp a, sexp_uint_t b, int offset); SEXP_API sexp sexp_bignum_fxmul (sexp ctx, sexp d, sexp a, sexp_uint_t b, int offset);
@ -44,7 +419,8 @@ SEXP_API sexp sexp_quotient (sexp ctx, sexp a, sexp b);
SEXP_API sexp sexp_remainder (sexp ctx, sexp a, sexp b); SEXP_API sexp sexp_remainder (sexp ctx, sexp a, sexp b);
#if SEXP_USE_RATIOS #if SEXP_USE_RATIOS
SEXP_API sexp sexp_double_to_ratio (sexp ctx, double f); SEXP_API sexp sexp_double_to_ratio (sexp ctx, double f);
SEXP_API double sexp_ratio_to_double (sexp rat); SEXP_API sexp sexp_double_to_ratio_2 (sexp ctx, double f);
SEXP_API double sexp_ratio_to_double (sexp ctx, sexp rat);
SEXP_API sexp sexp_make_ratio (sexp ctx, sexp num, sexp den); SEXP_API sexp sexp_make_ratio (sexp ctx, sexp num, sexp den);
SEXP_API sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in); SEXP_API sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in);
SEXP_API sexp sexp_ratio_round (sexp ctx, sexp a); SEXP_API sexp sexp_ratio_round (sexp ctx, sexp a);

View file

@ -46,8 +46,6 @@ enum sexp_opcode_classes {
SEXP_OPC_NUM_OP_CLASSES SEXP_OPC_NUM_OP_CLASSES
}; };
SEXP_API struct sexp_opcode_struct* sexp_primitive_opcodes;
#if SEXP_USE_DEBUG_VM || SEXP_USE_PROFILE_VM || SEXP_USE_STATIC_LIBS #if SEXP_USE_DEBUG_VM || SEXP_USE_PROFILE_VM || SEXP_USE_STATIC_LIBS
SEXP_API const char** sexp_opcode_names; SEXP_API const char** sexp_opcode_names;
#endif #endif
@ -131,6 +129,7 @@ SEXP_API sexp sexp_make_lit (sexp ctx, sexp value);
SEXP_API sexp sexp_make_opcode (sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp_proc1); SEXP_API sexp sexp_make_opcode (sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp, sexp_proc1);
SEXP_API sexp sexp_make_procedure_op (sexp ctx, sexp self, sexp_sint_t n, sexp flags, sexp num_args, sexp bc, sexp vars); SEXP_API sexp sexp_make_procedure_op (sexp ctx, sexp self, sexp_sint_t n, sexp flags, sexp num_args, sexp bc, sexp vars);
SEXP_API sexp sexp_define_foreign_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data); SEXP_API sexp sexp_define_foreign_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data);
SEXP_API sexp sexp_define_foreign_proc_aux (sexp ctx, sexp env, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data);
SEXP_API sexp sexp_register_optimization(sexp ctx, sexp self, sexp_sint_t n, sexp f, sexp i); SEXP_API sexp sexp_register_optimization(sexp ctx, sexp self, sexp_sint_t n, sexp f, sexp i);
#if SEXP_USE_AUTO_FORCE #if SEXP_USE_AUTO_FORCE
SEXP_API sexp sexp_make_promise (sexp ctx, sexp self, sexp_sint_t n, sexp done, sexp val); SEXP_API sexp sexp_make_promise (sexp ctx, sexp self, sexp_sint_t n, sexp done, sexp val);
@ -196,6 +195,8 @@ SEXP_API sexp sexp_define_foreign_param_aux(sexp ctx, sexp env, const char *name
#define sexp_define_foreign(c,e,s,n,f) sexp_define_foreign_aux(c,e,s,n,0,(const char*)#f,(sexp_proc1)f,NULL) #define sexp_define_foreign(c,e,s,n,f) sexp_define_foreign_aux(c,e,s,n,0,(const char*)#f,(sexp_proc1)f,NULL)
#define sexp_define_foreign_param(c,e,s,n,f,p) sexp_define_foreign_param_aux(c,e,s,n,(const char*)#f,(sexp_proc1)f,p) #define sexp_define_foreign_param(c,e,s,n,f,p) sexp_define_foreign_param_aux(c,e,s,n,(const char*)#f,(sexp_proc1)f,p)
#define sexp_define_foreign_opt(c,e,s,n,f,p) sexp_define_foreign_aux(c,e,s,n,1,(const char*)#f,(sexp_proc1)f,p) #define sexp_define_foreign_opt(c,e,s,n,f,p) sexp_define_foreign_aux(c,e,s,n,1,(const char*)#f,(sexp_proc1)f,p)
#define sexp_define_foreign_proc(c,e,s,n,f) sexp_define_foreign_proc_aux(c,e,s,n,SEXP_PROC_NONE,(const char*)#f,(sexp_proc1)f,NULL)
#define sexp_define_foreign_proc_rest(c,e,s,n,f) sexp_define_foreign_proc_aux(c,e,s,n,SEXP_PROC_VARIADIC,(const char*)#f,(sexp_proc1)f,NULL)
#define sexp_env_key(x) sexp_car(x) #define sexp_env_key(x) sexp_car(x)
#define sexp_env_value(x) sexp_cdr(x) #define sexp_env_value(x) sexp_cdr(x)
@ -239,6 +240,7 @@ SEXP_API sexp sexp_9p_respond (sexp ctx, sexp self, sexp_sint_t n, sexp req, sex
SEXP_API sexp sexp_9p_responderror (sexp ctx, sexp self, sexp_sint_t n, sexp req); SEXP_API sexp sexp_9p_responderror (sexp ctx, sexp self, sexp_sint_t n, sexp req);
#else #else
SEXP_API sexp sexp_get_port_fileno (sexp ctx, sexp self, sexp_sint_t n, sexp port); SEXP_API sexp sexp_get_port_fileno (sexp ctx, sexp self, sexp_sint_t n, sexp port);
SEXP_API sexp sexp_stream_portp_op (sexp ctx, sexp self, sexp_sint_t n, sexp port);
#endif #endif
#if SEXP_USE_SIMPLIFY #if SEXP_USE_SIMPLIFY

View file

@ -1,5 +1,5 @@
/* features.h -- general feature configuration */ /* features.h -- general feature configuration */
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */ /* Copyright (c) 2009-2021 Alex Shinn. All rights reserved. */
/* BSD-style license: http://synthcode.com/license.txt */ /* BSD-style license: http://synthcode.com/license.txt */
/* uncomment this to disable most features */ /* uncomment this to disable most features */
@ -23,16 +23,27 @@
/* sexp_init_library(ctx, env) function provided. */ /* sexp_init_library(ctx, env) function provided. */
/* #define SEXP_USE_DL 0 */ /* #define SEXP_USE_DL 0 */
/* uncomment this to statically compile all C libs */ /* uncomment this to support statically compiled C libs */
/* If set, this will statically include the clibs.c file */ /* Unless SEXP_USE_STATIC_LIBS_EMPTY is set (see below), this */
/* into the standard environment, so that you can have */ /* will statically include the clibs.c file into the standard */
/* access to a predefined set of C libraries without */ /* environment, so that you can have access to a predefined set */
/* needing dynamic loading. The clibs.c file is generated */ /* of C libraries without needing dynamic loading. The clibs.c */
/* automatically by searching the lib directory for */ /* file is generated automatically by searching the lib directory */
/* modules with include-shared, but can be hand-tailored */ /* for modules with include-shared, but can be hand-tailored to */
/* to your needs. */ /* your needs. You can also register your own C libraries using */
/* sexp_add_static_libraries (see below). */
/* #define SEXP_USE_STATIC_LIBS 1 */ /* #define SEXP_USE_STATIC_LIBS 1 */
/* uncomment this to enable user exported C libs */
/* You can register your own C libraries using */
/* sexp_add_static_libraries. Each entry in the supplied table, */
/* is a name/entry point pair. These work as if they were */
/* dynamically loaded libraries, so naming follows the same */
/* conventions. An entry {"foo", init_foo} will register a */
/* library that can be loaded with (load "foo"), or */
/* (include-shared "foo"), both of which will call init_foo. */
/* #define SEXP_USE_STATIC_LIBS_EMPTY 1 */
/* uncomment this to disable detailed source info for debugging */ /* uncomment this to disable detailed source info for debugging */
/* By default Chibi will associate source info with every */ /* By default Chibi will associate source info with every */
/* bytecode offset. By disabling this only lambda-level source */ /* bytecode offset. By disabling this only lambda-level source */
@ -64,6 +75,15 @@
/* if you suspect a bug in the native GC. */ /* if you suspect a bug in the native GC. */
/* #define SEXP_USE_BOEHM 1 */ /* #define SEXP_USE_BOEHM 1 */
/* uncomment this to enable automatic file descriptor unification */
/* File descriptors as returned by C functions are raw integers, */
/* which are convereted to GC'ed first-class objects on the Scheme */
/* side. By default we assume that each fd is new, however if this */
/* option is enabled and an fd is returned which matches an existing */
/* open fd, they are assumed to refer to the same descriptor and */
/* unified. */
/* #define SEXP_USE_UNIFY_FILENOS_BY_NUMBER 1 */
/* uncomment this to disable weak references */ /* uncomment this to disable weak references */
/* #define SEXP_USE_WEAK_REFERENCES 0 */ /* #define SEXP_USE_WEAK_REFERENCES 0 */
@ -168,11 +188,27 @@
/* uncomment this if you don't want 1## style approximate digits */ /* uncomment this if you don't want 1## style approximate digits */
/* #define SEXP_USE_PLACEHOLDER_DIGITS 0 */ /* #define SEXP_USE_PLACEHOLDER_DIGITS 0 */
/* uncomment this to disable a workaround for numeric formatting, */
/* to fix numbers in locales which don't use the '.' decimal sep */
/* #define SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS 0 */
/* uncomment this if you don't need extended math operations */ /* uncomment this if you don't need extended math operations */
/* This includes the trigonometric and expt functions. */ /* This includes the trigonometric and expt functions. */
/* Automatically disabled if you've disabled flonums. */ /* Automatically disabled if you've disabled flonums. */
/* #define SEXP_USE_MATH 0 */ /* #define SEXP_USE_MATH 0 */
/* uncomment this to enable lenient matching of top-level bindings */
/* Historically, to match behavior with some other Schemes and in */
/* hopes of making it easier to use macros and modules, Chibi allowed */
/* top-level bindings with the same underlying symbol name to match */
/* with identifier=?. In particular, there still isn't a good way */
/* to handle the case where auxiliary syntax conflicts with some other */
/* binding without renaming one or the other (though SRFI 206 helps). */
/* However, if people make use of this you can write Chibi programs */
/* which don't work portably in other implementations, which has been */
/* a source of confusion, so the default has reverted to strict R7RS. */
/* #define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 0 */
/* uncomment this to disable warning about references to undefined variables */ /* uncomment this to disable warning about references to undefined variables */
/* This is something of a hack, but can be quite useful. */ /* This is something of a hack, but can be quite useful. */
/* It's very fast and doesn't involve any separate analysis */ /* It's very fast and doesn't involve any separate analysis */
@ -210,12 +246,32 @@
/* Making them immutable allows for packed UTF-8 strings. */ /* Making them immutable allows for packed UTF-8 strings. */
/* #define SEXP_USE_MUTABLE_STRINGS 0 */ /* #define SEXP_USE_MUTABLE_STRINGS 0 */
/* uncomment this to make string cursors just fixnum offsets */ /* uncomment this to enable precomputed index->cursor tables for strings */
/* The default when using UTF-8 is to have a disjoint string */ /* This makes string-ref faster at the expensive of making string */
/* cursor type. This is an immediate type with no loss in */ /* construction (including string-append and I/O) slower. */
/* performance, and prevents confusion mixing indexes and */ /* You can configure with SEXP_STRING_INDEX_TABLE_CHUNK_SIZE below, */
/* cursors. */ /* the default is caching every 64th index (<=12.5% string overhead). */
/* #define SEXP_USE_DISJOINT_STRING_CURSORS 0 */ /* With a minimum of 1 you'd have up to 8x string overhead, and */
/* string-ref would still be slightly slower than string-cursors, */
/* and string-append would be marginally slower as well. */
/* */
/* In practice, the overhead of iterating over a string with */
/* string-ref isn't noticeable until about 10k chars. Times */
/* for iteration using the different approaches: */
/* */
/* impl\len 1000 10000 100000 1000000 */
/* string-ref (utf8) 1 97 9622 x */
/* string-ref (fast) 0 2 19 216 */
/* cursor-ref (srfi 130) 0 4 18 150 */
/* text-ref (srfi 135) 2 27 211 2006 */
/* */
/* #define SEXP_USE_STRING_INDEX_TABLE 1 */
/* uncomment this to cache a string cursor for string-ref calls */
/* The default is not to use a cache. The goal of caching is to */
/* soften the performance impact of repeated O(n) string-ref */
/* operations on the same string. */
/* #define SEXP_USE_STRING_REF_CACHE 1 */
/* uncomment this to disable automatic closing of ports */ /* uncomment this to disable automatic closing of ports */
/* If enabled, the underlying FILE* for file ports will be */ /* If enabled, the underlying FILE* for file ports will be */
@ -245,7 +301,7 @@
/* uncomment this to make the VM adhere to alignment rules */ /* uncomment this to make the VM adhere to alignment rules */
/* This is required on some platforms, e.g. ARM */ /* This is required on some platforms, e.g. ARM */
/* #define SEXP_USE_ALIGNED_BYTECODE */ /* #define SEXP_USE_ALIGNED_BYTECODE 1 */
/************************************************************************/ /************************************************************************/
/* These settings are configurable but only recommended for */ /* These settings are configurable but only recommended for */
@ -271,6 +327,15 @@
#define SEXP_GROW_HEAP_RATIO 0.75 #define SEXP_GROW_HEAP_RATIO 0.75
#endif #endif
/* how much to expand the heap size by */
#ifndef SEXP_GROW_HEAP_FACTOR
#define SEXP_GROW_HEAP_FACTOR 2 /* 1.6180339887498948482 */
#endif
/* size of per-context stack that is used during gc cycles
* increase if you can affort extra unused memory */
#define SEXP_MARK_STACK_COUNT 1024
/* the default number of opcodes to run each thread for */ /* the default number of opcodes to run each thread for */
#ifndef SEXP_DEFAULT_QUANTUM #ifndef SEXP_DEFAULT_QUANTUM
#define SEXP_DEFAULT_QUANTUM 500 #define SEXP_DEFAULT_QUANTUM 500
@ -280,12 +345,21 @@
#define SEXP_MAX_ANALYZE_DEPTH 8192 #define SEXP_MAX_ANALYZE_DEPTH 8192
#endif #endif
/* The size of flexible arrays (empty arrays at the end of a struct */
/* representing the trailing data), when compiled with C++. Technically */
/* 0 is an illegal value here, and the C++ idiom is to use 1, but this */
/* breaks compatibility with C when computing the size of structs, and */
/* in practice all of the major C++ compilers support 0. */
#ifndef SEXP_FLEXIBLE_ARRAY_SIZE
#define SEXP_FLEXIBLE_ARRAY_SIZE 0
#endif
/************************************************************************/ /************************************************************************/
/* DEFAULTS - DO NOT MODIFY ANYTHING BELOW THIS LINE */ /* DEFAULTS - DO NOT MODIFY ANYTHING BELOW THIS LINE */
/************************************************************************/ /************************************************************************/
#ifndef SEXP_64_BIT #ifndef SEXP_64_BIT
#if defined(__amd64) || defined(__x86_64) || defined(_WIN64) || defined(_Wp64) || defined(__LP64__) || defined(__PPC64__) || defined(__mips64__) || defined(__sparc64__) #if defined(__amd64) || defined(__x86_64) || defined(_WIN64) || defined(_Wp64) || defined(__LP64__) || defined(__PPC64__) || defined(__mips64__) || defined(__sparc64__) || defined(__arm64)
#define SEXP_64_BIT 1 #define SEXP_64_BIT 1
#else #else
#define SEXP_64_BIT 0 #define SEXP_64_BIT 0
@ -301,6 +375,51 @@
#endif #endif
#endif #endif
/* Detect specific BSD */
#if SEXP_BSD
#if defined(__APPLE__)
#define SEXP_DARWIN 1
#define SEXP_FREEBSD 0
#define SEXP_NETBSD 0
#define SEXP_DRAGONFLY 0
#define SEXP_OPENBSD 0
#elif defined(__FreeBSD__)
#define SEXP_DARWIN 0
#define SEXP_FREEBSD 1
#define SEXP_NETBSD 0
#define SEXP_DRAGONFLY 0
#define SEXP_OPENBSD 0
#elif defined(__NetBSD__)
#define SEXP_DARWIN 0
#define SEXP_FREEBSD 0
#define SEXP_NETBSD 1
#define SEXP_DRAGONFLY 0
#define SEXP_OPENBSD 0
#elif defined(__DragonFly__)
#define SEXP_DARWIN 0
#define SEXP_FREEBSD 0
#define SEXP_NETBSD 0
#define SEXP_DRAGONFLY 1
#define SEXP_OPENBSD 0
#elif defined(__OpenBSD__)
#define SEXP_DARWIN 0
#define SEXP_FREEBSD 0
#define SEXP_NETBSD 0
#define SEXP_DRAGONFLY 0
#define SEXP_OPENBSD 1
#endif
#endif
/* for bignum support, need a double long to store long*long */
/* gcc supports uint128_t, otherwise we need a custom struct */
#ifndef SEXP_USE_CUSTOM_LONG_LONGS
#if SEXP_64_BIT && !defined(__GNUC__)
#define SEXP_USE_CUSTOM_LONG_LONGS 1
#else
#define SEXP_USE_CUSTOM_LONG_LONGS 0
#endif
#endif
#ifndef SEXP_USE_NO_FEATURES #ifndef SEXP_USE_NO_FEATURES
#define SEXP_USE_NO_FEATURES 0 #define SEXP_USE_NO_FEATURES 0
#endif #endif
@ -309,9 +428,19 @@
#define SEXP_USE_PEDANTIC 0 #define SEXP_USE_PEDANTIC 0
#endif #endif
/* this ensures public structs and enums are unchanged by feature toggles. */
/* should generally be left at 1. */
#ifndef SEXP_USE_STABLE_ABI
#define SEXP_USE_STABLE_ABI 1
#endif
#ifndef SEXP_USE_GREEN_THREADS #ifndef SEXP_USE_GREEN_THREADS
#if defined(_WIN32)
#define SEXP_USE_GREEN_THREADS 0
#else
#define SEXP_USE_GREEN_THREADS ! SEXP_USE_NO_FEATURES #define SEXP_USE_GREEN_THREADS ! SEXP_USE_NO_FEATURES
#endif #endif
#endif
#ifndef SEXP_USE_DEBUG_THREADS #ifndef SEXP_USE_DEBUG_THREADS
#define SEXP_USE_DEBUG_THREADS 0 #define SEXP_USE_DEBUG_THREADS 0
@ -349,13 +478,17 @@
#endif #endif
#endif #endif
#ifndef SEXP_USE_STATIC_LIBS_EMPTY
#define SEXP_USE_STATIC_LIBS_EMPTY 0
#endif
#ifndef SEXP_USE_STATIC_LIBS #ifndef SEXP_USE_STATIC_LIBS
#define SEXP_USE_STATIC_LIBS 0 #define SEXP_USE_STATIC_LIBS SEXP_USE_STATIC_LIBS_EMPTY
#endif #endif
/* don't include clibs.c - include separately or link */ /* don't include clibs.c - include separately or link */
#ifndef SEXP_USE_STATIC_LIBS_NO_INCLUDE #ifndef SEXP_USE_STATIC_LIBS_NO_INCLUDE
#ifdef PLAN9 #if defined(PLAN9) || SEXP_USE_STATIC_LIBS_EMPTY
#define SEXP_USE_STATIC_LIBS_NO_INCLUDE 0 #define SEXP_USE_STATIC_LIBS_NO_INCLUDE 0
#else #else
#define SEXP_USE_STATIC_LIBS_NO_INCLUDE 1 #define SEXP_USE_STATIC_LIBS_NO_INCLUDE 1
@ -374,9 +507,17 @@
#define SEXP_USE_BOEHM 0 #define SEXP_USE_BOEHM 0
#endif #endif
#ifdef SEXP_USE_UNIFY_FILENOS_BY_NUMBER
#define SEXP_USE_UNIFY_FILENOS_BY_NUMBER 0
#endif
#ifndef SEXP_USE_WEAK_REFERENCES #ifndef SEXP_USE_WEAK_REFERENCES
#if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
#define SEXP_USE_WEAK_REFERENCES 1
#else
#define SEXP_USE_WEAK_REFERENCES ! SEXP_USE_NO_FEATURES #define SEXP_USE_WEAK_REFERENCES ! SEXP_USE_NO_FEATURES
#endif #endif
#endif
#ifndef SEXP_USE_FIXED_CHUNK_SIZE_HEAPS #ifndef SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
#define SEXP_USE_FIXED_CHUNK_SIZE_HEAPS 0 #define SEXP_USE_FIXED_CHUNK_SIZE_HEAPS 0
@ -399,7 +540,11 @@
#endif #endif
#ifndef SEXP_USE_TIME_GC #ifndef SEXP_USE_TIME_GC
#define SEXP_USE_TIME_GC SEXP_USE_DEBUG_GC > 0 #if SEXP_USE_DEBUG_GC > 0 || defined(__linux) || SEXP_BSD
#define SEXP_USE_TIME_GC 1
#else
#define SEXP_USE_TIME_GC 0
#endif
#endif #endif
#ifndef SEXP_USE_SAFE_GC_MARK #ifndef SEXP_USE_SAFE_GC_MARK
@ -422,6 +567,18 @@
#define SEXP_USE_TRACK_ALLOC_BACKTRACE SEXP_USE_TRACK_ALLOC_SOURCE #define SEXP_USE_TRACK_ALLOC_BACKTRACE SEXP_USE_TRACK_ALLOC_SOURCE
#endif #endif
#ifndef SEXP_USE_TRACK_ALLOC_TIMES
#define SEXP_USE_TRACK_ALLOC_TIMES 0
#endif
#ifndef SEXP_USE_TRACK_ALLOC_SIZES
#define SEXP_USE_TRACK_ALLOC_SIZES 0
#endif
#ifndef SEXP_ALLOC_HISTOGRAM_BUCKETS
#define SEXP_ALLOC_HISTOGRAM_BUCKETS 32
#endif
#ifndef SEXP_BACKTRACE_SIZE #ifndef SEXP_BACKTRACE_SIZE
#define SEXP_BACKTRACE_SIZE 3 #define SEXP_BACKTRACE_SIZE 3
#endif #endif
@ -459,7 +616,7 @@
#endif #endif
#ifndef SEXP_USE_STRICT_TOPLEVEL_BINDINGS #ifndef SEXP_USE_STRICT_TOPLEVEL_BINDINGS
#define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 0 #define SEXP_USE_STRICT_TOPLEVEL_BINDINGS 1
#endif #endif
#if SEXP_USE_STRICT_TOPLEVEL_BINDINGS #if SEXP_USE_STRICT_TOPLEVEL_BINDINGS
@ -533,6 +690,10 @@
#define SEXP_PLACEHOLDER_DIGIT '#' #define SEXP_PLACEHOLDER_DIGIT '#'
#endif #endif
#ifndef SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS
#define SEXP_USE_PATCH_NON_DECIMAL_NUMERIC_FORMATS 1
#endif
#ifndef SEXP_USE_MATH #ifndef SEXP_USE_MATH
#define SEXP_USE_MATH SEXP_USE_FLONUMS && ! SEXP_USE_NO_FEATURES #define SEXP_USE_MATH SEXP_USE_FLONUMS && ! SEXP_USE_NO_FEATURES
#endif #endif
@ -549,15 +710,27 @@
#define SEXP_USE_OBJECT_BRACE_LITERALS (SEXP_USE_TYPE_DEFS && !SEXP_USE_NO_FEATURES) #define SEXP_USE_OBJECT_BRACE_LITERALS (SEXP_USE_TYPE_DEFS && !SEXP_USE_NO_FEATURES)
#endif #endif
/* Dangerous without shared object detection. */
#ifndef SEXP_USE_TYPE_PRINTERS #ifndef SEXP_USE_TYPE_PRINTERS
#define SEXP_USE_TYPE_PRINTERS 0 #define SEXP_USE_TYPE_PRINTERS SEXP_USE_OBJECT_BRACE_LITERALS
#endif
#ifndef SEXP_USE_UNIFORM_VECTOR_LITERALS
#define SEXP_USE_UNIFORM_VECTOR_LITERALS ! SEXP_USE_NO_FEATURES
#endif
#ifndef SEXP_USE_MINI_FLOAT_UNIFORM_VECTORS
#define SEXP_USE_MINI_FLOAT_UNIFORM_VECTORS ! SEXP_USE_NO_FEATURES
#endif #endif
#ifndef SEXP_USE_BYTEVECTOR_LITERALS #ifndef SEXP_USE_BYTEVECTOR_LITERALS
#define SEXP_USE_BYTEVECTOR_LITERALS ! SEXP_USE_NO_FEATURES #define SEXP_USE_BYTEVECTOR_LITERALS SEXP_USE_UNIFORM_VECTOR_LITERALS
#endif #endif
#ifndef SEXP_BYTEVECTOR_HEX_LITERALS
#define SEXP_BYTEVECTOR_HEX_LITERALS SEXP_USE_BYTEVECTOR_LITERALS
#endif
#ifndef SEXP_USE_SELF_PARAMETER #ifndef SEXP_USE_SELF_PARAMETER
#define SEXP_USE_SELF_PARAMETER 1 #define SEXP_USE_SELF_PARAMETER 1
#endif #endif
@ -629,6 +802,18 @@
#define SEXP_USE_PACKED_STRINGS 1 #define SEXP_USE_PACKED_STRINGS 1
#endif #endif
#if SEXP_USE_PACKED_STRINGS
#define SEXP_USE_STRING_INDEX_TABLE 0
#endif
#ifndef SEXP_USE_STRING_INDEX_TABLE
#define SEXP_USE_STRING_INDEX_TABLE 0
#endif
/* for every chunk_size indexes store the precomputed offset */
#ifndef SEXP_STRING_INDEX_TABLE_CHUNK_SIZE
#define SEXP_STRING_INDEX_TABLE_CHUNK_SIZE 64
#endif
#ifndef SEXP_USE_DISJOINT_STRING_CURSORS #ifndef SEXP_USE_DISJOINT_STRING_CURSORS
#define SEXP_USE_DISJOINT_STRING_CURSORS SEXP_USE_UTF8_STRINGS #define SEXP_USE_DISJOINT_STRING_CURSORS SEXP_USE_UTF8_STRINGS
#endif #endif
@ -695,6 +880,10 @@
#define SEXP_MAX_STACK_SIZE SEXP_INIT_STACK_SIZE*1000 #define SEXP_MAX_STACK_SIZE SEXP_INIT_STACK_SIZE*1000
#endif #endif
#ifndef SEXP_MAX_VECTOR_LENGTH
#define SEXP_MAX_VECTOR_LENGTH (SEXP_MAX_FIXNUM >> 1)
#endif
#ifndef SEXP_DEFAULT_EQUAL_DEPTH #ifndef SEXP_DEFAULT_EQUAL_DEPTH
#define SEXP_DEFAULT_EQUAL_DEPTH 10000 #define SEXP_DEFAULT_EQUAL_DEPTH 10000
#endif #endif
@ -703,6 +892,10 @@
#define SEXP_DEFAULT_EQUAL_BOUND 100000000 #define SEXP_DEFAULT_EQUAL_BOUND 100000000
#endif #endif
#ifndef SEXP_DEFAULT_WRITE_BOUND
#define SEXP_DEFAULT_WRITE_BOUND 10000
#endif
#ifndef SEXP_STRIP_SYNCLOS_BOUND #ifndef SEXP_STRIP_SYNCLOS_BOUND
#define SEXP_STRIP_SYNCLOS_BOUND 10000 #define SEXP_STRIP_SYNCLOS_BOUND 10000
#endif #endif
@ -713,7 +906,7 @@
#endif #endif
#ifndef SEXP_USE_IMAGE_LOADING #ifndef SEXP_USE_IMAGE_LOADING
#define SEXP_USE_IMAGE_LOADING SEXP_USE_DL && !SEXP_USE_GLOBAL_HEAP && !SEXP_USE_BOEHM && !SEXP_USE_NO_FEATURES #define SEXP_USE_IMAGE_LOADING SEXP_USE_DL && SEXP_64_BIT && !SEXP_USE_GLOBAL_HEAP && !SEXP_USE_BOEHM && !SEXP_USE_NO_FEATURES
#endif #endif
#ifndef SEXP_USE_UNSAFE_PUSH #ifndef SEXP_USE_UNSAFE_PUSH
@ -810,11 +1003,15 @@
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#ifdef SEXP_STATIC_LIBRARY
#define SEXP_API extern
#else
#ifdef BUILDING_DLL #ifdef BUILDING_DLL
#define SEXP_API __declspec(dllexport) #define SEXP_API __declspec(dllexport)
#else #else
#define SEXP_API __declspec(dllimport) #define SEXP_API __declspec(dllimport)
#endif #endif
#endif
#else #else
#define SEXP_API extern #define SEXP_API extern
#endif #endif

View file

@ -7,6 +7,12 @@
#include "chibi/sexp.h" #include "chibi/sexp.h"
#if SEXP_USE_IMAGE_LOADING
#ifdef __cplusplus
extern "C" {
#endif
/* Iterate the heap associated with the context argument 'ctx', /* Iterate the heap associated with the context argument 'ctx',
calling user provided callbacks for the individual heap elements. calling user provided callbacks for the individual heap elements.
@ -90,10 +96,10 @@ SEXP_API sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t h
*/ */
SEXP_API char* sexp_load_image_err(); SEXP_API char* sexp_load_image_err();
#ifdef __cplusplus
}
#endif
/* Debugging tool. Prints a summary of the heap structure to stdout. #endif /* SEXP_USE_IMAGE_LOADING */
*/
SEXP_API void sexp_gc_heap_stats_print(sexp ctx);
#endif /* ! SEXP_GC_HEAP_H */ #endif /* ! SEXP_GC_HEAP_H */

View file

@ -0,0 +1,6 @@
#define sexp_so_extension "@CMAKE_SHARED_LIBRARY_SUFFIX@"
#define sexp_default_module_path "@default_module_path@"
#define sexp_platform "@platform@"
#define sexp_architecture "@CMAKE_SYSTEM_PROCESSOR@"
#define sexp_version "@CMAKE_PROJECT_VERSION@"
#define sexp_release_name "@release@"

View file

@ -1,5 +1,5 @@
char _huff_tab1[8], _huff_tab2[8], _huff_tab3[2], _huff_tab4[2], extern char _huff_tab1[8], _huff_tab2[8], _huff_tab3[2], _huff_tab4[2],
_huff_tab5[4], _huff_tab6[2], _huff_tab7[4], _huff_tab8[4], _huff_tab5[4], _huff_tab6[2], _huff_tab7[4], _huff_tab8[4],
_huff_tab9[4], _huff_tab10[4], _huff_tab11[4], _huff_tab12[2], _huff_tab9[4], _huff_tab10[4], _huff_tab11[4], _huff_tab12[2],
_huff_tab13[8], _huff_tab14[2], _huff_tab15[8], _huff_tab16[8], _huff_tab13[8], _huff_tab14[2], _huff_tab15[8], _huff_tab16[8],

View file

@ -1,5 +1,5 @@
/* sexp.h -- header for sexp library */ /* sexp.h -- header for sexp library */
/* Copyright (c) 2009-2015 Alex Shinn. All rights reserved. */ /* Copyright (c) 2009-2022 Alex Shinn. All rights reserved. */
/* BSD-style license: http://synthcode.com/license.txt */ /* BSD-style license: http://synthcode.com/license.txt */
#ifndef SEXP_H #ifndef SEXP_H
@ -7,12 +7,13 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#define SEXP_FLEXIBLE_ARRAY [1] #define SEXP_FLEXIBLE_ARRAY [SEXP_FLEXIBLE_ARRAY_SIZE]
#else #else
#define SEXP_FLEXIBLE_ARRAY [] #define SEXP_FLEXIBLE_ARRAY []
#endif #endif
#define SEXP_MODULE_PATH_VAR "CHIBI_MODULE_PATH" #define SEXP_MODULE_PATH_VAR "CHIBI_MODULE_PATH"
#define SEXP_NO_SYSTEM_PATH_VAR "CHIBI_IGNORE_SYSTEM_PATH"
#include "chibi/features.h" #include "chibi/features.h"
#include "chibi/install.h" #include "chibi/install.h"
@ -81,6 +82,12 @@ typedef long long off_t;
#define exit(x) exits(TOSTRING(x)) #define exit(x) exits(TOSTRING(x))
#define fabsl fabs #define fabsl fabs
#define M_LN10 2.30258509299404568402 /* log_e 10 */ #define M_LN10 2.30258509299404568402 /* log_e 10 */
#define FLT_RADIX 2
#define isfinite(x) !(isNaN(x) || isInf(x,0))
typedef u32int uint32_t;
typedef s32int int32_t;
typedef u64int uint64_t;
typedef s64int int64_t;
#else #else
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
@ -162,13 +169,13 @@ enum sexp_types {
SEXP_VECTOR, SEXP_VECTOR,
SEXP_FLONUM, SEXP_FLONUM,
SEXP_BIGNUM, SEXP_BIGNUM,
#if SEXP_USE_RATIOS #if SEXP_USE_STABLE_ABI || SEXP_USE_RATIOS
SEXP_RATIO, SEXP_RATIO,
#endif #endif
#if SEXP_USE_COMPLEX #if SEXP_USE_STABLE_ABI || SEXP_USE_COMPLEX
SEXP_COMPLEX, SEXP_COMPLEX,
#endif #endif
#if SEXP_USE_DISJOINT_STRING_CURSORS #if SEXP_USE_STABLE_ABI || SEXP_USE_DISJOINT_STRING_CURSORS
SEXP_STRING_CURSOR, SEXP_STRING_CURSOR,
#endif #endif
SEXP_IPORT, SEXP_IPORT,
@ -181,7 +188,7 @@ enum sexp_types {
SEXP_ENV, SEXP_ENV,
SEXP_BYTECODE, SEXP_BYTECODE,
SEXP_CORE, SEXP_CORE,
#if SEXP_USE_DL #if SEXP_USE_STABLE_ABI || SEXP_USE_DL
SEXP_DL, SEXP_DL,
#endif #endif
SEXP_OPCODE, SEXP_OPCODE,
@ -195,10 +202,11 @@ enum sexp_types {
SEXP_STACK, SEXP_STACK,
SEXP_CONTEXT, SEXP_CONTEXT,
SEXP_CPOINTER, SEXP_CPOINTER,
#if SEXP_USE_AUTO_FORCE SEXP_UNIFORM_VECTOR,
#if SEXP_USE_STABLE_ABI || SEXP_USE_AUTO_FORCE
SEXP_PROMISE, SEXP_PROMISE,
#endif #endif
#if SEXP_USE_WEAK_REFERENCES #if SEXP_USE_STABLE_ABI || SEXP_USE_WEAK_REFERENCES
SEXP_EPHEMERON, SEXP_EPHEMERON,
#endif #endif
SEXP_NUM_CORE_TYPES SEXP_NUM_CORE_TYPES
@ -209,37 +217,51 @@ enum sexp_types {
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#if defined(_MSC_VER) && SEXP_64_BIT
/* On SEXP_64_BIT, 128bits arithmetic is mandatory */
#error Unsupported configuration
#endif
#if SEXP_64_BIT #if SEXP_64_BIT
typedef unsigned int sexp_tag_t; typedef unsigned int sexp_tag_t;
typedef unsigned long long sexp_uint_t; typedef unsigned long long sexp_uint_t;
typedef long long sexp_sint_t; typedef long long sexp_sint_t;
#define SEXP_PRIdFIXNUM "lld"
#else #else
typedef unsigned short sexp_tag_t; typedef unsigned short sexp_tag_t;
typedef unsigned int sexp_uint_t; typedef unsigned int sexp_uint_t;
typedef int sexp_sint_t; typedef int sexp_sint_t;
#define SEXP_PRIdFIXNUM "d"
#endif #endif
#define sexp_heap_align(n) sexp_align(n, 5) #define sexp_heap_align(n) sexp_align(n, 5)
#define sexp_heap_chunks(n) (sexp_heap_align(n)>>5) #define sexp_heap_chunks(n) (sexp_heap_align(n)>>5)
#elif SEXP_64_BIT #elif SEXP_64_BIT
#if PLAN9
typedef uintptr sexp_tag_t;
typedef uintptr sexp_uint_t;
typedef intptr sexp_sint_t;
#else
typedef unsigned int sexp_tag_t; typedef unsigned int sexp_tag_t;
typedef unsigned long sexp_uint_t; typedef unsigned long sexp_uint_t;
typedef long sexp_sint_t; typedef long sexp_sint_t;
#endif
#define SEXP_PRIdFIXNUM "ld"
#define sexp_heap_align(n) sexp_align(n, 5) #define sexp_heap_align(n) sexp_align(n, 5)
#define sexp_heap_chunks(n) (sexp_heap_align(n)>>5) #define sexp_heap_chunks(n) (sexp_heap_align(n)>>5)
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
typedef unsigned short sexp_tag_t; typedef unsigned short sexp_tag_t;
typedef unsigned int sexp_uint_t; typedef unsigned int sexp_uint_t;
typedef int sexp_sint_t; typedef int sexp_sint_t;
#define SEXP_PRIdFIXNUM "d"
#define sexp_heap_align(n) sexp_align(n, 5) #define sexp_heap_align(n) sexp_align(n, 5)
#define sexp_heap_chunks(n) (sexp_heap_align(n)>>5) #define sexp_heap_chunks(n) (sexp_heap_align(n)>>5)
#elif PLAN9
typedef uintptr sexp_tag_t;
typedef unsigned int sexp_uint_t;
typedef int sexp_sint_t;
#define SEXP_PRIdFIXNUM "d"
#define sexp_heap_align(n) sexp_align(n, 4)
#define sexp_heap_chunks(n) (sexp_heap_align(n)>>4)
#else #else
typedef unsigned short sexp_tag_t; typedef unsigned short sexp_tag_t;
typedef unsigned int sexp_uint_t; typedef unsigned int sexp_uint_t;
typedef int sexp_sint_t; typedef int sexp_sint_t;
#define SEXP_PRIdFIXNUM "d"
#define sexp_heap_align(n) sexp_align(n, 4) #define sexp_heap_align(n) sexp_align(n, 4)
#define sexp_heap_chunks(n) (sexp_heap_align(n)>>4) #define sexp_heap_chunks(n) (sexp_heap_align(n)>>4)
#endif #endif
@ -248,10 +270,15 @@ typedef int sexp_sint_t;
#define SEXP_PROC_NONE ((sexp_uint_t)0) #define SEXP_PROC_NONE ((sexp_uint_t)0)
#define SEXP_PROC_VARIADIC ((sexp_uint_t)1) #define SEXP_PROC_VARIADIC ((sexp_uint_t)1)
#define SEXP_PROC_UNUSED_REST ((sexp_uint_t)2) #define SEXP_PROC_UNUSED_REST ((sexp_uint_t)2)
#define SEXP_PROC_VARIABLE_TRANSFORMER ((sexp_uint_t)4)
#ifdef SEXP_USE_INTTYPES #ifdef SEXP_USE_INTTYPES
# include <inttypes.h> #ifdef PLAN9
#include <ape/stdint.h>
#else
#include <stdint.h>
#endif
# ifdef UINT8_MAX # ifdef UINT8_MAX
# define SEXP_UINT8_DEFINED 1 # define SEXP_UINT8_DEFINED 1
typedef uint8_t sexp_uint8_t; typedef uint8_t sexp_uint8_t;
@ -266,6 +293,13 @@ typedef int32_t sexp_int32_t;
# include <ape/limits.h> # include <ape/limits.h>
# else # else
# include <limits.h> # include <limits.h>
# if SEXP_USE_UNIFORM_VECTOR_LITERALS
# ifdef PLAN9
# include <ape/stdint.h>
# else
# include <stdint.h>
# endif
# endif
# endif # endif
# if UCHAR_MAX == 255 # if UCHAR_MAX == 255
# define SEXP_UINT8_DEFINED 1 # define SEXP_UINT8_DEFINED 1
@ -284,12 +318,12 @@ typedef long sexp_int32_t;
typedef unsigned short sexp_uint32_t; typedef unsigned short sexp_uint32_t;
typedef short sexp_int32_t; typedef short sexp_int32_t;
# endif # endif
#endif #endif /* SEXP_USE_INTTYPES */
#if defined(__APPLE__) || defined(_WIN64) || (defined(__CYGWIN__) && __SIZEOF_POINTER__ == 8) #if defined(__APPLE__) || defined(_WIN64) || (defined(__CYGWIN__) && __SIZEOF_POINTER__ == 8)
#define PRIoff "%lld" #define SEXP_PRIdOFF "lld"
#else #else
#define PRIoff "%ld" #define SEXP_PRIdOFF "ld"
#endif #endif
#if SEXP_USE_LONG_PROCEDURE_ARGS #if SEXP_USE_LONG_PROCEDURE_ARGS
@ -361,12 +395,13 @@ struct sexp_gc_var_t {
struct sexp_gc_var_t *next; struct sexp_gc_var_t *next;
}; };
struct sexp_library_entry_t { /* for static builds */ struct sexp_library_entry_t { /* for static builds and user exported C */
const char *name; const char *name; /* libaries */
sexp_init_proc init; sexp_init_proc init;
}; };
struct sexp_type_struct { struct sexp_type_struct {
sexp name, cpl, slots, getters, setters, id, print, dl, finalize_name;
sexp_tag_t tag; sexp_tag_t tag;
short field_base, field_eq_len_base, field_len_base, field_len_off; short field_base, field_eq_len_base, field_len_base, field_len_off;
unsigned short field_len_scale; unsigned short field_len_scale;
@ -374,14 +409,13 @@ struct sexp_type_struct {
unsigned short size_scale; unsigned short size_scale;
short weak_base, weak_len_base, weak_len_off, weak_len_scale, weak_len_extra; short weak_base, weak_len_base, weak_len_off, weak_len_scale, weak_len_extra;
short depth; short depth;
sexp name, cpl, slots, getters, setters, id, print, dl, finalize_name;
sexp_proc2 finalize; sexp_proc2 finalize;
}; };
struct sexp_opcode_struct { struct sexp_opcode_struct {
unsigned char op_class, code, num_args, flags, inverse;
sexp name, data, data2, proc, ret_type, arg1_type, arg2_type, arg3_type, sexp name, data, data2, proc, ret_type, arg1_type, arg2_type, arg3_type,
argn_type, methods, dl; argn_type, methods, dl;
unsigned char op_class, code, num_args, flags, inverse;
sexp_proc1 func; sexp_proc1 func;
}; };
@ -390,6 +424,17 @@ struct sexp_core_form_struct {
sexp name; sexp name;
}; };
struct sexp_mark_stack_ptr_t {
sexp *start, *end;
struct sexp_mark_stack_ptr_t *prev; /* TODO: remove for allocations on stack */
};
/* Note this must be kept in sync with the _sexp_type_specs type */
/* registry in sexp.c. The structure of a sexp type is: */
/* [ HEADER [[EQ_FIELDS... ] GC_FIELDS...] [WEAK_FIELDS...] [OTHER...] ] */
/* Thus all sexp's must be contiguous and align at the start of the type. */
/* This is used by the gc, equal? and slot-ref (although only the latter */
/* expects the alignment at the start of the type). */
struct sexp_struct { struct sexp_struct {
sexp_tag_t tag; sexp_tag_t tag;
char markedp; char markedp;
@ -397,6 +442,7 @@ struct sexp_struct {
unsigned int freep:1; unsigned int freep:1;
unsigned int brokenp:1; unsigned int brokenp:1;
unsigned int syntacticp:1; unsigned int syntacticp:1;
unsigned int copyonwritep:1;
#if SEXP_USE_TRACK_ALLOC_SOURCE #if SEXP_USE_TRACK_ALLOC_SOURCE
const char* source; const char* source;
void* backtrace[SEXP_BACKTRACE_SIZE]; void* backtrace[SEXP_BACKTRACE_SIZE];
@ -415,47 +461,56 @@ struct sexp_struct {
} pair; } pair;
struct { struct {
sexp_uint_t length; sexp_uint_t length;
sexp data SEXP_FLEXIBLE_ARRAY;
} vector; } vector;
struct { struct {
sexp_uint_t length; sexp_uint_t length;
char data SEXP_FLEXIBLE_ARRAY;
} bytes; } bytes;
struct { struct {
#if SEXP_USE_PACKED_STRINGS
sexp_uint_t length;
char data SEXP_FLEXIBLE_ARRAY;
#else
sexp_uint_t offset, length;
sexp bytes; sexp bytes;
unsigned char element_type;
sexp_sint_t length;
} uvector;
struct {
#if SEXP_USE_PACKED_STRINGS
#if SEXP_USE_STRING_INDEX_TABLE
sexp charlens;
#endif
sexp_uint_t length;
#else
sexp bytes;
#if SEXP_USE_STRING_INDEX_TABLE
sexp charlens;
#elif SEXP_USE_STRING_REF_CACHE
sexp_uint_t cached_char_idx;
sexp cached_cursor;
#endif
sexp_uint_t offset, length;
#endif #endif
} string; } string;
struct { struct {
sexp_uint_t length; sexp_uint_t length;
char data SEXP_FLEXIBLE_ARRAY;
} symbol; } symbol;
struct { struct {
sexp name;
sexp cookie;
sexp fd;
FILE *stream; FILE *stream;
char *buf; char *buf;
char openp, bidirp, binaryp, shutdownp, no_closep, sourcep, char openp, bidirp, binaryp, shutdownp, no_closep, sourcep,
blockedp, fold_casep; blockedp, fold_casep;
sexp_uint_t offset, line, flags; sexp_uint_t offset, line, flags;
size_t size; size_t size;
sexp name;
sexp cookie;
sexp fd;
} port; } port;
struct { struct {
char openp, no_closep; char openp, no_closep;
sexp_sint_t fd, count; sexp_sint_t fd, count;
} fileno; } fileno;
struct { struct {
sexp kind, message, irritants, procedure, source; sexp kind, message, irritants, procedure, source, stack_trace;
} exception; } exception;
struct { struct {
signed char sign; signed char sign;
sexp_uint_t length; sexp_uint_t length;
sexp_uint_t data SEXP_FLEXIBLE_ARRAY;
} bignum; } bignum;
struct { struct {
sexp numerator, denominator; sexp numerator, denominator;
@ -464,33 +519,31 @@ struct sexp_struct {
sexp real, imag; sexp real, imag;
} complex; } complex;
struct { struct {
sexp parent;
sexp_uint_t length; sexp_uint_t length;
void *value; void *value;
sexp parent;
char body SEXP_FLEXIBLE_ARRAY;
} cpointer; } cpointer;
/* runtime types */ /* runtime types */
struct { struct {
sexp parent, lambda, bindings; sexp parent, lambda, bindings;
#if SEXP_USE_RENAME_BINDINGS #if SEXP_USE_STABLE_ABI || SEXP_USE_RENAME_BINDINGS
sexp renames; sexp renames;
#endif #endif
} env; } env;
struct { struct {
sexp_uint_t length, max_depth;
sexp name, literals, source; sexp name, literals, source;
unsigned char data SEXP_FLEXIBLE_ARRAY; sexp_uint_t length, max_depth;
} bytecode; } bytecode;
struct { struct {
char flags;
sexp_proc_num_args_t num_args;
sexp bc, vars; sexp bc, vars;
char flags; /* a boxed fixnum truncated to char */
sexp_proc_num_args_t num_args;
} procedure; } procedure;
struct { struct {
sexp proc, env, source; sexp proc, env, source, aux;
} macro; } macro;
struct { struct {
sexp env, free_vars, expr; sexp env, free_vars, expr, rename;
} synclo; } synclo;
struct { struct {
sexp file; sexp file;
@ -523,34 +576,43 @@ struct sexp_struct {
/* compiler state */ /* compiler state */
struct { struct {
sexp_uint_t length, top; sexp_uint_t length, top;
sexp data SEXP_FLEXIBLE_ARRAY;
} stack; } stack;
struct { struct {
sexp stack, env, parent, child,
globals, dk, params, proc, name, specific, event, result;
#if SEXP_USE_STABLE_ABI || SEXP_USE_DL
sexp dl;
#endif
sexp_heap heap; sexp_heap heap;
struct sexp_mark_stack_ptr_t mark_stack[SEXP_MARK_STACK_COUNT];
struct sexp_mark_stack_ptr_t *mark_stack_ptr;
struct sexp_gc_var_t *saves; struct sexp_gc_var_t *saves;
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
sexp_sint_t refuel; sexp_sint_t refuel;
unsigned char* ip; unsigned char* ip;
struct timeval tval; struct timeval tval;
#endif #endif
char tailp, tracep, timeoutp, waitp, errorp; char tailp, tracep, timeoutp, waitp, errorp, interruptp;
sexp_uint_t last_fp; sexp_uint_t last_fp;
sexp_uint_t gc_count;
#if SEXP_USE_TIME_GC #if SEXP_USE_TIME_GC
sexp_uint_t gc_count, gc_usecs; sexp_uint_t gc_usecs;
#endif #endif
sexp stack, env, parent, child, #if SEXP_USE_TRACK_ALLOC_TIMES
globals, dk, params, proc, name, specific, event, result; sexp_uint_t alloc_count, alloc_usecs;
#if SEXP_USE_DL double alloc_usecs_sq;
sexp dl; #endif
#if SEXP_USE_TRACK_ALLOC_SIZES
sexp_uint_t alloc_histogram[SEXP_ALLOC_HISTOGRAM_BUCKETS];
#endif #endif
} context; } context;
#if SEXP_USE_AUTO_FORCE #if SEXP_USE_STABLE_ABI || SEXP_USE_AUTO_FORCE
struct { struct {
int donep;
sexp value; sexp value;
int donep;
} promise; } promise;
#endif #endif
#if SEXP_USE_WEAK_REFERENCES #if SEXP_USE_STABLE_ABI || SEXP_USE_WEAK_REFERENCES
struct { struct {
sexp key, value; sexp key, value;
} ephemeron; } ephemeron;
@ -571,9 +633,10 @@ struct sexp_struct {
#define SEXP_RAWDOT SEXP_MAKE_IMMEDIATE(7) /* internal use */ #define SEXP_RAWDOT SEXP_MAKE_IMMEDIATE(7) /* internal use */
#define SEXP_STRING_OPORT SEXP_MAKE_IMMEDIATE(8) /* internal use */ #define SEXP_STRING_OPORT SEXP_MAKE_IMMEDIATE(8) /* internal use */
#define SEXP_TRAMPOLINE SEXP_MAKE_IMMEDIATE(9) /* internal use */ #define SEXP_TRAMPOLINE SEXP_MAKE_IMMEDIATE(9) /* internal use */
#define SEXP_ABI_ERROR SEXP_MAKE_IMMEDIATE(10) /* internal use */ #define SEXP_UNCAUGHT SEXP_MAKE_IMMEDIATE(10) /* internal use */
#define SEXP_ABI_ERROR SEXP_MAKE_IMMEDIATE(11) /* internal use */
#if SEXP_USE_OBJECT_BRACE_LITERALS #if SEXP_USE_OBJECT_BRACE_LITERALS
#define SEXP_CLOSE_BRACE SEXP_MAKE_IMMEDIATE(11) /* internal use */ #define SEXP_CLOSE_BRACE SEXP_MAKE_IMMEDIATE(12) /* internal use */
#endif #endif
#if SEXP_USE_LIMITED_MALLOC #if SEXP_USE_LIMITED_MALLOC
@ -711,9 +774,11 @@ void* sexp_alloc(sexp ctx, size_t size);
#define sexp_markedp(x) ((x)->markedp) #define sexp_markedp(x) ((x)->markedp)
#define sexp_flags(x) ((x)->flags) #define sexp_flags(x) ((x)->flags)
#define sexp_immutablep(x) ((x)->immutablep) #define sexp_immutablep(x) ((x)->immutablep)
#define sexp_mutablep(x) (!(x)->immutablep)
#define sexp_freep(x) ((x)->freep) #define sexp_freep(x) ((x)->freep)
#define sexp_brokenp(x) ((x)->brokenp) #define sexp_brokenp(x) ((x)->brokenp)
#define sexp_pointer_magic(x) ((x)->magic) #define sexp_pointer_magic(x) ((x)->magic)
#define sexp_copy_on_writep(x) ((x)->copyonwritep)
#if SEXP_USE_TRACK_ALLOC_SOURCE #if SEXP_USE_TRACK_ALLOC_SOURCE
#define sexp_pointer_source(x) ((x)->source) #define sexp_pointer_source(x) ((x)->source)
@ -728,15 +793,17 @@ void* sexp_alloc(sexp ctx, size_t size);
#define sexp_isa(a, b) (sexp_pointerp(a) && sexp_typep(b) && (sexp_pointer_tag(a) == sexp_type_tag(b))) #define sexp_isa(a, b) (sexp_pointerp(a) && sexp_typep(b) && (sexp_pointer_tag(a) == sexp_type_tag(b)))
#if SEXP_USE_IMMEDIATE_FLONUMS
union sexp_flonum_conv { union sexp_flonum_conv {
float flonum; float flonum;
unsigned int bits; unsigned int bits;
}; };
#if SEXP_USE_IMMEDIATE_FLONUMS
#define sexp_flonump(x) (((sexp_uint_t)(x) & SEXP_EXTENDED_MASK) == SEXP_IFLONUM_TAG) #define sexp_flonump(x) (((sexp_uint_t)(x) & SEXP_EXTENDED_MASK) == SEXP_IFLONUM_TAG)
SEXP_API sexp sexp_flonum_predicate (sexp ctx, sexp x); SEXP_API sexp sexp_flonum_predicate (sexp ctx, sexp x);
#if SEXP_64_BIT #if SEXP_64_BIT
SEXP_API float sexp_flonum_value (sexp x); SEXP_API float sexp_flonum_value (sexp x);
#define sexp_flonum_value_set(f, x) (f = sexp_make_flonum(NULL, x))
#define sexp_flonum_bits(f) ((char*)&f) #define sexp_flonum_bits(f) ((char*)&f)
SEXP_API sexp sexp_make_flonum(sexp ctx, float f); SEXP_API sexp sexp_make_flonum(sexp ctx, float f);
#else #else
@ -746,6 +813,7 @@ SEXP_API sexp sexp_make_flonum(sexp ctx, float f);
#else #else
#define sexp_flonump(x) (sexp_check_tag(x, SEXP_FLONUM)) #define sexp_flonump(x) (sexp_check_tag(x, SEXP_FLONUM))
#define sexp_flonum_value(f) ((f)->value.flonum) #define sexp_flonum_value(f) ((f)->value.flonum)
#define sexp_flonum_value_set(f, x) ((f)->value.flonum = x)
#define sexp_flonum_bits(f) ((f)->value.flonum_bits) #define sexp_flonum_bits(f) ((f)->value.flonum_bits)
SEXP_API sexp sexp_make_flonum(sexp ctx, double f); SEXP_API sexp sexp_make_flonum(sexp ctx, double f);
#endif #endif
@ -800,6 +868,42 @@ SEXP_API sexp sexp_make_flonum(sexp ctx, double f);
#define sexp_promisep(x) (sexp_check_tag(x, SEXP_PROMISE)) #define sexp_promisep(x) (sexp_check_tag(x, SEXP_PROMISE))
#define sexp_ephemeronp(x) (sexp_check_tag(x, SEXP_EPHEMERON)) #define sexp_ephemeronp(x) (sexp_check_tag(x, SEXP_EPHEMERON))
#if SEXP_USE_UNIFORM_VECTOR_LITERALS
#define sexp_uvectorp(x) (sexp_check_tag(x, SEXP_UNIFORM_VECTOR))
#define sexp_u1vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_U1)
#define sexp_u8vectorp(x) (sexp_bytesp(x))
#define sexp_s8vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_S8)
#define sexp_u16vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_U16)
#define sexp_s16vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_S16)
#define sexp_u32vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_U32)
#define sexp_s32vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_S32)
#define sexp_u64vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_U64)
#define sexp_s64vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_S64)
#define sexp_f8vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_F8)
#define sexp_f16vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_F16)
#define sexp_f32vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_F32)
#define sexp_f64vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_F64)
#define sexp_c64vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_C64)
#define sexp_c128vectorp(x) (sexp_uvectorp(x) && sexp_uvector_type(x)==SEXP_C128)
#else
#define sexp_uvectorp(x) (sexp_vectorp(x))
#define sexp_u1vectorp(x) (sexp_vectorp(x))
#define sexp_u8vectorp(x) (sexp_bytesp(x))
#define sexp_s8vectorp(x) (sexp_vectorp(x))
#define sexp_u16vectorp(x) (sexp_vectorp(x))
#define sexp_s16vectorp(x) (sexp_vectorp(x))
#define sexp_u32vectorp(x) (sexp_vectorp(x))
#define sexp_s32vectorp(x) (sexp_vectorp(x))
#define sexp_u64vectorp(x) (sexp_vectorp(x))
#define sexp_s64vectorp(x) (sexp_vectorp(x))
#define sexp_f8vectorp(x) (sexp_vectorp(x))
#define sexp_f16vectorp(x) (sexp_vectorp(x))
#define sexp_f32vectorp(x) (sexp_vectorp(x))
#define sexp_f64vectorp(x) (sexp_vectorp(x))
#define sexp_c64vectorp(x) (sexp_vectorp(x))
#define sexp_c128vectorp(x) (sexp_vectorp(x))
#endif
#define sexp_applicablep(x) (sexp_procedurep(x) || sexp_opcodep(x)) #define sexp_applicablep(x) (sexp_procedurep(x) || sexp_opcodep(x))
#if SEXP_USE_HUFF_SYMS #if SEXP_USE_HUFF_SYMS
@ -891,8 +995,15 @@ SEXP_API int sexp_idp(sexp x);
#endif #endif
#if SEXP_USE_BIGNUMS #if SEXP_USE_BIGNUMS
SEXP_API sexp sexp_make_integer_from_lsint(sexp ctx, sexp_lsint_t x);
SEXP_API sexp sexp_make_unsigned_integer_from_luint(sexp ctx, sexp_luint_t x);
#if SEXP_USE_CUSTOM_LONG_LONGS
SEXP_API sexp sexp_make_integer(sexp ctx, long long x);
SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, unsigned long long x);
#else
SEXP_API sexp sexp_make_integer(sexp ctx, sexp_lsint_t x); SEXP_API sexp sexp_make_integer(sexp ctx, sexp_lsint_t x);
SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x); SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#endif
#define sexp_exact_integerp(x) (sexp_fixnump(x) || sexp_bignump(x)) #define sexp_exact_integerp(x) (sexp_fixnump(x) || sexp_bignump(x))
#else #else
#define sexp_make_integer(ctx, x) sexp_make_fixnum(x) #define sexp_make_integer(ctx, x) sexp_make_fixnum(x)
@ -922,8 +1033,12 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#if SEXP_USE_COMPLEX #if SEXP_USE_COMPLEX
#define sexp_numberp(x) (sexp_realp(x) || sexp_complexp(x)) #define sexp_numberp(x) (sexp_realp(x) || sexp_complexp(x))
#define sexp_real_part(x) (sexp_complexp(x) ? sexp_complex_real(x) : x)
#define sexp_imag_part(x) (sexp_complexp(x) ? sexp_complex_imag(x) : SEXP_ZERO)
#else #else
#define sexp_numberp(x) (sexp_realp(x)) #define sexp_numberp(x) (sexp_realp(x))
#define sexp_real_part(x) (x)
#define sexp_imag_part(x) SEXP_ZERO
#endif #endif
#define sexp_exact_negativep(x) (sexp_fixnump(x) ? (sexp_unbox_fixnum(x) < 0) \ #define sexp_exact_negativep(x) (sexp_fixnump(x) ? (sexp_unbox_fixnum(x) < 0) \
@ -935,7 +1050,10 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_negativep(x) (sexp_exact_negativep(x) || \ #define sexp_negativep(x) (sexp_exact_negativep(x) || \
(sexp_flonump(x) && sexp_flonum_value(x) < 0)) (sexp_flonump(x) && sexp_flonum_value(x) < 0))
#define sexp_positivep(x) (!(sexp_negativep(x))) #define sexp_positivep(x) (!(sexp_negativep(x)))
#define sexp_pedantic_negativep(x) (sexp_exact_negativep(x) || \ #define sexp_pedantic_negativep(x) ( \
sexp_exact_negativep(x) || \
(sexp_ratiop(x) && \
sexp_exact_negativep(sexp_ratio_numerator(x))) || \
(sexp_flonump(x) && \ (sexp_flonump(x) && \
((sexp_flonum_value(x) < 0) || \ ((sexp_flonum_value(x) < 0) || \
(sexp_flonum_value(x) == 0 && \ (sexp_flonum_value(x) == 0 && \
@ -961,19 +1079,39 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_negate_flonum(x) sexp_flonum_value(x) = -(sexp_flonum_value(x)) #define sexp_negate_flonum(x) sexp_flonum_value(x) = -(sexp_flonum_value(x))
#endif #endif
/* TODO: Doesn't support x == SEXP_MIN_FIXNUM. */
#define sexp_negate(x) \ #define sexp_negate(x) \
if (sexp_flonump(x)) \ if (sexp_flonump(x)) \
sexp_negate_flonum(x); \ sexp_negate_flonum(x); \
else \ else \
sexp_negate_exact(x) sexp_negate_exact(x)
#define sexp_negate_maybe_ratio(x) \
if (sexp_ratiop(x)) { \
sexp_negate_exact(sexp_ratio_numerator(x)); \
} else { \
sexp_negate(x); \
}
#if SEXP_USE_FLONUMS || SEXP_USE_BIGNUMS #if SEXP_USE_FLONUMS || SEXP_USE_BIGNUMS
#define sexp_uint_value(x) ((sexp_uint_t)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignump(x) ? sexp_bignum_data(x)[0] : 0))
#define sexp_sint_value(x) ((sexp_sint_t)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignump(x) ? sexp_bignum_sign(x)*sexp_bignum_data(x)[0] : 0)) #if SEXP_64_BIT
#define sexp_bignum_to_sint(x) (sexp_bignum_sign(x)*sexp_bignum_data(x)[0])
#define sexp_bignum_to_uint(x) (sexp_bignum_data(x)[0])
#else #else
SEXP_API long long sexp_bignum_to_sint(sexp x);
SEXP_API unsigned long long sexp_bignum_to_uint(sexp x);
#endif
#define sexp_uint_value(x) ((unsigned long long)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignump(x) ? sexp_bignum_to_uint(x) : 0))
#define sexp_sint_value(x) ((long long)(sexp_fixnump(x) ? sexp_unbox_fixnum(x) : sexp_bignump(x) ? sexp_bignum_to_sint(x) : 0))
#else
#define sexp_uint_value(x) ((sexp_uint_t)sexp_unbox_fixnum(x)) #define sexp_uint_value(x) ((sexp_uint_t)sexp_unbox_fixnum(x))
#define sexp_sint_value(x) ((sexp_sint_t)sexp_unbox_fixnum(x)) #define sexp_sint_value(x) ((sexp_sint_t)sexp_unbox_fixnum(x))
#endif
#endif /* SEXP_USE_FLONUMS || SEXP_USE_BIGNUMS */
#define sexp_shift_epoch(x) ((x)-SEXP_EPOCH_OFFSET) #define sexp_shift_epoch(x) ((x)-SEXP_EPOCH_OFFSET)
#define sexp_unshift_epoch(x) ((x)+SEXP_EPOCH_OFFSET) #define sexp_unshift_epoch(x) ((x)+SEXP_EPOCH_OFFSET)
@ -987,6 +1125,13 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_flonum_eqv(x, y) (sexp_flonum_value(x) == sexp_flonum_value(y)) #define sexp_flonum_eqv(x, y) (sexp_flonum_value(x) == sexp_flonum_value(y))
#endif #endif
#if SEXP_USE_MINI_FLOAT_UNIFORM_VECTORS
SEXP_API double sexp_quarter_to_double(unsigned char q);
SEXP_API unsigned char sexp_double_to_quarter(double f);
SEXP_API double sexp_half_to_double(unsigned short x);
SEXP_API unsigned short sexp_double_to_half(double x);
#endif
/*************************** field accessors **************************/ /*************************** field accessors **************************/
#if SEXP_USE_SAFE_ACCESSORS #if SEXP_USE_SAFE_ACCESSORS
@ -1005,8 +1150,11 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_cpointer_field(x, field) ((x)->value.cpointer.field) #define sexp_cpointer_field(x, field) ((x)->value.cpointer.field)
#endif #endif
#define sexp_flexible_array_field(x, type, field_type) \
((field_type*)((char*)(x)+sexp_sizeof(type)))
#define sexp_vector_length(x) (sexp_field(x, vector, SEXP_VECTOR, length)) #define sexp_vector_length(x) (sexp_field(x, vector, SEXP_VECTOR, length))
#define sexp_vector_data(x) (sexp_field(x, vector, SEXP_VECTOR, data)) #define sexp_vector_data(x) sexp_flexible_array_field(x, vector, sexp)
#if SEXP_USE_SAFE_VECTOR_ACCESSORS #if SEXP_USE_SAFE_VECTOR_ACCESSORS
#define sexp_vector_ref(x,i) (sexp_unbox_fixnum(i)>=0 && sexp_unbox_fixnum(i)<sexp_vector_length(x) ? sexp_vector_data(x)[sexp_unbox_fixnum(i)] : (fprintf(stderr, "vector-ref length out of range %s on line %d: vector %p (length %lu): %ld\n", __FILE__, __LINE__, x, sexp_vector_length(x), sexp_unbox_fixnum(i)), SEXP_VOID)) #define sexp_vector_ref(x,i) (sexp_unbox_fixnum(i)>=0 && sexp_unbox_fixnum(i)<sexp_vector_length(x) ? sexp_vector_data(x)[sexp_unbox_fixnum(i)] : (fprintf(stderr, "vector-ref length out of range %s on line %d: vector %p (length %lu): %ld\n", __FILE__, __LINE__, x, sexp_vector_length(x), sexp_unbox_fixnum(i)), SEXP_VOID))
@ -1020,23 +1168,66 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_procedure_flags(x) (sexp_field(x, procedure, SEXP_PROCEDURE, flags)) #define sexp_procedure_flags(x) (sexp_field(x, procedure, SEXP_PROCEDURE, flags))
#define sexp_procedure_variadic_p(x) (sexp_unbox_fixnum(sexp_procedure_flags(x)) & SEXP_PROC_VARIADIC) #define sexp_procedure_variadic_p(x) (sexp_unbox_fixnum(sexp_procedure_flags(x)) & SEXP_PROC_VARIADIC)
#define sexp_procedure_unused_rest_p(x) (sexp_unbox_fixnum(sexp_procedure_flags(x)) & SEXP_PROC_UNUSED_REST) #define sexp_procedure_unused_rest_p(x) (sexp_unbox_fixnum(sexp_procedure_flags(x)) & SEXP_PROC_UNUSED_REST)
#define sexp_procedure_variable_transformer_p(x) (sexp_unbox_fixnum(sexp_procedure_flags(x)) & SEXP_PROC_VARIABLE_TRANSFORMER)
#define sexp_procedure_code(x) (sexp_field(x, procedure, SEXP_PROCEDURE, bc)) #define sexp_procedure_code(x) (sexp_field(x, procedure, SEXP_PROCEDURE, bc))
#define sexp_procedure_vars(x) (sexp_field(x, procedure, SEXP_PROCEDURE, vars)) #define sexp_procedure_vars(x) (sexp_field(x, procedure, SEXP_PROCEDURE, vars))
#define sexp_procedure_source(x) sexp_bytecode_source(sexp_procedure_code(x)) #define sexp_procedure_source(x) sexp_bytecode_source(sexp_procedure_code(x))
#define sexp_bytes_length(x) (sexp_field(x, bytes, SEXP_BYTES, length)) #define sexp_bytes_length(x) (sexp_field(x, bytes, SEXP_BYTES, length))
#define sexp_bytes_data(x) (sexp_field(x, bytes, SEXP_BYTES, data)) #define sexp_bytes_data(x) sexp_flexible_array_field(x, bytes, char)
#define sexp_bytes_maybe_null_data(x) (sexp_not(x) ? NULL : sexp_bytes_data(x)) #define sexp_bytes_maybe_null_data(x) (sexp_not(x) ? NULL : sexp_bytes_data(x))
static const unsigned char sexp_uvector_sizes[] = {
0, 1, 8, 8, 16, 16, 32, 32, 64, 64, 32, 64, 64, 128, 8, 16};
static const unsigned char sexp_uvector_chars[] = "#ususususuffccff";
enum sexp_uniform_vector_type {
SEXP_NOT_A_UNIFORM_TYPE,
SEXP_U1,
SEXP_S8,
SEXP_U8,
SEXP_S16,
SEXP_U16,
SEXP_S32,
SEXP_U32,
SEXP_S64,
SEXP_U64,
SEXP_F32,
SEXP_F64,
SEXP_C64,
SEXP_C128,
SEXP_F8,
SEXP_F16,
SEXP_END_OF_UNIFORM_TYPES
};
#define sexp_uvector_freep(x) (sexp_freep(x))
#define sexp_uvector_element_size(uvt) (sexp_uvector_sizes[uvt])
#define sexp_uvector_prefix(uvt) (sexp_uvector_chars[uvt])
#define sexp_uvector_length(x) (sexp_field(x, uvector, SEXP_UNIFORM_VECTOR, length))
#define sexp_uvector_type(x) (sexp_field(x, uvector, SEXP_UNIFORM_VECTOR, element_type))
#define sexp_uvector_data(x) sexp_bytes_data(sexp_uvector_bytes(x))
#define sexp_uvector_maybe_null_data(x) (sexp_not(x) ? NULL : sexp_uvector_data(x))
#define sexp_uvector_bytes(x) (sexp_field(x, uvector, SEXP_UNIFORM_VECTOR, bytes))
#define sexp_bit_ref(u1v, i) (((sexp_uvector_data(u1v)[i/8])>>(i%8))&1)
#define sexp_bit_set(u1v, i, x) (x ? (sexp_uvector_data(u1v)[i/8]|=(1<<(i%8))) : (sexp_uvector_data(u1v)[i/8]&=~(1<<(i%8))))
#define sexp_string_size(x) (sexp_field(x, string, SEXP_STRING, length)) #define sexp_string_size(x) (sexp_field(x, string, SEXP_STRING, length))
#define sexp_string_charlens(x) (sexp_field(x, string, SEXP_STRING, charlens))
#if SEXP_USE_PACKED_STRINGS #if SEXP_USE_PACKED_STRINGS
#define sexp_string_data(x) (sexp_field(x, string, SEXP_STRING, data)) #define sexp_string_data(x) sexp_flexible_array_field(x, string, char)
#define sexp_string_bytes(x) (x) #define sexp_string_bytes(x) (x)
#else #else
#define sexp_string_bytes(x) (sexp_field(x, string, SEXP_STRING, bytes)) #define sexp_string_bytes(x) (sexp_field(x, string, SEXP_STRING, bytes))
#define sexp_string_offset(x) (sexp_field(x, string, SEXP_STRING, offset)) #define sexp_string_offset(x) (sexp_field(x, string, SEXP_STRING, offset))
#define sexp_string_data(x) (sexp_bytes_data(sexp_string_bytes(x))+sexp_string_offset(x)) #define sexp_string_data(x) (sexp_bytes_data(sexp_string_bytes(x))+sexp_string_offset(x))
#endif #endif
#if SEXP_USE_STRING_REF_CACHE
#define sexp_cached_char_idx(x) (sexp_field(x, string, SEXP_STRING, cached_char_idx))
#define sexp_cached_cursor(x) (sexp_field(x, string, SEXP_STRING, cached_cursor))
#endif
#define sexp_string_maybe_null_data(x) (sexp_not(x) ? NULL : sexp_string_data(x)) #define sexp_string_maybe_null_data(x) (sexp_not(x) ? NULL : sexp_string_data(x))
#if SEXP_USE_PACKED_STRINGS #if SEXP_USE_PACKED_STRINGS
@ -1048,7 +1239,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_bytes_ref(x, i) (sexp_make_fixnum((unsigned char)sexp_bytes_data(x)[sexp_unbox_fixnum(i)])) #define sexp_bytes_ref(x, i) (sexp_make_fixnum((unsigned char)sexp_bytes_data(x)[sexp_unbox_fixnum(i)]))
#define sexp_bytes_set(x, i, v) (sexp_bytes_data(x)[sexp_unbox_fixnum(i)] = sexp_unbox_fixnum(v)) #define sexp_bytes_set(x, i, v) (sexp_bytes_data(x)[sexp_unbox_fixnum(i)] = sexp_unbox_fixnum(v))
#define sexp_lsymbol_data(x) (sexp_field(x, symbol, SEXP_SYMBOL, data)) #define sexp_lsymbol_data(x) sexp_flexible_array_field(x, symbol, char)
#define sexp_lsymbol_length(x) (sexp_field(x, symbol, SEXP_SYMBOL, length)) #define sexp_lsymbol_length(x) (sexp_field(x, symbol, SEXP_SYMBOL, length))
#define sexp_port_stream(p) (sexp_pred_field(p, port, sexp_portp, stream)) #define sexp_port_stream(p) (sexp_pred_field(p, port, sexp_portp, stream))
@ -1086,6 +1277,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_exception_irritants(x) (sexp_field(x, exception, SEXP_EXCEPTION, irritants)) #define sexp_exception_irritants(x) (sexp_field(x, exception, SEXP_EXCEPTION, irritants))
#define sexp_exception_procedure(x) (sexp_field(x, exception, SEXP_EXCEPTION, procedure)) #define sexp_exception_procedure(x) (sexp_field(x, exception, SEXP_EXCEPTION, procedure))
#define sexp_exception_source(x) (sexp_field(x, exception, SEXP_EXCEPTION, source)) #define sexp_exception_source(x) (sexp_field(x, exception, SEXP_EXCEPTION, source))
#define sexp_exception_stack_trace(x) (sexp_field(x, exception, SEXP_EXCEPTION, stack_trace))
#define sexp_trampolinep(x) (sexp_exceptionp(x) && sexp_exception_kind(x) == SEXP_TRAMPOLINE) #define sexp_trampolinep(x) (sexp_exceptionp(x) && sexp_exception_kind(x) == SEXP_TRAMPOLINE)
#define sexp_trampoline_procedure(x) sexp_exception_procedure(x) #define sexp_trampoline_procedure(x) sexp_exception_procedure(x)
@ -1094,7 +1286,6 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_cpointer_freep(x) (sexp_freep(x)) #define sexp_cpointer_freep(x) (sexp_freep(x))
#define sexp_cpointer_length(x) (sexp_cpointer_field(x, length)) #define sexp_cpointer_length(x) (sexp_cpointer_field(x, length))
#define sexp_cpointer_body(x) (sexp_cpointer_field(x, body))
#define sexp_cpointer_parent(x) (sexp_cpointer_field(x, parent)) #define sexp_cpointer_parent(x) (sexp_cpointer_field(x, parent))
#define sexp_cpointer_value(x) (sexp_cpointer_field(x, value)) #define sexp_cpointer_value(x) (sexp_cpointer_field(x, value))
#define sexp_cpointer_maybe_null_value(x) (sexp_not(x) ? NULL : sexp_cpointer_value(x)) #define sexp_cpointer_maybe_null_value(x) (sexp_not(x) ? NULL : sexp_cpointer_value(x))
@ -1104,7 +1295,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_bytecode_name(x) (sexp_field(x, bytecode, SEXP_BYTECODE, name)) #define sexp_bytecode_name(x) (sexp_field(x, bytecode, SEXP_BYTECODE, name))
#define sexp_bytecode_literals(x) (sexp_field(x, bytecode, SEXP_BYTECODE, literals)) #define sexp_bytecode_literals(x) (sexp_field(x, bytecode, SEXP_BYTECODE, literals))
#define sexp_bytecode_source(x) (sexp_field(x, bytecode, SEXP_BYTECODE, source)) #define sexp_bytecode_source(x) (sexp_field(x, bytecode, SEXP_BYTECODE, source))
#define sexp_bytecode_data(x) (sexp_field(x, bytecode, SEXP_BYTECODE, data)) #define sexp_bytecode_data(x) sexp_flexible_array_field(x, bytecode, unsigned char)
#define sexp_env_cell_syntactic_p(x) ((x)->syntacticp) #define sexp_env_cell_syntactic_p(x) ((x)->syntacticp)
@ -1119,10 +1310,12 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_macro_proc(x) (sexp_field(x, macro, SEXP_MACRO, proc)) #define sexp_macro_proc(x) (sexp_field(x, macro, SEXP_MACRO, proc))
#define sexp_macro_env(x) (sexp_field(x, macro, SEXP_MACRO, env)) #define sexp_macro_env(x) (sexp_field(x, macro, SEXP_MACRO, env))
#define sexp_macro_source(x) (sexp_field(x, macro, SEXP_MACRO, source)) #define sexp_macro_source(x) (sexp_field(x, macro, SEXP_MACRO, source))
#define sexp_macro_aux(x) (sexp_field(x, macro, SEXP_MACRO, aux))
#define sexp_synclo_env(x) (sexp_field(x, synclo, SEXP_SYNCLO, env)) #define sexp_synclo_env(x) (sexp_field(x, synclo, SEXP_SYNCLO, env))
#define sexp_synclo_free_vars(x) (sexp_field(x, synclo, SEXP_SYNCLO, free_vars)) #define sexp_synclo_free_vars(x) (sexp_field(x, synclo, SEXP_SYNCLO, free_vars))
#define sexp_synclo_expr(x) (sexp_field(x, synclo, SEXP_SYNCLO, expr)) #define sexp_synclo_expr(x) (sexp_field(x, synclo, SEXP_SYNCLO, expr))
#define sexp_synclo_rename(x) (sexp_field(x, synclo, SEXP_SYNCLO, rename))
#define sexp_core_code(x) (sexp_field(x, core, SEXP_CORE, code)) #define sexp_core_code(x) (sexp_field(x, core, SEXP_CORE, code))
#define sexp_core_name(x) (sexp_field(x, core, SEXP_CORE, name)) #define sexp_core_name(x) (sexp_field(x, core, SEXP_CORE, name))
@ -1192,7 +1385,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_stack_length(x) (sexp_field(x, stack, SEXP_STACK, length)) #define sexp_stack_length(x) (sexp_field(x, stack, SEXP_STACK, length))
#define sexp_stack_top(x) (sexp_field(x, stack, SEXP_STACK, top)) #define sexp_stack_top(x) (sexp_field(x, stack, SEXP_STACK, top))
#define sexp_stack_data(x) (sexp_field(x, stack, SEXP_STACK, data)) #define sexp_stack_data(x) sexp_flexible_array_field(x, stack, sexp)
#define sexp_promise_donep(x) (sexp_field(x, promise, SEXP_PROMISE, donep)) #define sexp_promise_donep(x) (sexp_field(x, promise, SEXP_PROMISE, donep))
#define sexp_promise_value(x) (sexp_field(x, promise, SEXP_PROMISE, value)) #define sexp_promise_value(x) (sexp_field(x, promise, SEXP_PROMISE, value))
@ -1204,6 +1397,8 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_context_stack(x) (sexp_field(x, context, SEXP_CONTEXT, stack)) #define sexp_context_stack(x) (sexp_field(x, context, SEXP_CONTEXT, stack))
#define sexp_context_parent(x) (sexp_field(x, context, SEXP_CONTEXT, parent)) #define sexp_context_parent(x) (sexp_field(x, context, SEXP_CONTEXT, parent))
#define sexp_context_child(x) (sexp_field(x, context, SEXP_CONTEXT, child)) #define sexp_context_child(x) (sexp_field(x, context, SEXP_CONTEXT, child))
#define sexp_context_mark_stack(x) (sexp_field(x, context, SEXP_CONTEXT, mark_stack))
#define sexp_context_mark_stack_ptr(x) (sexp_field(x, context, SEXP_CONTEXT, mark_stack_ptr))
#define sexp_context_saves(x) (sexp_field(x, context, SEXP_CONTEXT, saves)) #define sexp_context_saves(x) (sexp_field(x, context, SEXP_CONTEXT, saves))
#define sexp_context_tailp(x) (sexp_field(x, context, SEXP_CONTEXT, tailp)) #define sexp_context_tailp(x) (sexp_field(x, context, SEXP_CONTEXT, tailp))
#define sexp_context_tracep(x) (sexp_field(x, context, SEXP_CONTEXT, tracep)) #define sexp_context_tracep(x) (sexp_field(x, context, SEXP_CONTEXT, tracep))
@ -1211,13 +1406,20 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_context_dk(x) (sexp_field(x, context, SEXP_CONTEXT, dk)) #define sexp_context_dk(x) (sexp_field(x, context, SEXP_CONTEXT, dk))
#define sexp_context_params(x) (sexp_field(x, context, SEXP_CONTEXT, params)) #define sexp_context_params(x) (sexp_field(x, context, SEXP_CONTEXT, params))
#define sexp_context_last_fp(x) (sexp_field(x, context, SEXP_CONTEXT, last_fp)) #define sexp_context_last_fp(x) (sexp_field(x, context, SEXP_CONTEXT, last_fp))
#if SEXP_USE_TIME_GC
#define sexp_context_gc_count(x) (sexp_field(x, context, SEXP_CONTEXT, gc_count)) #define sexp_context_gc_count(x) (sexp_field(x, context, SEXP_CONTEXT, gc_count))
#if SEXP_USE_TIME_GC
#define sexp_context_gc_usecs(x) (sexp_field(x, context, SEXP_CONTEXT, gc_usecs)) #define sexp_context_gc_usecs(x) (sexp_field(x, context, SEXP_CONTEXT, gc_usecs))
#else #else
#define sexp_context_gc_count(x) 0
#define sexp_context_gc_usecs(x) 0 #define sexp_context_gc_usecs(x) 0
#endif #endif
#if SEXP_USE_TRACK_ALLOC_TIMES
#define sexp_context_alloc_count(x) (sexp_field(x, context, SEXP_CONTEXT, alloc_count))
#define sexp_context_alloc_usecs(x) (sexp_field(x, context, SEXP_CONTEXT, alloc_usecs))
#define sexp_context_alloc_usecs_sq(x) (sexp_field(x, context, SEXP_CONTEXT, alloc_usecs_sq))
#endif
#if SEXP_USE_TRACK_ALLOC_SIZES
#define sexp_context_alloc_histogram(x) (sexp_field(x, context, SEXP_CONTEXT, alloc_histogram))
#endif
#define sexp_context_refuel(x) (sexp_field(x, context, SEXP_CONTEXT, refuel)) #define sexp_context_refuel(x) (sexp_field(x, context, SEXP_CONTEXT, refuel))
#define sexp_context_ip(x) (sexp_field(x, context, SEXP_CONTEXT, ip)) #define sexp_context_ip(x) (sexp_field(x, context, SEXP_CONTEXT, ip))
#define sexp_context_proc(x) (sexp_field(x, context, SEXP_CONTEXT, proc)) #define sexp_context_proc(x) (sexp_field(x, context, SEXP_CONTEXT, proc))
@ -1231,6 +1433,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_context_result(x) (sexp_field(x, context, SEXP_CONTEXT, result)) #define sexp_context_result(x) (sexp_field(x, context, SEXP_CONTEXT, result))
#define sexp_context_errorp(x) (sexp_field(x, context, SEXP_CONTEXT, errorp)) #define sexp_context_errorp(x) (sexp_field(x, context, SEXP_CONTEXT, errorp))
#define sexp_context_interruptp(x) (sexp_field(x, context, SEXP_CONTEXT, interruptp))
/* during compilation, sexp_context_specific is set to a vector */ /* during compilation, sexp_context_specific is set to a vector */
/* containing the following elements: */ /* containing the following elements: */
@ -1327,7 +1530,7 @@ SEXP_API sexp sexp_symbol_table[SEXP_SYMBOL_TABLE_SIZE];
#define sexp_bignum_sign(x) (sexp_field(x, bignum, SEXP_BIGNUM, sign)) #define sexp_bignum_sign(x) (sexp_field(x, bignum, SEXP_BIGNUM, sign))
#define sexp_bignum_length(x) (sexp_field(x, bignum, SEXP_BIGNUM, length)) #define sexp_bignum_length(x) (sexp_field(x, bignum, SEXP_BIGNUM, length))
#define sexp_bignum_data(x) (sexp_field(x, bignum, SEXP_BIGNUM, data)) #define sexp_bignum_data(x) sexp_flexible_array_field(x, bignum, sexp_uint_t)
/****************************** arithmetic ****************************/ /****************************** arithmetic ****************************/
@ -1357,15 +1560,17 @@ SEXP_API sexp sexp_symbol_table[SEXP_SYMBOL_TABLE_SIZE];
/****************************** utilities *****************************/ /****************************** utilities *****************************/
enum sexp_context_globals { enum sexp_context_globals {
#if ! SEXP_USE_GLOBAL_SYMBOLS #if SEXP_USE_STABLE_ABI || ! SEXP_USE_GLOBAL_SYMBOLS
SEXP_G_SYMBOLS, SEXP_G_SYMBOLS,
#endif #endif
SEXP_G_ENDIANNESS,
SEXP_G_TYPES, SEXP_G_TYPES,
SEXP_G_FEATURES, SEXP_G_FEATURES,
SEXP_G_NUM_TYPES, SEXP_G_NUM_TYPES,
SEXP_G_OOM_ERROR, /* out of memory exception object */ SEXP_G_OOM_ERROR, /* out of memory exception object */
SEXP_G_OOS_ERROR, /* out of stack exception object */ SEXP_G_OOS_ERROR, /* out of stack exception object */
SEXP_G_ABI_ERROR, /* incompatible ABI loading library */ SEXP_G_ABI_ERROR, /* incompatible ABI loading library */
SEXP_G_INTERRUPT_ERROR, /* C-c in the repl */
SEXP_G_OPTIMIZATIONS, SEXP_G_OPTIMIZATIONS,
SEXP_G_SIGNAL_HANDLERS, SEXP_G_SIGNAL_HANDLERS,
SEXP_G_META_ENV, SEXP_G_META_ENV,
@ -1374,6 +1579,10 @@ enum sexp_context_globals {
SEXP_G_QUASIQUOTE_SYMBOL, SEXP_G_QUASIQUOTE_SYMBOL,
SEXP_G_UNQUOTE_SYMBOL, SEXP_G_UNQUOTE_SYMBOL,
SEXP_G_UNQUOTE_SPLICING_SYMBOL, SEXP_G_UNQUOTE_SPLICING_SYMBOL,
SEXP_G_SYNTAX_SYMBOL,
SEXP_G_QUASISYNTAX_SYMBOL,
SEXP_G_UNSYNTAX_SYMBOL,
SEXP_G_UNSYNTAX_SPLICING_SYMBOL,
SEXP_G_EMPTY_VECTOR, SEXP_G_EMPTY_VECTOR,
SEXP_G_CUR_IN_SYMBOL, SEXP_G_CUR_IN_SYMBOL,
SEXP_G_CUR_OUT_SYMBOL, SEXP_G_CUR_OUT_SYMBOL,
@ -1386,18 +1595,18 @@ enum sexp_context_globals {
SEXP_G_RANDOM_SOURCE, SEXP_G_RANDOM_SOURCE,
SEXP_G_STRICT_P, SEXP_G_STRICT_P,
SEXP_G_NO_TAIL_CALLS_P, SEXP_G_NO_TAIL_CALLS_P,
#if SEXP_USE_FOLD_CASE_SYMS #if SEXP_USE_STABLE_ABI || SEXP_USE_FOLD_CASE_SYMS
SEXP_G_FOLD_CASE_P, SEXP_G_FOLD_CASE_P,
#endif #endif
#if SEXP_USE_WEAK_REFERENCES #if SEXP_USE_STABLE_ABI || SEXP_USE_WEAK_REFERENCES
SEXP_G_WEAK_OBJECTS_PRESENT, SEXP_G_WEAK_OBJECTS_PRESENT,
SEXP_G_FILE_DESCRIPTORS, SEXP_G_FILE_DESCRIPTORS,
SEXP_G_NUM_FILE_DESCRIPTORS, SEXP_G_NUM_FILE_DESCRIPTORS,
#endif #endif
#if ! SEXP_USE_BOEHM #if SEXP_USE_STABLE_ABI || ! SEXP_USE_BOEHM
SEXP_G_PRESERVATIVES, SEXP_G_PRESERVATIVES,
#endif #endif
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_STABLE_ABI || SEXP_USE_GREEN_THREADS
SEXP_G_IO_BLOCK_ERROR, SEXP_G_IO_BLOCK_ERROR,
SEXP_G_IO_BLOCK_ONCE_ERROR, SEXP_G_IO_BLOCK_ONCE_ERROR,
SEXP_G_THREAD_TERMINATE_ERROR, SEXP_G_THREAD_TERMINATE_ERROR,
@ -1495,10 +1704,21 @@ sexp sexp_finalize_dl (sexp ctx, sexp self, sexp_sint_t n, sexp dl);
#define sexp_current_source_param #define sexp_current_source_param
#endif #endif
/* To export a library from the embedding C program to Scheme, so */
/* that it can be included into Scheme library foo/qux.sld as */
/* (include-shared "bar"), libraries should contain the entry */
/* {"foo/bar", init_bar}. The signature and function of init_bar is */
/* the same as that of sexp_init_library in shared libraries. The */
/* array libraries must be terminated with {NULL, NULL} and must */
/* remain valid throughout its use by Chibi. */
SEXP_API void sexp_add_static_libraries(struct sexp_library_entry_t* libraries);
SEXP_API sexp sexp_alloc_tagged_aux(sexp ctx, size_t size, sexp_uint_t tag sexp_current_source_param); SEXP_API sexp sexp_alloc_tagged_aux(sexp ctx, size_t size, sexp_uint_t tag sexp_current_source_param);
SEXP_API sexp sexp_make_context(sexp ctx, size_t size, size_t max_size); SEXP_API sexp sexp_make_context(sexp ctx, size_t size, size_t max_size);
SEXP_API sexp sexp_cons_op(sexp ctx, sexp self, sexp_sint_t n, sexp head, sexp tail); SEXP_API sexp sexp_cons_op(sexp ctx, sexp self, sexp_sint_t n, sexp head, sexp tail);
SEXP_API sexp sexp_list2(sexp ctx, sexp a, sexp b); SEXP_API sexp sexp_list2(sexp ctx, sexp a, sexp b);
SEXP_API sexp sexp_list3(sexp ctx, sexp a, sexp b, sexp c);
SEXP_API sexp sexp_equalp_bound (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b, sexp depth, sexp bound); SEXP_API sexp sexp_equalp_bound (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b, sexp depth, sexp bound);
SEXP_API sexp sexp_equalp_op (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b); SEXP_API sexp sexp_equalp_op (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b);
SEXP_API sexp sexp_listp_op(sexp ctx, sexp self, sexp_sint_t n, sexp obj); SEXP_API sexp sexp_listp_op(sexp ctx, sexp self, sexp_sint_t n, sexp obj);
@ -1512,6 +1732,7 @@ SEXP_API sexp sexp_length_op(sexp ctx, sexp self, sexp_sint_t n, sexp ls);
SEXP_API sexp sexp_c_string(sexp ctx, const char *str, sexp_sint_t slen); SEXP_API sexp sexp_c_string(sexp ctx, const char *str, sexp_sint_t slen);
SEXP_API sexp sexp_make_ephemeron_op(sexp ctx, sexp self, sexp_sint_t n, sexp key, sexp value); SEXP_API sexp sexp_make_ephemeron_op(sexp ctx, sexp self, sexp_sint_t n, sexp key, sexp value);
SEXP_API sexp sexp_make_bytes_op(sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp i); SEXP_API sexp sexp_make_bytes_op(sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp i);
SEXP_API sexp sexp_make_uvector_op(sexp ctx, sexp self, sexp_sint_t n, sexp elt_type, sexp len);
SEXP_API sexp sexp_make_string_op(sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp ch); SEXP_API sexp sexp_make_string_op(sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp ch);
SEXP_API sexp sexp_substring_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end); SEXP_API sexp sexp_substring_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end);
SEXP_API sexp sexp_subbytes_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end); SEXP_API sexp sexp_subbytes_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end);
@ -1523,6 +1744,7 @@ SEXP_API sexp sexp_string_to_number_op (sexp ctx, sexp self, sexp_sint_t n, sexp
SEXP_API sexp sexp_flonump_op (sexp ctx, sexp self, sexp_sint_t n, sexp x); SEXP_API sexp sexp_flonump_op (sexp ctx, sexp self, sexp_sint_t n, sexp x);
SEXP_API sexp sexp_make_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp dflt); SEXP_API sexp sexp_make_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp dflt);
SEXP_API sexp sexp_list_to_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls); SEXP_API sexp sexp_list_to_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls);
SEXP_API sexp sexp_list_to_uvector_op (sexp ctx, sexp self, sexp_sint_t n, sexp etype, sexp ls);
SEXP_API sexp sexp_make_cpointer (sexp ctx, sexp_uint_t type_id, void* value, sexp parent, int freep); SEXP_API sexp sexp_make_cpointer (sexp ctx, sexp_uint_t type_id, void* value, sexp parent, int freep);
SEXP_API int sexp_is_separator(int c); SEXP_API int sexp_is_separator(int c);
SEXP_API sexp sexp_write_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp out); SEXP_API sexp sexp_write_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp out);
@ -1568,17 +1790,22 @@ SEXP_API sexp sexp_lookup_type_op (sexp ctx, sexp self, sexp_sint_t n, sexp name
SEXP_API sexp sexp_open_input_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp str); SEXP_API sexp sexp_open_input_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp str);
SEXP_API sexp sexp_open_output_string_op (sexp ctx, sexp self, sexp_sint_t n); SEXP_API sexp sexp_open_output_string_op (sexp ctx, sexp self, sexp_sint_t n);
SEXP_API sexp sexp_get_output_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp port); SEXP_API sexp sexp_get_output_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp port);
SEXP_API sexp sexp_make_immutable_op (sexp ctx, sexp self, sexp_sint_t n, sexp x);
SEXP_API sexp sexp_make_exception (sexp ctx, sexp kind, sexp message, sexp irritants, sexp procedure, sexp source); SEXP_API sexp sexp_make_exception (sexp ctx, sexp kind, sexp message, sexp irritants, sexp procedure, sexp source);
SEXP_API sexp sexp_user_exception (sexp ctx, sexp self, const char *msg, sexp x); SEXP_API sexp sexp_user_exception (sexp ctx, sexp self, const char *msg, sexp x);
SEXP_API sexp sexp_user_exception_ls (sexp ctx, sexp self, const char *msg, int n, ...);
SEXP_API sexp sexp_file_exception (sexp ctx, sexp self, const char *msg, sexp x); SEXP_API sexp sexp_file_exception (sexp ctx, sexp self, const char *msg, sexp x);
SEXP_API sexp sexp_type_exception (sexp ctx, sexp self, sexp_uint_t type_id, sexp x); SEXP_API sexp sexp_type_exception (sexp ctx, sexp self, sexp_uint_t type_id, sexp x);
SEXP_API sexp sexp_xtype_exception (sexp ctx, sexp self, const char *msg, sexp x); SEXP_API sexp sexp_xtype_exception (sexp ctx, sexp self, const char *msg, sexp x);
SEXP_API sexp sexp_range_exception (sexp ctx, sexp obj, sexp start, sexp end); SEXP_API sexp sexp_range_exception (sexp ctx, sexp obj, sexp start, sexp end);
SEXP_API sexp sexp_get_stack_trace (sexp ctx);
SEXP_API sexp sexp_print_exception_op (sexp ctx, sexp self, sexp_sint_t n, sexp exn, sexp out); SEXP_API sexp sexp_print_exception_op (sexp ctx, sexp self, sexp_sint_t n, sexp exn, sexp out);
SEXP_API sexp sexp_stack_trace_op (sexp ctx, sexp self, sexp_sint_t n, sexp out); SEXP_API sexp sexp_stack_trace_op (sexp ctx, sexp self, sexp_sint_t n, sexp out);
SEXP_API sexp sexp_print_exception_stack_trace_op (sexp ctx, sexp self, sexp_sint_t n, sexp exn, sexp out);
SEXP_API sexp sexp_apply (sexp context, sexp proc, sexp args); SEXP_API sexp sexp_apply (sexp context, sexp proc, sexp args);
SEXP_API sexp sexp_apply1 (sexp ctx, sexp f, sexp x); SEXP_API sexp sexp_apply1 (sexp ctx, sexp f, sexp x);
SEXP_API sexp sexp_apply2 (sexp ctx, sexp f, sexp x, sexp y); SEXP_API sexp sexp_apply2 (sexp ctx, sexp f, sexp x, sexp y);
SEXP_API sexp sexp_apply3 (sexp ctx, sexp f, sexp x, sexp y, sexp z);
SEXP_API sexp sexp_apply_no_err_handler (sexp ctx, sexp proc, sexp args); SEXP_API sexp sexp_apply_no_err_handler (sexp ctx, sexp proc, sexp args);
SEXP_API sexp sexp_make_trampoline (sexp ctx, sexp proc, sexp args); SEXP_API sexp sexp_make_trampoline (sexp ctx, sexp proc, sexp args);
SEXP_API sexp sexp_make_foreign (sexp ctx, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data); SEXP_API sexp sexp_make_foreign (sexp ctx, const char *name, int num_args, int flags, const char *fname, sexp_proc1 f, sexp data);
@ -1600,7 +1827,7 @@ SEXP_API int sexp_write_utf8_char (sexp ctx, int c, sexp out);
#define sexp_string_ref(ctx, s, i) (sexp_string_utf8_index_ref(ctx, NULL, 2, s, i)) #define sexp_string_ref(ctx, s, i) (sexp_string_utf8_index_ref(ctx, NULL, 2, s, i))
#define sexp_string_set(ctx, s, i, ch) (sexp_string_utf8_index_set(ctx, NULL, 3, s, i, ch)) #define sexp_string_set(ctx, s, i, ch) (sexp_string_utf8_index_set(ctx, NULL, 3, s, i, ch))
#define sexp_string_cursor_ref(ctx, s, i) (sexp_string_utf8_ref(ctx, s, i)) #define sexp_string_cursor_ref(ctx, s, i) (sexp_string_utf8_ref(ctx, s, i))
#define sexp_string_cursor_set(ctx, s, i) (sexp_string_utf8_set(ctx, s, i)) #define sexp_string_cursor_set(ctx, s, i, ch) (sexp_string_utf8_set(ctx, s, i, ch))
#define sexp_string_cursor_next(s, i) sexp_make_string_cursor(sexp_unbox_string_cursor(i) + sexp_utf8_initial_byte_count(((unsigned char*)sexp_string_data(s))[sexp_unbox_string_cursor(i)])) #define sexp_string_cursor_next(s, i) sexp_make_string_cursor(sexp_unbox_string_cursor(i) + sexp_utf8_initial_byte_count(((unsigned char*)sexp_string_data(s))[sexp_unbox_string_cursor(i)]))
#define sexp_string_cursor_prev(s, i) sexp_make_string_cursor(sexp_string_utf8_prev((unsigned char*)sexp_string_data(s)+sexp_unbox_string_cursor(i)) - sexp_string_data(s)) #define sexp_string_cursor_prev(s, i) sexp_make_string_cursor(sexp_string_utf8_prev((unsigned char*)sexp_string_data(s)+sexp_unbox_string_cursor(i)) - sexp_string_data(s))
#define sexp_string_length(s) sexp_string_utf8_length((unsigned char*)sexp_string_data(s), sexp_string_size(s)) #define sexp_string_length(s) sexp_string_utf8_length((unsigned char*)sexp_string_data(s), sexp_string_size(s))
@ -1618,6 +1845,12 @@ SEXP_API int sexp_write_utf8_char (sexp ctx, int c, sexp out);
#define sexp_substring_cursor(ctx, s, i, j) sexp_substring_op(ctx, NULL, 3, s, i, j) #define sexp_substring_cursor(ctx, s, i, j) sexp_substring_op(ctx, NULL, 3, s, i, j)
#endif #endif
#if SEXP_USE_STRING_INDEX_TABLE
SEXP_API void sexp_update_string_index_lookup(sexp ctx, sexp s);
#else
#define sexp_update_string_index_lookup(ctx, s)
#endif
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
SEXP_API int sexp_maybe_block_port (sexp ctx, sexp in, int forcep); SEXP_API int sexp_maybe_block_port (sexp ctx, sexp in, int forcep);
SEXP_API void sexp_maybe_unblock_port (sexp ctx, sexp in); SEXP_API void sexp_maybe_unblock_port (sexp ctx, sexp in);
@ -1653,9 +1886,13 @@ SEXP_API sexp sexp_finalize (sexp ctx);
#if SEXP_USE_GLOBAL_HEAP #if SEXP_USE_GLOBAL_HEAP
#define sexp_free_heap(heap) #define sexp_free_heap(heap)
#define sexp_debug_heap_stats(heap)
#define sexp_destroy_context(ctx) SEXP_TRUE #define sexp_destroy_context(ctx) SEXP_TRUE
#else #else
SEXP_API void sexp_free_heap (sexp_heap heap); SEXP_API void sexp_free_heap (sexp_heap heap);
SEXP_API void sexp_debug_heap_stats (sexp_heap heap);
SEXP_API void sexp_debug_alloc_times(sexp ctx);
SEXP_API void sexp_debug_alloc_sizes(sexp ctx);
SEXP_API sexp sexp_destroy_context (sexp ctx); SEXP_API sexp sexp_destroy_context (sexp ctx);
SEXP_API sexp sexp_copy_context (sexp ctx, sexp dst, sexp flags); SEXP_API sexp sexp_copy_context (sexp ctx, sexp dst, sexp flags);
#endif #endif
@ -1699,6 +1936,7 @@ SEXP_API int sexp_poll_port(sexp ctx, sexp port, int inputp);
#define sexp_read(ctx, in) sexp_read_op(ctx, NULL, 1, in) #define sexp_read(ctx, in) sexp_read_op(ctx, NULL, 1, in)
#define sexp_write(ctx, obj, out) sexp_write_op(ctx, NULL, 2, obj, out) #define sexp_write(ctx, obj, out) sexp_write_op(ctx, NULL, 2, obj, out)
#define sexp_print_exception(ctx, e, out) sexp_print_exception_op(ctx, NULL, 2, e, out) #define sexp_print_exception(ctx, e, out) sexp_print_exception_op(ctx, NULL, 2, e, out)
#define sexp_print_exception_stack_trace(ctx, e, out) sexp_print_exception_stack_trace_op(ctx, NULL, 2, e, out)
#define sexp_flush_output(ctx, out) sexp_flush_output_op(ctx, NULL, 1, out) #define sexp_flush_output(ctx, out) sexp_flush_output_op(ctx, NULL, 1, out)
#define sexp_equalp(ctx, a, b) sexp_equalp_op(ctx, NULL, 2, a, b) #define sexp_equalp(ctx, a, b) sexp_equalp_op(ctx, NULL, 2, a, b)
#define sexp_listp(ctx, x) sexp_listp_op(ctx, NULL, 1, x) #define sexp_listp(ctx, x) sexp_listp_op(ctx, NULL, 1, x)
@ -1711,12 +1949,20 @@ SEXP_API int sexp_poll_port(sexp ctx, sexp port, int inputp);
#define sexp_append2(ctx, a, b) sexp_append2_op(ctx, NULL, 2, a, b) #define sexp_append2(ctx, a, b) sexp_append2_op(ctx, NULL, 2, a, b)
#define sexp_make_vector(ctx, a, b) sexp_make_vector_op(ctx, NULL, 2, a, b) #define sexp_make_vector(ctx, a, b) sexp_make_vector_op(ctx, NULL, 2, a, b)
#define sexp_list_to_vector(ctx, x) sexp_list_to_vector_op(ctx, NULL, 1, x) #define sexp_list_to_vector(ctx, x) sexp_list_to_vector_op(ctx, NULL, 1, x)
#define sexp_list_to_uvector(ctx, etype, ls) sexp_list_to_uvector_op(ctx, NULL, 2, etype, ls)
#define sexp_exception_type(ctx, x) sexp_exception_type_op(ctx, NULL, 1, x) #define sexp_exception_type(ctx, x) sexp_exception_type_op(ctx, NULL, 1, x)
#define sexp_string_to_symbol(ctx, s) sexp_string_to_symbol_op(ctx, NULL, 1, s) #define sexp_string_to_symbol(ctx, s) sexp_string_to_symbol_op(ctx, NULL, 1, s)
#define sexp_string_to_number(ctx, s, b) sexp_string_to_number_op(ctx, NULL, 2, s, b) #define sexp_string_to_number(ctx, s, b) sexp_string_to_number_op(ctx, NULL, 2, s, b)
#define sexp_symbol_to_string(ctx, s) sexp_symbol_to_string_op(ctx, NULL, 1, s) #define sexp_symbol_to_string(ctx, s) sexp_symbol_to_string_op(ctx, NULL, 1, s)
#define sexp_make_ephemeron(ctx, k, v) sexp_make_ephemeron_op(ctx, NULL, 2, k, v) #define sexp_make_ephemeron(ctx, k, v) sexp_make_ephemeron_op(ctx, NULL, 2, k, v)
#define sexp_make_bytes(ctx, l, i) sexp_make_bytes_op(ctx, NULL, 2, l, i) #define sexp_make_bytes(ctx, l, i) sexp_make_bytes_op(ctx, NULL, 2, l, i)
#if SEXP_USE_UNIFORM_VECTOR_LITERALS
#define sexp_make_uvector(ctx, et, l) sexp_make_uvector_op(ctx, NULL, 2, et, l)
#else
#define sexp_make_uvector(ctx, et, l) sexp_make_vector(ctx, l, SEXP_ZERO)
#define sexp_write_uvector NULL
#define sexp_finalize_uvector NULL
#endif
#define sexp_make_string(ctx, l, c) sexp_make_string_op(ctx, NULL, 2, l, c) #define sexp_make_string(ctx, l, c) sexp_make_string_op(ctx, NULL, 2, l, c)
#define sexp_subbytes(ctx, a, b, c) sexp_subbytes_op(ctx, NULL, 3, a, b, c) #define sexp_subbytes(ctx, a, b, c) sexp_subbytes_op(ctx, NULL, 3, a, b, c)
#define sexp_string_concatenate(ctx, ls, s) sexp_string_concatenate_op(ctx, NULL, 2, ls, s) #define sexp_string_concatenate(ctx, ls, s) sexp_string_concatenate_op(ctx, NULL, 2, ls, s)

View file

@ -1,5 +1,4 @@
[ [
'_main', "_main",
'_sexp_resume' "_sexp_resume"
] ]

View file

@ -92,19 +92,19 @@ sexp sexp_listen (sexp ctx, sexp self, sexp fileno, sexp backlog) {
/* Additional utilities. */ /* Additional utilities. */
sexp sexp_sockaddr_name (sexp ctx, sexp self, struct sockaddr* addr) { sexp sexp_sockaddr_name (sexp ctx, sexp self, struct sockaddr* addr) {
char buf[24]; char buf[INET6_ADDRSTRLEN];
/* struct sockaddr_in *sa = (struct sockaddr_in *)addr; */ /* struct sockaddr_in *sa = (struct sockaddr_in *)addr; */
/* unsigned char *ptr = (unsigned char *)&(sa->sin_addr); */ /* unsigned char *ptr = (unsigned char *)&(sa->sin_addr); */
/* sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]); */ /* snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]); */
inet_ntop(addr->sa_family, inet_ntop(addr->sa_family,
(addr->sa_family == AF_INET6 ? (addr->sa_family == AF_INET6 ?
(void*)(&(((struct sockaddr_in6 *)addr)->sin6_addr)) : (void*)(&(((struct sockaddr_in6 *)addr)->sin6_addr)) :
(void*)(&(((struct sockaddr_in *)addr)->sin_addr))), (void*)(&(((struct sockaddr_in *)addr)->sin_addr))),
buf, 24); buf, INET6_ADDRSTRLEN);
return sexp_c_string(ctx, buf, -1); return sexp_c_string(ctx, buf, -1);
} }
int sexp_sockaddr_port (sexp ctx, sexp self, struct sockaddr* addr) { int sexp_sockaddr_port (sexp ctx, sexp self, struct sockaddr* addr) {
struct sockaddr_in *sa = (struct sockaddr_in *)addr; struct sockaddr_in *sa = (struct sockaddr_in *)addr;
return sa->sin_port; return ntohs(sa->sin_port);
} }

View file

@ -41,4 +41,9 @@
(guard (exn (else 'error)) (guard (exn (else 'error))
(run-application zoo-app-spec (run-application zoo-app-spec
'("zoo" "--soap" "wash" "--animals" "rhino")))) '("zoo" "--soap" "wash" "--animals" "rhino"))))
(let ((out (open-output-string)))
(parameterize ((current-output-port out))
(run-application zoo-app-spec '("zoo" "help"))
(test "Usage: zoo [options] <command>\nCommands:\n feed animals ... - feed the animals\n wash animals ... - wash the animals\n help - print help\nOptions:\n --animals - list of animals to act on (default all)\n -l, --lions - also apply the action to lions\n"
(get-output-string out))))
(test-end)))) (test-end))))

View file

@ -1,12 +1,19 @@
;; app.scm -- unified option parsing and config ;; app.scm -- unified option parsing and config
;; Copyright (c) 2012-2015 Alex Shinn. All rights reserved. ;; Copyright (c) 2012-2024 Alex Shinn. All rights reserved.
;; BSD-style license: http://synthcode.com/license.txt ;; BSD-style license: http://synthcode.com/license.txt
;;> The high-level interface. Given an application spec \var{spec}, ;;> The high-level interface. Parses a command-line with optional
;;> parses the given command-line arguments \var{args} into a config ;;> and/or positional arguments, with arbitrarily nested subcommands
;;> object, prepended to the existing object \var{config} if given. ;;> (optionally having their own arguments), and calls the
;;> Then runs the corresponding command (or sub-command) procedure ;;> corresponding main procedure on the parsed config.
;;> from \var{spec}. ;;>
;;> Given an application spec \var{spec}, parses the given
;;> command-line arguments \var{args} into a config object (from
;;> \scheme{(chibi config)}), prepended to the existing object
;;> \var{config} if given. Then runs the corresponding command (or
;;> sub-command) procedure from \var{spec} on the following arguments:
;;>
;;> \scheme{(<proc> <config> <spec> <positional args> ...)}
;;> ;;>
;;> The app spec should be a list of the form: ;;> The app spec should be a list of the form:
;;> ;;>
@ -15,12 +22,13 @@
;;> where clauses can be any of: ;;> where clauses can be any of:
;;> ;;>
;;> \itemlist[ ;;> \itemlist[
;;> \item[\scheme{(@ <opt-spec>)} - option spec, described below] ;;> \item{\scheme{(@ <opt-spec>)} - option spec, described below}
;;> \item[\scheme{(begin: <begin-proc>)} - procedure to run before main] ;;> \item{\scheme{(begin: <begin-proc>)} - procedure to run before main}
;;> \item[\scheme{(end: <end-proc>)} - procedure to run after main] ;;> \item{\scheme{(end: <end-proc>)} - procedure to run after main}
;;> \item[\scheme{(<proc> args ...)} - main procedure (args only for documentation)] ;;> \item{\scheme{(types: (<type-name> <parser>) ...)} - additional types that can be used in argument parsing}
;;> \item[\scheme{<app-spec>} - a subcommand described by the nested spec] ;;> \item{\scheme{(<proc> args ...)} - main procedure (args only for documentation)}
;;> \item[\scheme{(or <app-spec> ...)} - an alternate list of subcommands] ;;> \item{\scheme{<app-spec>} - a subcommand described by the nested spec}
;;> \item{\scheme{(or <app-spec> ...)} - an alternate list of subcommands}
;;> ] ;;> ]
;;> ;;>
;;> For subcommands the symbolic command name must match, though it is ;;> For subcommands the symbolic command name must match, though it is
@ -40,7 +48,7 @@
;;> ;;>
;;> \itemlist[ ;;> \itemlist[
;;> \item{\scheme{boolean} - boolean, associated value optional, allowing \scheme{--noname} to indicate \scheme{#false}} ;;> \item{\scheme{boolean} - boolean, associated value optional, allowing \scheme{--noname} to indicate \scheme{#false}}
;;> \item{[\scheme{char} - a single character} ;;> \item{\scheme{char} - a single character}
;;> \item{\scheme{integer} - an exact integer} ;;> \item{\scheme{integer} - an exact integer}
;;> \item{\scheme{real} - any real number} ;;> \item{\scheme{real} - any real number}
;;> \item{\scheme{number} - any real or complex number} ;;> \item{\scheme{number} - any real or complex number}
@ -55,7 +63,43 @@
;;> files, whereas the app specs include embedded procedure objects so ;;> files, whereas the app specs include embedded procedure objects so
;;> are typically written with \scheme{quasiquote}. ;;> are typically written with \scheme{quasiquote}.
;;> ;;>
;;> Complete Example: ;;> Complete Example - stripped down ls(1):
;;>
;;> \schemeblock{
;;> (import (scheme base)
;;> (scheme process-context)
;;> (scheme write)
;;> (srfi 130)
;;> (chibi app)
;;> (chibi config)
;;> (chibi filesystem))
;;>
;;> (define (ls cfg spec . files)
;;> (for-each
;;> (lambda (x)
;;> (for-each
;;> (lambda (file)
;;> (unless (and (string-prefix? "." file)
;;> (not (conf-get cfg 'all)))
;;> (write-string file)
;;> (when (conf-get cfg 'long)
;;> (write-string " ")
;;> (write (file-modification-time file)))
;;> (newline)))
;;> (if (file-directory? x) (directory-files x) (list x))))
;;> files))
;;>
;;> (run-application
;;> `(ls
;;> "list directory contents"
;;> (@
;;> (long boolean (#\\l) "use a long listing format")
;;> (all boolean (#\\a) "do not ignore entries starting with ."))
;;> (,ls files ...))
;;> (command-line))
;;> }
;;>
;;> Subcommand Skeleton Example:
;;> ;;>
;;> \schemeblock{ ;;> \schemeblock{
;;> (run-application ;;> (run-application
@ -63,11 +107,11 @@
;;> "Zookeeper Application" ;;> "Zookeeper Application"
;;> (@ ;;> (@
;;> (animals (list symbol) "list of animals to act on (default all)") ;;> (animals (list symbol) "list of animals to act on (default all)")
;;> (lions boolean (#\l) "also apply the action to lions")) ;;> (lions boolean (#\\l) "also apply the action to lions"))
;;> (or ;;> (or
;;> (feed "feed the animals" () (,feed animals ...)) ;;> (feed "feed the animals" () (,feed animals ...))
;;> (wash "wash the animals" (@ (soap boolean)) (,wash animals ...)) ;;> (wash "wash the animals" (@ (soap boolean)) (,wash animals ...))
;;> (help "print help" (,app-help-command))) ;;> (help "print help" (,app-help-command))))
;;> (command-line) ;;> (command-line)
;;> (conf-load (string-append (get-environment-variable "HOME") "/.zoo"))) ;;> (conf-load (string-append (get-environment-variable "HOME") "/.zoo")))
;;> } ;;> }
@ -125,7 +169,7 @@
(let ((args (or (and (pair? o) (car o)) (command-line))) (let ((args (or (and (pair? o) (car o)) (command-line)))
(config (and (pair? o) (pair? (cdr o)) (cadr o)))) (config (and (pair? o) (pair? (cdr o)) (cadr o))))
(cond (cond
((parse-app '() (cdr spec) '() (cdr args) config #f #f) ((parse-app '() (cdr spec) '() (cdr args) config #f #f '())
=> (lambda (v) => (lambda (v)
(let ((proc (vector-ref v 0)) (let ((proc (vector-ref v 0))
(cfg (vector-ref v 1)) (cfg (vector-ref v 1))
@ -140,7 +184,7 @@
(app-help spec args) (app-help spec args)
(error "Expected a command")) (error "Expected a command"))
(else (else
(error "Unknown command" (cdr args)))))) (error "Unknown command" args)))))
;;> Parse a single command-line argument from \var{args} according to ;;> Parse a single command-line argument from \var{args} according to
;;> \var{conf-spec}, and returns a list of two values: the ;;> \var{conf-spec}, and returns a list of two values: the
@ -150,7 +194,7 @@
;;> \var{fail} with a single string argument describing the error, ;;> \var{fail} with a single string argument describing the error,
;;> returning that result. ;;> returning that result.
(define (parse-option prefix conf-spec args fail) (define (parse-option prefix conf-spec args types fail)
(define (parse-value type str) (define (parse-value type str)
(cond (cond
((not (string? str)) ((not (string? str))
@ -187,7 +231,10 @@
res)) res))
#f)) #f))
(else (else
(list str #f)))))) (cond
((assq type types)
=> (lambda (cell) (list ((cadr cell) str) #f)))
(else (list str #f))))))))
(define (lookup-conf-spec conf-spec syms strs) (define (lookup-conf-spec conf-spec syms strs)
(let ((sym (car syms)) (let ((sym (car syms))
(str (car strs))) (str (car strs)))
@ -302,7 +349,7 @@
;;> is the list of remaining non-option arguments. Calls fail on ;;> is the list of remaining non-option arguments. Calls fail on
;;> error and tries to continue processing from the result. ;;> error and tries to continue processing from the result.
(define (parse-options prefix conf-spec orig-args fail) (define (parse-options prefix conf-spec orig-args types fail)
(let lp ((args orig-args) (let lp ((args orig-args)
(opts (make-conf '() #f (cons 'options orig-args) #f))) (opts (make-conf '() #f (cons 'options orig-args) #f)))
(cond (cond
@ -312,7 +359,7 @@
(not (eqv? #\- (string-ref (car args) 0)))) (not (eqv? #\- (string-ref (car args) 0))))
(cons opts (if (equal? (car args) "--") (cdr args) args))) (cons opts (if (equal? (car args) "--") (cdr args) args)))
(else (else
(let ((val+args (parse-option prefix conf-spec args fail))) (let ((val+args (parse-option prefix conf-spec args types fail)))
(lp (cdr val+args) (lp (cdr val+args)
(conf-set opts (caar val+args) (cdar val+args)))))))) (conf-set opts (caar val+args) (cdar val+args))))))))
@ -332,23 +379,42 @@
;;> all prefixed by \var{prefix}. The original \var{spec} is used for ;;> all prefixed by \var{prefix}. The original \var{spec} is used for
;;> \scheme{app-help}. ;;> \scheme{app-help}.
(define (parse-app prefix spec opt-spec args config init end . o) (define (parse-app prefix spec opt-spec args config init end types . o)
(define (next-prefix prefix name) (define (next-prefix prefix name)
(append (if (null? prefix) '(command) prefix) (list name))) (append (if (null? prefix) '(command) prefix) (list name)))
(define (prev-prefix prefix) (define (prev-prefix prefix)
(cond ((and (= 2 (length prefix))) '()) (cond ((and (= 2 (length prefix))) '())
((null? prefix) '()) ((null? prefix) '())
(else (reverse (cdr (reverse prefix)))))) (else (reverse (cdr (reverse prefix))))))
(define (all-opt-names opt-spec)
;; TODO: nested options
(let lp ((ls opt-spec) (res '()))
(if (null? ls)
(map (lambda (x) (if (symbol? x) (symbol->string x) x))
(remove char? (reverse res)))
(let ((o (car ls)))
(lp (cdr ls)
(append (if (and (pair? (cddr o)) (pair? (third o)))
(third o)
'())
(cons (car o) res)))))))
(let ((fail (if (pair? o) (let ((fail (if (pair? o)
(car o) (car o)
(lambda (prefix spec opt args reason) (lambda (prefix spec opt args reason)
;; TODO: search for closest option in "unknown" case (cond
(error reason opt))))) ((and (string=? reason "unknown option")
(find-nearest-edits opt (all-opt-names spec)))
=> (lambda (similar)
(if (pair? similar)
(error reason opt "Did you mean: " similar)
(error reason opt))))
(else
(error reason opt)))))))
(cond (cond
((null? spec) ((null? spec)
(error "no procedure in application spec")) (error "no procedure in application spec"))
((or (null? (car spec)) (equal? '(@) (car spec))) ((or (null? (car spec)) (equal? '(@) (car spec)))
(parse-app prefix (cdr spec) opt-spec args config init end fail)) (parse-app prefix (cdr spec) opt-spec args config init end types fail))
((pair? (car spec)) ((pair? (car spec))
(case (caar spec) (case (caar spec)
((@) ((@)
@ -364,38 +430,41 @@
(car tail)))) (car tail))))
(new-fail (new-fail
(lambda (new-prefix new-spec new-opt new-args reason) (lambda (new-prefix new-spec new-opt new-args reason)
(parse-option (prev-prefix prefix) opt-spec new-args fail))) (parse-option (prev-prefix prefix) opt-spec new-args types fail)))
(cfg+args (parse-options prefix new-opt-spec args new-fail)) (cfg+args (parse-options prefix new-opt-spec args types new-fail))
(config (conf-append (car cfg+args) config)) (config (conf-append (car cfg+args) config))
(args (cdr cfg+args))) (args (cdr cfg+args)))
(parse-app prefix (cdr spec) new-opt-spec args config (parse-app prefix (cdr spec) new-opt-spec args config
init end new-fail))) init end types new-fail)))
((or) ((or)
(any (lambda (x) (parse-app prefix x opt-spec args config init end)) (any (lambda (x) (parse-app prefix x opt-spec args config init end types))
(cdar spec))) (cdar spec)))
((begin:) ((begin:)
(parse-app prefix (cdr spec) opt-spec args config (parse-app prefix (cdr spec) opt-spec args config
(cadr (car spec)) end fail)) (cadr (car spec)) end types fail))
((end:) ((end:)
(parse-app prefix (cdr spec) opt-spec args config (parse-app prefix (cdr spec) opt-spec args config
init (cadr (car spec)) fail)) init (cadr (car spec)) types fail))
((types:)
(parse-app prefix (cdr spec) opt-spec args config
init end (cdr (car spec)) fail))
(else (else
(if (procedure? (caar spec)) (if (procedure? (caar spec))
(vector (caar spec) config args init end) ; TODO: verify (vector (caar spec) config args init end) ; TODO: verify
(parse-app prefix (car spec) opt-spec args config (parse-app prefix (car spec) opt-spec args config
init end fail))))) init end types fail)))))
((symbol? (car spec)) ((symbol? (car spec))
(and (pair? args) (and (pair? args)
(eq? (car spec) (string->symbol (car args))) (eq? (car spec) (string->symbol (car args)))
(let ((prefix (next-prefix prefix (car spec)))) (let ((prefix (next-prefix prefix (car spec))))
(parse-app prefix (cdr spec) opt-spec (cdr args) config (parse-app prefix (cdr spec) opt-spec (cdr args) config
init end fail)))) init end types fail))))
((procedure? (car spec)) ((procedure? (car spec))
(vector (car spec) config args init end)) (vector (car spec) config args init end))
(else (else
(if (not (string? (car spec))) (if (not (string? (car spec)))
(error "unknown application spec" (car spec))) (error "unknown application spec" (car spec)))
(parse-app prefix (cdr spec) opt-spec args config init end fail))))) (parse-app prefix (cdr spec) opt-spec args config init end types fail)))))
(define (print-command-help command out) (define (print-command-help command out)
(cond (cond
@ -469,7 +538,7 @@
(and (pair? (car ls)) (memq (caar ls) '(begin: end:) ))) (and (pair? (car ls)) (memq (caar ls) '(begin: end:) )))
(lp (cdr ls) (car ls) commands options)) (lp (cdr ls) (car ls) commands options))
((and (pair? (car ls)) (eq? '@ (caar ls))) ((and (pair? (car ls)) (eq? '@ (caar ls)))
(lp (cdr ls) docs commands (append options (cadr (car ls))))) (lp (cdr ls) docs commands (append options (cdar ls))))
((and (pair? (car ls)) (symbol? (caar ls))) ((and (pair? (car ls)) (symbol? (caar ls)))
;; don't print nested commands ;; don't print nested commands
(if (pair? commands) (if (pair? commands)

View file

@ -9,5 +9,6 @@
(scheme process-context) (scheme process-context)
(srfi 1) (srfi 1)
(chibi config) (chibi config)
(chibi edit-distance)
(chibi string)) (chibi string))
(include "app.scm")) (include "app.scm"))

33
lib/chibi/apropos.scm Normal file
View file

@ -0,0 +1,33 @@
(define (list-bindings env)
(let parents ((env env) (binds '()))
(if (not env) binds
(let symbols ((syms (env-exports env)) (binds binds))
(if (null? syms) (parents (env-parent env) binds)
(symbols (cdr syms) (if (assv (car syms) binds) binds
(cons (cons (car syms) env)
binds))))))))
(define (apropos-list-bindings query)
(cond ((symbol? query) (set! query (symbol->string query)))
((not (string? query))
(error "Apropos query must be a symbol or a string")))
(sort (filter (lambda (binding)
(string-contains (symbol->string (car binding)) query))
(list-bindings (interaction-environment)))
(lambda (a b) (string<? (symbol->string (car a))
(symbol->string (car b))))))
(define (apropos-list query) (map car (apropos-list-bindings query)))
(define (apropos-prefix sym env)
(let ((p "procedure ")
(s "syntax ")
(v "variable "))
(guard (_ (else s)) (if (procedure? (eval sym env)) p v))))
(define (apropos query)
(for-each (lambda (bind)
(display (apropos-prefix (car bind) (cdr bind)))
(write (car bind))
(newline))
(apropos-list-bindings query)))

4
lib/chibi/apropos.sld Normal file
View file

@ -0,0 +1,4 @@
(define-library (chibi apropos)
(export apropos apropos-list)
(import (scheme base) (chibi) (chibi string) (srfi 1) (srfi 95))
(include "apropos.scm"))

30
lib/chibi/assert-test.sld Normal file
View file

@ -0,0 +1,30 @@
(define-library (chibi assert-test)
(import (chibi) (chibi assert) (chibi test))
(export run-tests)
(begin
(define-syntax test-assert
(syntax-rules ()
((test-assert irritants expr)
(protect (exn
(else
(test irritants (exception-irritants exn))))
expr
(error "assertion not triggered")))))
(define (run-tests)
(test-begin "assert")
(test-assert '((= x (+ x 1))
(x 3))
(let ((x 3)) (assert (= x (+ x 1)))))
(test-assert '((= x (+ y 1))
(x 3)
(y 42))
(let ((x 3) (y 42)) (assert (= x (+ y 1)))))
(test-assert '((eq? x 'three)
(x 3))
(let ((x 3)) (assert (eq? x 'three))))
(test-assert '((eq? x 'three)
"expected three: "
3)
(let ((x 3)) (assert (eq? x 'three) "expected three: " x)))
(test-end))))

115
lib/chibi/assert.sld Normal file
View file

@ -0,0 +1,115 @@
;;> A nice assert macro.
;;>
;;> Assert macros are common in Scheme, in particular being helpful
;;> for domain checks at the beginning of a procedure to catch errors
;;> as early as possible. Compared to statically typed languages this
;;> has the advantages that the assertions are optional, and that they
;;> are not limited by the type system. SRFI 145 provides the related
;;> notion of assumptions, but the motivation there is to provide
;;> hints to optimizing compilers, and these are not required to
;;> actually signal an error.
;;>
;;> \macro{(assert expr [msg ...])}
;;>
;;> Equivalent to SRFI 145 \code{assume} except that an error is
;;> guaranteed to be raised if \var{expr} is false. Conceptually
;;> shorthand for
;;>
;;> \code{(or \var{expr}
;;> (error "assertion failed" \var{msg} ...))}
;;>
;;> that is, evaluates \var{expr} and returns it if true, but raises
;;> an exception otherwise. The error is augmented to include the
;;> text of the failed \var{expr}. If no additional \var{msg}
;;> arguments are provided then \var{expr} is scanned for free
;;> variables in non-operator positions to report values from, e.g. in
;;>
;;> \code{(let ((x 3))
;;> (assert (= x (+ x 1))))}
;;>
;;> the error would also report the bound value of \code{x}. This
;;> uses the technique from Oleg Kiselyov's \hyperlink[http://okmij.org/ftp/Scheme/assert-syntax-rule.txt]{good assert macro},
;;> which is convenient but fallible. It is thus best to keep the
;;> body of the assertion simple, moving any predicates you need to
;;> external utilities, or provide an explicit \var{msg}.
(define-library (chibi assert)
(export assert)
(cond-expand
(chibi
(import (chibi))
(begin
(define-syntax syntax-identifier?
(er-macro-transformer
(lambda (expr rename compare)
(if (identifier? (cadr expr))
(car (cddr expr))
(cadr (cddr expr))))))
(define-syntax syntax-id-memq?
(er-macro-transformer
(lambda (expr rename compare)
(let ((expr (cdr expr)))
(if (any (lambda (x) (compare x (car expr))) (cadr expr))
(car (cddr expr))
(cadr (cddr expr)))))))))
(else
(import (scheme base))
(begin
;; from match.scm
(define-syntax syntax-identifier?
(syntax-rules ()
((_ (x . y) success-k failure-k) failure-k)
((_ #(x ...) success-k failure-k) failure-k)
((_ x success-k failure-k)
(let-syntax
((sym?
(syntax-rules ()
((sym? x sk fk) sk)
((sym? y sk fk) fk))))
(sym? abracadabra success-k failure-k)))))
(define-syntax syntax-id-memq?
(syntax-rules ()
((syntax-memq? id (ids ...) sk fk)
(let-syntax
((memq?
(syntax-rules (ids ...)
((memq? id sk2 fk2) fk2)
((memq? any-other sk2 fk2) sk2))))
(memq? random-symbol-to-match sk fk))))))))
(begin
(define-syntax extract-vars
(syntax-rules ()
((report-vars (op arg0 arg1 ...) (next ...) res)
(syntax-id-memq? op (quote quasiquote lambda let let* letrec letrec*
let-syntax letrec-syntax let-values let*-values
receive match case define define-syntax do)
(next ... res)
(extract-vars arg0
(extract-vars (op arg1 ...) (next ...))
res)))
((report-vars (op . x) (next ...) res)
(next ... res))
((report-vars x (next ...) (res ...))
(syntax-identifier? x
(syntax-id-memq? x (res ...)
(next ... (res ...))
(next ... (res ... x)))
(next ... (res ...))))))
(define-syntax qq-vars
(syntax-rules ()
((qq-vars (next ...) (var ...))
(next ... `(var ,var) ...))))
(define-syntax report-final
(syntax-rules ()
((report-final expr msg ...)
(error "assertion failed" 'expr msg ...))))
(define-syntax assert
(syntax-rules ()
((assert test)
(or test
(extract-vars test (qq-vars (report-final test)) ())))
((assert test msg ...)
(or test
(report-final test msg ...)))
((assert) #t)))))

View file

@ -72,7 +72,7 @@ sexp sexp_get_env_cell (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp id, s
id = sexp_synclo_expr(id); id = sexp_synclo_expr(id);
} }
cell = sexp_env_cell(ctx, env, id, 0); cell = sexp_env_cell(ctx, env, id, 0);
if (!cell && createp) if (!cell && sexp_truep(createp))
cell = sexp_env_cell_define(ctx, env, id, SEXP_UNDEF, NULL); cell = sexp_env_cell_define(ctx, env, id, SEXP_UNDEF, NULL);
} }
return cell ? cell : SEXP_FALSE; return cell ? cell : SEXP_FALSE;
@ -98,9 +98,26 @@ sexp sexp_get_procedure_variadic_p (sexp ctx, sexp self, sexp_sint_t n, sexp pro
return sexp_make_boolean(sexp_procedure_variadic_p(proc)); return sexp_make_boolean(sexp_procedure_variadic_p(proc));
} }
sexp sexp_get_procedure_variable_transformer_p (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
return sexp_make_boolean(sexp_procedure_variable_transformer_p(proc));
}
sexp sexp_get_procedure_flags (sexp ctx, sexp self, sexp_sint_t n, sexp proc) { sexp sexp_get_procedure_flags (sexp ctx, sexp self, sexp_sint_t n, sexp proc) {
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc); sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, proc);
return sexp_make_fixnum(sexp_procedure_flags(proc)); return (sexp) (sexp_uint_t) sexp_procedure_flags(proc);
}
sexp sexp_make_variable_transformer_op (sexp ctx, sexp self, sexp_sint_t n, sexp base_proc) {
sexp flags;
sexp_assert_type(ctx, sexp_procedurep, SEXP_PROCEDURE, base_proc);
if (sexp_procedure_variable_transformer_p(base_proc))
return base_proc;
flags = sexp_make_fixnum(sexp_unbox_fixnum(sexp_procedure_flags(base_proc)) | SEXP_PROC_VARIABLE_TRANSFORMER);
return sexp_make_procedure(ctx, flags,
sexp_make_fixnum(sexp_procedure_num_args(base_proc)),
sexp_procedure_code(base_proc),
sexp_procedure_vars(base_proc));
} }
sexp sexp_get_opcode_name (sexp ctx, sexp self, sexp_sint_t n, sexp op) { sexp sexp_get_opcode_name (sexp ctx, sexp self, sexp_sint_t n, sexp op) {
@ -216,6 +233,18 @@ sexp sexp_set_port_line (sexp ctx, sexp self, sexp_sint_t n, sexp p, sexp i) {
return SEXP_VOID; return SEXP_VOID;
} }
sexp sexp_get_port_sourcep (sexp ctx, sexp self, sexp_sint_t n, sexp p) {
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
return sexp_make_boolean(sexp_port_sourcep(p));
}
sexp sexp_set_port_sourcep (sexp ctx, sexp self, sexp_sint_t n, sexp p, sexp b) {
sexp_assert_type(ctx, sexp_portp, SEXP_IPORT, p);
sexp_assert_type(ctx, sexp_booleanp, SEXP_BOOLEAN, b);
sexp_port_sourcep(p) = sexp_truep(b);
return SEXP_VOID;
}
sexp sexp_type_of (sexp ctx, sexp self, sexp_sint_t n, sexp x) { sexp sexp_type_of (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
if (!x) if (!x)
return sexp_type_by_index(ctx, SEXP_OBJECT); return sexp_type_by_index(ctx, SEXP_OBJECT);
@ -335,12 +364,21 @@ sexp sexp_immutablep_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
return sexp_pointerp(x) ? sexp_make_boolean(sexp_immutablep(x)) : SEXP_TRUE; return sexp_pointerp(x) ? sexp_make_boolean(sexp_immutablep(x)) : SEXP_TRUE;
} }
sexp sexp_make_immutable_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) { sexp sexp_immutable_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp s) {
if (sexp_pointerp(x)) { sexp res;
sexp_immutablep(x) = 1; sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, s);
return SEXP_TRUE; #if SEXP_USE_PACKED_STRINGS
} /* no sharing with packed strings */
return SEXP_FALSE; res = sexp_c_string(ctx, sexp_string_data(s), sexp_string_size(s));
#else
res = sexp_alloc_type(ctx, string, SEXP_STRING);
sexp_string_bytes(res) = sexp_string_bytes(s);
sexp_string_offset(res) = sexp_string_offset(s);
sexp_string_size(res) = sexp_string_size(s);
sexp_copy_on_writep(s) = 1;
#endif
sexp_immutablep(res) = 1;
return res;
} }
sexp sexp_integer_to_immediate (sexp ctx, sexp self, sexp_sint_t n, sexp i, sexp dflt) { sexp sexp_integer_to_immediate (sexp ctx, sexp self, sexp_sint_t n, sexp i, sexp dflt) {
@ -476,6 +514,12 @@ sexp sexp_set_atomic (sexp ctx, sexp self, sexp_sint_t n, sexp new_val) {
} }
#endif #endif
sexp sexp_thread_interrupt (sexp ctx, sexp self, sexp_sint_t n, sexp thread) {
sexp_assert_type(ctx, sexp_contextp, SEXP_CONTEXT, thread);
sexp_context_interruptp(thread) = 1;
return sexp_make_boolean(ctx == thread);
}
sexp sexp_thread_list (sexp ctx, sexp self, sexp_sint_t n) { sexp sexp_thread_list (sexp ctx, sexp self, sexp_sint_t n) {
sexp_gc_var1(res); sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res); sexp_gc_preserve1(ctx, res);
@ -582,6 +626,7 @@ sexp sexp_abort (sexp ctx, sexp self, sexp_sint_t n, sexp value) {
sexp_env_define(ctx, env, sexp_intern(ctx, name, -1), sexp_type_by_index(ctx, tag)); sexp_env_define(ctx, env, sexp_intern(ctx, name, -1), sexp_type_by_index(ctx, tag));
sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, const sexp_abi_identifier_t abi) { sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, const sexp_abi_identifier_t abi) {
sexp_gc_var2(sym, str);
if (!(sexp_version_compatible(ctx, version, sexp_version) if (!(sexp_version_compatible(ctx, version, sexp_version)
&& sexp_abi_compatible(ctx, abi, SEXP_ABI_IDENTIFIER))) && sexp_abi_compatible(ctx, abi, SEXP_ABI_IDENTIFIER)))
return SEXP_ABI_ERROR; return SEXP_ABI_ERROR;
@ -632,7 +677,6 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_type_predicate(ctx, env, "ref?", SEXP_REF); sexp_define_type_predicate(ctx, env, "ref?", SEXP_REF);
sexp_define_type_predicate(ctx, env, "seq?", SEXP_SEQ); sexp_define_type_predicate(ctx, env, "seq?", SEXP_SEQ);
sexp_define_type_predicate(ctx, env, "lit?", SEXP_LIT); sexp_define_type_predicate(ctx, env, "lit?", SEXP_LIT);
sexp_define_type_predicate(ctx, env, "opcode?", SEXP_OPCODE);
sexp_define_type_predicate(ctx, env, "type?", SEXP_TYPE); sexp_define_type_predicate(ctx, env, "type?", SEXP_TYPE);
sexp_define_type_predicate(ctx, env, "core?", SEXP_CORE); sexp_define_type_predicate(ctx, env, "core?", SEXP_CORE);
sexp_define_type_predicate(ctx, env, "context?", SEXP_CONTEXT); sexp_define_type_predicate(ctx, env, "context?", SEXP_CONTEXT);
@ -656,23 +700,28 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_accessors(ctx, env, SEXP_CND, 2, "cnd-fail", "cnd-fail-set!"); sexp_define_accessors(ctx, env, SEXP_CND, 2, "cnd-fail", "cnd-fail-set!");
sexp_define_accessors(ctx, env, SEXP_SET, 0, "set-var", "set-var-set!"); sexp_define_accessors(ctx, env, SEXP_SET, 0, "set-var", "set-var-set!");
sexp_define_accessors(ctx, env, SEXP_SET, 1, "set-value", "set-value-set!"); sexp_define_accessors(ctx, env, SEXP_SET, 1, "set-value", "set-value-set!");
sexp_define_accessors(ctx, env, SEXP_SET, 2, "set-source", "set-source-set!");
sexp_define_accessors(ctx, env, SEXP_REF, 0, "ref-name", "ref-name-set!"); sexp_define_accessors(ctx, env, SEXP_REF, 0, "ref-name", "ref-name-set!");
sexp_define_accessors(ctx, env, SEXP_REF, 1, "ref-cell", "ref-cell-set!"); sexp_define_accessors(ctx, env, SEXP_REF, 1, "ref-cell", "ref-cell-set!");
sexp_define_accessors(ctx, env, SEXP_SEQ, 0, "seq-ls", "seq-ls-set!"); sexp_define_accessors(ctx, env, SEXP_SEQ, 0, "seq-ls", "seq-ls-set!");
sexp_define_accessors(ctx, env, SEXP_LIT, 0, "lit-value", "lit-value-set!"); sexp_define_accessors(ctx, env, SEXP_LIT, 0, "lit-value", "lit-value-set!");
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 2, "bytecode-name", "bytecode-name-set!"); sexp_define_accessors(ctx, env, SEXP_BYTECODE, 0, "bytecode-name", "bytecode-name-set!");
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 3, "bytecode-literals", NULL); sexp_define_accessors(ctx, env, SEXP_BYTECODE, 1, "bytecode-literals", NULL);
sexp_define_accessors(ctx, env, SEXP_BYTECODE, 4, "bytecode-source", NULL); sexp_define_accessors(ctx, env, SEXP_BYTECODE, 2, "bytecode-source", NULL);
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 1, "exception-message", NULL); sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 1, "exception-message", NULL);
sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 4, "exception-source", NULL); sexp_define_accessors(ctx, env, SEXP_EXCEPTION, 4, "exception-source", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 0, "macro-procedure", NULL); sexp_define_accessors(ctx, env, SEXP_MACRO, 0, "macro-procedure", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 1, "macro-env", NULL); sexp_define_accessors(ctx, env, SEXP_MACRO, 1, "macro-env", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 2, "macro-source", NULL); sexp_define_accessors(ctx, env, SEXP_MACRO, 2, "macro-source", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 3, "macro-aux", "macro-aux-set!");
sexp_define_foreign(ctx, env, "make-procedure", 4, sexp_make_procedure_op);
sexp_define_foreign(ctx, env, "procedure-code", 1, sexp_get_procedure_code); sexp_define_foreign(ctx, env, "procedure-code", 1, sexp_get_procedure_code);
sexp_define_foreign(ctx, env, "procedure-vars", 1, sexp_get_procedure_vars); sexp_define_foreign(ctx, env, "procedure-vars", 1, sexp_get_procedure_vars);
sexp_define_foreign(ctx, env, "procedure-arity", 1, sexp_get_procedure_arity); sexp_define_foreign(ctx, env, "procedure-arity", 1, sexp_get_procedure_arity);
sexp_define_foreign(ctx, env, "procedure-variadic?", 1, sexp_get_procedure_variadic_p); sexp_define_foreign(ctx, env, "procedure-variadic?", 1, sexp_get_procedure_variadic_p);
sexp_define_foreign(ctx, env, "procedure-variable-transformer?", 1, sexp_get_procedure_variable_transformer_p);
sexp_define_foreign(ctx, env, "procedure-flags", 1, sexp_get_procedure_flags); sexp_define_foreign(ctx, env, "procedure-flags", 1, sexp_get_procedure_flags);
sexp_define_foreign(ctx, env, "make-variable-transformer", 1, sexp_make_variable_transformer_op);
sexp_define_foreign(ctx, env, "copy-lambda", 1, sexp_copy_lambda); sexp_define_foreign(ctx, env, "copy-lambda", 1, sexp_copy_lambda);
sexp_define_foreign_opt(ctx, env, "make-lambda", 4, sexp_make_lambda_op, SEXP_NULL); sexp_define_foreign_opt(ctx, env, "make-lambda", 4, sexp_make_lambda_op, SEXP_NULL);
sexp_define_foreign_opt(ctx, env, "make-cnd", 3, sexp_make_cnd_op, SEXP_VOID); sexp_define_foreign_opt(ctx, env, "make-cnd", 3, sexp_make_cnd_op, SEXP_VOID);
@ -695,6 +744,8 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_foreign(ctx, env, "opcode-param-type", 2, sexp_get_opcode_param_type); sexp_define_foreign(ctx, env, "opcode-param-type", 2, sexp_get_opcode_param_type);
sexp_define_foreign(ctx, env, "port-line", 1, sexp_get_port_line); sexp_define_foreign(ctx, env, "port-line", 1, sexp_get_port_line);
sexp_define_foreign(ctx, env, "port-line-set!", 2, sexp_set_port_line); sexp_define_foreign(ctx, env, "port-line-set!", 2, sexp_set_port_line);
sexp_define_foreign(ctx, env, "port-source?", 1, sexp_get_port_sourcep);
sexp_define_foreign(ctx, env, "port-source?-set!", 2, sexp_set_port_sourcep);
sexp_define_foreign(ctx, env, "type-of", 1, sexp_type_of); sexp_define_foreign(ctx, env, "type-of", 1, sexp_type_of);
sexp_define_foreign(ctx, env, "type-name", 1, sexp_type_name_op); sexp_define_foreign(ctx, env, "type-name", 1, sexp_type_name_op);
sexp_define_foreign(ctx, env, "type-cpl", 1, sexp_type_cpl_op); sexp_define_foreign(ctx, env, "type-cpl", 1, sexp_type_cpl_op);
@ -712,7 +763,7 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_foreign(ctx, env, "core-code", 1, sexp_core_code_op); sexp_define_foreign(ctx, env, "core-code", 1, sexp_core_code_op);
sexp_define_foreign(ctx, env, "object-size", 1, sexp_object_size); sexp_define_foreign(ctx, env, "object-size", 1, sexp_object_size);
sexp_define_foreign(ctx, env, "immutable?", 1, sexp_immutablep_op); sexp_define_foreign(ctx, env, "immutable?", 1, sexp_immutablep_op);
sexp_define_foreign(ctx, env, "make-immutable!", 1, sexp_make_immutable_op); sexp_define_foreign(ctx, env, "immutable-string", 1, sexp_immutable_string_op);
sexp_define_foreign_opt(ctx, env, "integer->immediate", 2, sexp_integer_to_immediate, SEXP_FALSE); sexp_define_foreign_opt(ctx, env, "integer->immediate", 2, sexp_integer_to_immediate, SEXP_FALSE);
sexp_define_foreign_opt(ctx, env, "object->integer", 1, sexp_object_to_integer, SEXP_FALSE); sexp_define_foreign_opt(ctx, env, "object->integer", 1, sexp_object_to_integer, SEXP_FALSE);
sexp_define_foreign(ctx, env, "gc", 0, sexp_gc_op); sexp_define_foreign(ctx, env, "gc", 0, sexp_gc_op);
@ -721,6 +772,7 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
sexp_define_foreign(ctx, env, "%set-atomic!", 1, sexp_set_atomic); sexp_define_foreign(ctx, env, "%set-atomic!", 1, sexp_set_atomic);
#endif #endif
sexp_define_foreign(ctx, env, "%thread-interrupt!", 1, sexp_thread_interrupt);
sexp_define_foreign(ctx, env, "thread-list", 0, sexp_thread_list); sexp_define_foreign(ctx, env, "thread-list", 0, sexp_thread_list);
sexp_define_foreign_opt(ctx, env, "string-contains", 3, sexp_string_contains, sexp_make_string_cursor(0)); sexp_define_foreign_opt(ctx, env, "string-contains", 3, sexp_string_contains, sexp_make_string_cursor(0));
sexp_define_foreign(ctx, env, "string-cursor-copy!", 5, sexp_string_cursor_copy); sexp_define_foreign(ctx, env, "string-cursor-copy!", 5, sexp_string_cursor_copy);
@ -730,5 +782,11 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_foreign(ctx, env, "setenv", 2, sexp_setenv); sexp_define_foreign(ctx, env, "setenv", 2, sexp_setenv);
sexp_define_foreign(ctx, env, "unsetenv", 1, sexp_unsetenv); sexp_define_foreign(ctx, env, "unsetenv", 1, sexp_unsetenv);
sexp_define_foreign(ctx, env, "abort", 1, sexp_abort); sexp_define_foreign(ctx, env, "abort", 1, sexp_abort);
sexp_gc_preserve2(ctx, sym, str);
sym = sexp_intern(ctx, "chibi-version", -1);
str = sexp_c_string(ctx, sexp_version, -1);
sexp_immutablep(str) = 1;
sexp_env_define(ctx, env, sym, str);
sexp_gc_release2(ctx);
return SEXP_VOID; return SEXP_VOID;
} }

View file

@ -109,6 +109,34 @@
((opcode? x) (cond ((opcode-name x) => string->symbol) (else x))) ((opcode? x) (cond ((opcode-name x) => string->symbol) (else x)))
(else x))))) (else x)))))
;;> \section{Identifier Macros}
;;> \procedure{(make-variable-transformer proc)}
;;> Returns a new procedure wrapping the input procedure \var{proc}.
;;> The returned procedure, if used as a macro transformer procedure,
;;> can expand an instance of \scheme{set!} with its keyword on the
;;> left hand side.
;;> \macro{(identifier-syntax clauses ...)}
;;> A high-level form for creating identifier macros. See
;;> \hyperlink["http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_796"]{the R6RS specification.}
(define-syntax identifier-syntax
(syntax-rules (set!)
((_ template)
(syntax-rules ()
((_ xs (... ...))
(template xs (... ...)))
(x template)))
((_ (id_1 template_1) ((set! id_2 pattern) template_2))
(make-variable-transformer
(syntax-rules (set!)
((set! id_2 pattern) template_2)
((id_1 xs (... ...)) (template_1 xs (... ...)))
(id_1 template_1))))))
;;> \section{Types} ;;> \section{Types}
;;> All objects have an associated type, and types may have parent ;;> All objects have an associated type, and types may have parent
@ -121,32 +149,32 @@
;;> used in the \scheme{match} \scheme{($ ...)} syntax. ;;> used in the \scheme{match} \scheme{($ ...)} syntax.
;;> \itemlist[ ;;> \itemlist[
;;> \item{\scheme{<object>} - the parent of all types} ;;> \item{\scheme{Object} - the parent of all types}
;;> \item{\scheme{<number>} - abstract numeric type} ;;> \item{\scheme{Number} - abstract numeric type}
;;> \item{\scheme{<bignum>} - arbitrary precision exact integers} ;;> \item{\scheme{Bignum} - arbitrary precision exact integers}
;;> \item{\scheme{<flonum>} - inexact real numbers} ;;> \item{\scheme{Flonum} - inexact real numbers}
;;> \item{\scheme{<integer>} - abstract integer type} ;;> \item{\scheme{Integer} - abstract integer type}
;;> \item{\scheme{<symbol>} - symbols} ;;> \item{\scheme{Symbol} - symbols}
;;> \item{\scheme{<char>} - character} ;;> \item{\scheme{Char} - character}
;;> \item{\scheme{<boolean>} - \scheme{#t} or \scheme{#f}} ;;> \item{\scheme{Boolean} - \scheme{#t} or \scheme{#f}}
;;> \item{\scheme{<string>} - strings of characters} ;;> \item{\scheme{String} - strings of characters}
;;> \item{\scheme{<byte-vector>} - uniform vector of octets} ;;> \item{\scheme{Byte-Vector} - uniform vector of octets}
;;> \item{\scheme{<pair>} - a \var{car} and \var{cdr}, the basis for lists} ;;> \item{\scheme{Pair} - a \var{car} and \var{cdr}, the basis for lists}
;;> \item{\scheme{<vector>} - vectors} ;;> \item{\scheme{Vector} - vectors}
;;> \item{\scheme{<opcode>} - a primitive opcode or C function} ;;> \item{\scheme{Opcode} - a primitive opcode or C function}
;;> \item{\scheme{<procedure>} - a closure} ;;> \item{\scheme{Procedure} - a closure}
;;> \item{\scheme{<bytecode>} - the compiled code for a closure} ;;> \item{\scheme{Bytecode} - the compiled code for a closure}
;;> \item{\scheme{<env>} - an environment structure} ;;> \item{\scheme{Env} - an environment structure}
;;> \item{\scheme{<macro>} - a macro object, usually not first-class} ;;> \item{\scheme{Macro} - a macro object, usually not first-class}
;;> \item{\scheme{<lam>} - a lambda AST type} ;;> \item{\scheme{Lam} - a lambda AST type}
;;> \item{\scheme{<cnd>} - an conditional AST type (i.e. \scheme{if})} ;;> \item{\scheme{Cnd} - an conditional AST type (i.e. \scheme{if})}
;;> \item{\scheme{<ref>} - a reference AST type} ;;> \item{\scheme{Ref} - a reference AST type}
;;> \item{\scheme{<set>} - a mutation AST type (i.e. \scheme{set!})} ;;> \item{\scheme{Set} - a mutation AST type (i.e. \scheme{set!})}
;;> \item{\scheme{<seq>} - a sequence AST type} ;;> \item{\scheme{Seq} - a sequence AST type}
;;> \item{\scheme{<lit>} - a literal AST type} ;;> \item{\scheme{Lit} - a literal AST type}
;;> \item{\scheme{<sc>} - a syntactic closure} ;;> \item{\scheme{Sc} - a syntactic closure}
;;> \item{\scheme{<context>} - a context object (including threads)} ;;> \item{\scheme{Context} - a context object (including threads)}
;;> \item{\scheme{<exception>} - an exception object} ;;> \item{\scheme{Exception} - an exception object}
;;> ] ;;> ]
;;> The following extended type predicates may also be used to test ;;> The following extended type predicates may also be used to test
@ -222,6 +250,8 @@
;;> \item{\scheme{(macro-procedure f)} - the macro procedure} ;;> \item{\scheme{(macro-procedure f)} - the macro procedure}
;;> \item{\scheme{(macro-env f)} - the environment the macro was defined in} ;;> \item{\scheme{(macro-env f)} - the environment the macro was defined in}
;;> \item{\scheme{(macro-source f)} - the source location the macro was defined in} ;;> \item{\scheme{(macro-source f)} - the source location the macro was defined in}
;;> \item{\scheme{(macro-aux f)} - custom auxiliary data stored with the macro}
;;> \item{\scheme{(macro-aux-set! f x)}}
;;> ] ;;> ]
;;> \subsection{Bytecode Objects} ;;> \subsection{Bytecode Objects}
@ -351,11 +381,29 @@
;;> Returns the interpretation of the integer \var{n} as ;;> Returns the interpretation of the integer \var{n} as
;;> an immediate object, useful for debugging. ;;> an immediate object, useful for debugging.
;;> \procedure{(string-contains str pat)} ;;> \procedure{(string-contains str pat [start])}
;;> Returns the first string cursor of \var{pat} in \var{str}, ;;> Returns the first string cursor of \var{pat} in \var{str},
;;> of \scheme{#f} if it's not found. ;;> of \scheme{#f} if it's not found.
(cond-expand
(safe-string-cursors
(define orig-string-contains string-contains)
(set! string-contains
(lambda (str pat . o)
(let ((res
(if (pair? o)
(orig-string-contains str pat (string-cursor-where (car o)))
(orig-string-contains str pat))))
(and res (make-string-cursor str res (string-size str)))))))
(else
))
;;> \procedure{(string-cursor-copy! dst src from start end)}
;;> Copies the characters from \var{src}[\var{start}..\var{end}]
;;> to \var{dst} starting at \var{from}.
;;> \procedure{(safe-setenv name value)} ;;> \procedure{(safe-setenv name value)}
;;> Equivalent to \scheme{setenv} but does nothing and returns ;;> Equivalent to \scheme{setenv} but does nothing and returns
@ -388,3 +436,7 @@
(else (else
(define-syntax atomically (define-syntax atomically
(syntax-rules () ((atomically . body) (begin . body)))))) (syntax-rules () ((atomically . body) (begin . body))))))
(define (thread-interrupt! thread)
(if (%thread-interrupt! thread)
(yield!)))

View file

@ -1,7 +1,8 @@
(define-library (chibi ast) (define-library (chibi ast)
(export (export
analyze optimize env-cell ast->sexp macroexpand type-of analyze optimize env-cell ast->sexp macroexpand identifier-syntax
type-of
Object Input-Port Output-Port Opcode Procedure Bytecode Macro Env Object Input-Port Output-Port Opcode Procedure Bytecode Macro Env
Number Bignum Flonum Integer Complex Char Boolean Number Bignum Flonum Integer Complex Char Boolean
Symbol String Byte-Vector Vector Pair File-Descriptor Symbol String Byte-Vector Vector Pair File-Descriptor
@ -20,17 +21,18 @@
lambda-source-set! lambda-source-set!
cnd-test cnd-pass cnd-fail cnd-test cnd-pass cnd-fail
cnd-test-set! cnd-pass-set! cnd-fail-set! cnd-test-set! cnd-pass-set! cnd-fail-set!
set-var set-value set-var-set! set-value-set! set-var set-value set-var-set! set-value-set! set-source set-source-set!
ref-name ref-cell ref-name-set! ref-cell-set! ref-name ref-cell ref-name-set! ref-cell-set!
seq-ls seq-ls-set! lit-value lit-value-set! seq-ls seq-ls-set! lit-value lit-value-set!
exception-kind exception-message exception-irritants exception-source exception-kind exception-message exception-irritants exception-source
opcode-name opcode-num-params opcode-return-type opcode-param-type opcode-name opcode-num-params opcode-return-type opcode-param-type
opcode-class opcode-code opcode-data opcode-variadic? opcode-class opcode-code opcode-data opcode-variadic? opcode?
macro-procedure macro-env macro-source macro-procedure macro-env macro-source macro-aux macro-aux-set!
procedure-code procedure-vars procedure-name procedure-name-set! procedure-code procedure-vars procedure-name procedure-name-set!
procedure-arity procedure-variadic? procedure-flags procedure-arity procedure-variadic? procedure-variable-transformer?
procedure-flags make-variable-transformer make-procedure procedure?
bytecode-name bytecode-literals bytecode-source bytecode-name bytecode-literals bytecode-source
port-line port-line-set! port-line port-line-set! port-source? port-source?-set!
extend-env env-parent env-parent-set! env-lambda env-lambda-set! extend-env env-parent env-parent-set! env-lambda env-lambda-set!
env-define! env-push! env-syntactic? env-syntactic?-set! core-code env-define! env-push! env-syntactic? env-syntactic?-set! core-code
type-name type-cpl type-parent type-slots type-num-slots type-name type-cpl type-parent type-slots type-num-slots
@ -39,7 +41,9 @@
atomically thread-list abort atomically thread-list abort
string-contains string-cursor-copy! errno integer->error-string string-contains string-cursor-copy! errno integer->error-string
flatten-dot update-free-vars! setenv unsetenv safe-setenv flatten-dot update-free-vars! setenv unsetenv safe-setenv
immutable? make-immutable!) immutable? immutable-string make-immutable!
thread-interrupt!
chibi-version)
(import (chibi)) (import (chibi))
(include-shared "ast") (include-shared "ast")
(include "ast.scm")) (include "ast.scm"))

View file

@ -0,0 +1,31 @@
(define-library (chibi binary-record-test)
(export run-tests)
(import (scheme base) (chibi binary-record) (chibi test))
(begin
(define-binary-record-type gif-header
(make: make-gif-header)
(pred: gif-header?)
(read: read-gif-header)
(write: write-gif-header)
(block:
"GIF89a"
(width (u16/le) gif-header-width)
(height (u16/le) gif-header-height)
(gct (u8) gif-header-gct)
(bgcolor (u8) gif-header-gbcolor)
(aspect-ratio (u8) gif-header-aspect-ratio)
))
(define (gif->bytevector gif)
(let ((out (open-output-bytevector)))
(write-gif-header gif out)
(get-output-bytevector out)))
(define (bytevector->gif bv)
(read-gif-header (open-input-bytevector bv)))
(define (run-tests)
(test-begin "(chibi binary-record)")
(let ((gif (make-gif-header 4096 2160 #xF7 1 2)))
(test #u8(#x47 #x49 #x46 #x38 #x39 #x61 0 #x10 #x70 #x08 #xF7 #x01 #x02)
(gif->bytevector gif))
(test gif (bytevector->gif (gif->bytevector gif))))
(test-end))))

View file

@ -1,6 +1,80 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; binary records ;; Binary Records
;;> \macro{(define-binary-record-type <name> [<bindings> ...] (block: <fields> ...))}
;;>
;;> Defines a new record type that supports serializing to and from
;;> binary ports. The generated procedures accept keyword-style
;;> arguments:
;;>
;;> \itemlist[
;;> \item{\scheme{(make: <constructor-name>)}}
;;> \item{\scheme{(pred: <predicate-name>)}}
;;> \item{\scheme{(read: <reader-name>)}}
;;> \item{\scheme{(write: <writer-name>)}}
;;> \item{\scheme{(block: <fields> ...)}}
;;> ]
;;>
;;> The fields are also similar to \scheme{define-record-type} but
;;> with an additional type:
;;>
;;> \scheme{(field (type args ...) getter setter)}
;;>
;;> Built-in types include:
;;>
;;> \itemlist[
;;> \item{\scheme{(u8)} - a single byte in [0, 255]}
;;> \item{\scheme{(u16/le)} - a little-endian short integer}
;;> \item{\scheme{(u16/be)} - a big-endian short integer}
;;> \item{\scheme{(fixed-string <length>)} - a fixed-length utf-8 string}
;;> \item{\scheme{(padded-string <length> (pad <pad-char>))} - a utf-8 string padded to a given length}
;;> \item{\scheme{(octal <length>)} - an integer in octal string format}
;;> \item{\scheme{(decimal <length>)} - an integer in decimal string format}
;;> \item{\scheme{(hexadecimal <length>)} - an integer in hexadecimal string format}
;;> ]
;;>
;;> In addition, the field can be a literal (char, string or
;;> bytevector), for instance as a file magic sequence or fixed
;;> separator. The fields (and any constants) are serialized in the
;;> order they appear in the block. For example, the header of a GIF
;;> file could be defined as:
;;>
;;> \example{
;;> (define-binary-record-type gif-header
;;> (make: make-gif-header)
;;> (pred: gif-header?)
;;> (read: read-gif-header)
;;> (write: write-gif-header)
;;> (block:
;;> "GIF89a"
;;> (width (u16/le) gif-header-width)
;;> (height (u16/le) gif-header-height)
;;> (gct (u8) gif-header-gct)
;;> (bgcolor (u8) gif-header-gbcolor)
;;> (aspect-ratio (u8) gif-header-aspect-ratio)
;;> ))
;;> }
;;>
;;> For a more complex example see the \scheme{(chibi tar)}
;;> implementation.
;;>
;;> The binary type itself is a macro used to expand to a predicate
;;> and reader/writer procedures, which can be defined with
;;> \scheme{define-binary-type}. For example,
;;>
;;> \example{
;;> (define-binary-type (u8)
;;> (lambda (x) (and (exact-integer? x) (<= 0 x 255)))
;;> read-u8
;;> write-u8)
;;> }
(define-syntax define-binary-record-type
(syntax-rules ()
((define-binary-record-type name x ...)
(defrec (x ...) name hidden-make hidden-pred hidden-read hidden-write
() () ()))))
(define-syntax defrec (define-syntax defrec
(syntax-rules (make: pred: read: write: block:) (syntax-rules (make: pred: read: write: block:)
@ -84,9 +158,3 @@
((defrec ((block:) . rest) n m p r w b f s) ((defrec ((block:) . rest) n m p r w b f s)
(defrec rest n m p r w b f s)) (defrec rest n m p r w b f s))
)) ))
(define-syntax define-binary-record-type
(syntax-rules ()
((define-binary-record-type name x ...)
(defrec (x ...) name hidden-make hidden-pred hidden-read hidden-write
() () ()))))

View file

@ -8,6 +8,26 @@
(cond-expand (cond-expand
((library (srfi 130)) (import (srfi 130))) ((library (srfi 130)) (import (srfi 130)))
(else (import (srfi 13)))) (else (import (srfi 13))))
(cond-expand
;; ((library (auto))
;; (import (only (auto) make: pred: read: write: block:)))
(else
;; indirect exports for chicken
(export defrec define-auxiliary-syntax syntax-let-optionals*)
(begin
(define-syntax define-auxiliary-syntax
(syntax-rules ()
((define-auxiliary-syntax name)
(define-syntax name
(syntax-rules ()
((name . x)
(syntax-error "invalid use of auxiliary syntax"
(name . x))))))))
(define-auxiliary-syntax make:)
(define-auxiliary-syntax pred:)
(define-auxiliary-syntax read:)
(define-auxiliary-syntax write:)
(define-auxiliary-syntax block:))))
(export (export
;; interface ;; interface
define-binary-record-type define-binary-record-type
@ -16,9 +36,8 @@
octal decimal hexadecimal octal decimal hexadecimal
;; auxiliary syntax ;; auxiliary syntax
make: pred: read: write: block: make: pred: read: write: block:
;; indirect exports ;; new types
define-binary-type defrec define-auxiliary-syntax define-binary-type)
syntax-let-optionals*)
(include "binary-types.scm") (include "binary-types.scm")
(cond-expand (cond-expand
(chicken (chicken

View file

@ -85,20 +85,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; syntax ;; syntax
(define-syntax define-auxiliary-syntax
(syntax-rules ()
((define-auxiliary-syntax name)
(define-syntax name
(syntax-rules ()
((name . x)
(syntax-error "invalid use of auxilliary syntax" (name . x))))))))
(define-auxiliary-syntax make:)
(define-auxiliary-syntax pred:)
(define-auxiliary-syntax read:)
(define-auxiliary-syntax write:)
(define-auxiliary-syntax block:)
(define-syntax syntax-let-optionals* (define-syntax syntax-let-optionals*
(syntax-rules () (syntax-rules ()
((syntax-let-optionals* () type-args expr) ((syntax-let-optionals* () type-args expr)

View file

@ -0,0 +1,81 @@
(define-library (chibi bytevector-test)
(export run-tests)
(import (scheme base) (chibi bytevector) (chibi test))
(begin
(define floats
`(0.0 -1.0 #i1/3 1.192092896E-07 ,(+ 1 1.192092896E-07)
1e-23 -1e-23
3.40282346638528860e+38 -3.40282346638528860e+38
1.40129846432481707e-45 -1.40129846432481707e-45
3.14159265358979323846))
(define f32-le
'#u8(#x00 #x00 #x00 #x00 #x00 #x00 #x80 #xbf
#xab #xaa #xaa #x3e #x00 #x00 #x00 #x34
#x01 #x00 #x80 #x3f #x9a #x6d #x41 #x19
#x9a #x6d #x41 #x99 #xff #xff #x7f #x7f
#xff #xff #x7f #xff #x01 #x00 #x00 #x00
#x01 #x00 #x00 #x80 #xdb #x0f #x49 #x40))
(define f64-le
'#u8(#x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00
#x00 #x00 #x00 #x00 #x00 #x00 #xf0 #xbf
#x55 #x55 #x55 #x55 #x55 #x55 #xd5 #x3f
#x68 #x5f #x1c #x00 #x00 #x00 #x80 #x3e
#x00 #x00 #x00 #x20 #x00 #x00 #xf0 #x3f
#x51 #xb2 #x12 #x40 #xb3 #x2d #x28 #x3b
#x51 #xb2 #x12 #x40 #xb3 #x2d #x28 #xbb
#x00 #x00 #x00 #xe0 #xff #xff #xef #x47
#x00 #x00 #x00 #xe0 #xff #xff #xef #xc7
#x00 #x00 #x00 #x00 #x00 #x00 #xa0 #x36
#x00 #x00 #x00 #x00 #x00 #x00 #xa0 #xb6
#x18 #x2d #x44 #x54 #xfb #x21 #x09 #x40))
(define (run-tests)
(test-begin "bytevector")
(test-group "reading ieee"
(do ((ls floats (cdr ls))
(i 0 (+ i 4)))
((null? ls))
(test (car ls) (bytevector-ieee-single-native-ref f32-le i)))
(do ((ls floats (cdr ls))
(i 0 (+ i 8)))
((null? ls))
(test (car ls) (bytevector-ieee-double-native-ref f64-le i))))
(test-group "writing ieee"
(do ((ls floats (cdr ls))
(i 0 (+ i 4)))
((null? ls))
(let ((bv (make-bytevector 4 0)))
(bytevector-ieee-single-native-set! bv 0 (car ls))
(test (bytevector-copy f32-le i (+ i 4)) (values bv))))
(do ((ls floats (cdr ls))
(i 0 (+ i 8)))
((null? ls))
(let ((bv (make-bytevector 8 0)))
(bytevector-ieee-double-native-set! bv 0 (car ls))
;;(test (bytevector-copy f64-le i (+ i 8)) (values bv))
(test (car ls)
(bytevector-ieee-double-native-ref bv 0)))))
(test-group "ber integers"
(do ((ls '(0 1 128 16383 32767
18446744073709551615
340282366920938463463374607431768211456)
(cdr ls)))
((null? ls))
(let ((bv (make-bytevector 256)))
(do ((offsets '(0 1 27) (cdr offsets)))
((null? offsets))
(bytevector-ber-set! bv (car ls) (car offsets))
(test (car ls) (bytevector-ber-ref bv (car offsets)))))))
(test-end))))

View file

@ -33,6 +33,46 @@
(arithmetic-shift (bytevector-u8-ref bv (+ i 2)) 8) (arithmetic-shift (bytevector-u8-ref bv (+ i 2)) 8)
(bytevector-u8-ref bv (+ i 3)))) (bytevector-u8-ref bv (+ i 3))))
;;> \section{Bignum encodings}
;;> A BER compressed integer (X.209) is an unsigned integer in base 128,
;;> most significant digit first, where the high bit is set on all but the
;;> final (least significant) byte. Thus any size integer can be
;;> encoded, but the encoding is efficient and small integers don't take
;;> up any more space than they would in normal char/short/int encodings.
(define (bytevector-ber-ref bv . o)
(let ((end (if (and (pair? o) (pair? (cdr o)))
(cadr o)
(bytevector-length bv))))
(let lp ((acc 0) (i (if (pair? o) (car o) 0)))
(if (>= i end)
(error "unterminated ber integer in bytevector" bv)
(let ((b (bytevector-u8-ref bv i)))
(if (< b 128)
(+ acc b)
(lp (arithmetic-shift (+ acc (bitwise-and b 127)) 7)
(+ i 1))))))))
(define (bytevector-ber-set! bv n . o)
;;(assert (integer? number) (not (negative? number)))
(let ((start (if (pair? o) (car o) 0))
(end (if (and (pair? o) (pair? (cdr o)))
(cadr o)
(bytevector-length bv))))
(let lp ((n (arithmetic-shift n -7))
(ls (list (bitwise-and n 127))))
(if (zero? n)
(do ((i start (+ i 1))
(ls ls (cdr ls)))
((null? ls))
(if (>= i end)
(error "integer doesn't fit in bytevector as ber"
bv n start end)
(bytevector-u8-set! bv i (car ls))))
(lp (arithmetic-shift n -7)
(cons (+ 128 (bitwise-and n 127)) ls))))))
;;> \section{Integer conversion} ;;> \section{Integer conversion}
;;> Convert an unsigned integer \var{n} to a bytevector representing ;;> Convert an unsigned integer \var{n} to a bytevector representing

View file

@ -5,13 +5,37 @@
(export (export
bytevector-u16-ref-le bytevector-u16-ref-be bytevector-u16-ref-le bytevector-u16-ref-be
bytevector-u32-ref-le bytevector-u32-ref-be bytevector-u32-ref-le bytevector-u32-ref-be
bytevector-ber-ref bytevector-ber-set!
bytevector-pad-left bytevector-pad-left
integer->bytevector bytevector->integer integer->bytevector bytevector->integer
integer->hex-string hex-string->integer integer->hex-string hex-string->integer
bytevector->hex-string hex-string->bytevector) bytevector->hex-string hex-string->bytevector
(import (scheme base)) bytevector-ieee-single-ref
bytevector-ieee-single-native-ref
bytevector-ieee-single-set!
bytevector-ieee-single-native-set!
bytevector-ieee-double-ref
bytevector-ieee-double-native-ref
bytevector-ieee-double-set!
bytevector-ieee-double-native-set!
)
(import (scheme base) (scheme inexact))
(cond-expand
(big-endian
(begin
(define-syntax native-endianness
(syntax-rules () ((_) 'big)))))
(else
(begin
(define-syntax native-endianness
(syntax-rules () ((_) 'little))))))
(cond-expand (cond-expand
((library (srfi 151)) (import (srfi 151))) ((library (srfi 151)) (import (srfi 151)))
((library (srfi 33)) (import (srfi 33))) ((library (srfi 33)) (import (srfi 33)))
(else (import (srfi 60)))) (else (import (srfi 60))))
(include "bytevector.scm")) (include "bytevector.scm")
(cond-expand
(chibi
(import (except (scheme bytevector) bytevector-copy!)))
(else
(include "ieee-754.scm"))))

View file

@ -1,42 +1,42 @@
;; char-set:lower-case ;; char-set:lower-case
(define char-set:lower-case (immutable-char-set (%make-iset 97 122 #f #f #f))) (define char-set:lower-case (immutable-char-set (%make-iset 97 127 67108863 #f #f)))
;; char-set:upper-case ;; char-set:upper-case
(define char-set:upper-case (immutable-char-set (%make-iset 65 90 #f #f #f))) (define char-set:upper-case (immutable-char-set (%make-iset 65 127 67108863 #f #f)))
;; char-set:title-case ;; char-set:title-case
(define char-set:title-case (immutable-char-set (%make-iset 0 0 0 #f #f))) (define char-set:title-case (immutable-char-set (%make-iset 0 0 0 #f #f)))
;; char-set:letter ;; char-set:letter
(define char-set:letter (immutable-char-set (%make-iset 97 122 #f (%make-iset 65 90 #f #f #f) #f))) (define char-set:letter (immutable-char-set (%make-iset 65 127 288230371923853311 #f #f)))
;; char-set:punctuation ;; char-set:punctuation
(define char-set:punctuation (immutable-char-set (%make-iset 63 64 #f (%make-iset 44 47 #f (%make-iset 37 42 #f (%make-iset 33 35 #f #f #f) #f) (%make-iset 58 59 #f #f #f)) (%make-iset 123 123 #f (%make-iset 95 95 #f (%make-iset 91 93 #f #f #f) #f) (%make-iset 125 125 #f #f #f))))) (define char-set:punctuation (immutable-char-set (%make-iset 33 127 6189700203056200029306911735 #f #f)))
;; char-set:symbol ;; char-set:symbol
(define char-set:symbol (immutable-char-set (%make-iset 94 94 #f (%make-iset 43 43 #f (%make-iset 36 36 #f #f #f) (%make-iset 60 62 #f #f #f)) (%make-iset 124 124 #f (%make-iset 96 96 #f #f #f) (%make-iset 126 126 #f #f #f))))) (define char-set:symbol (immutable-char-set (%make-iset 36 127 1547425050547877224499904641 #f #f)))
;; char-set:blank ;; char-set:blank
(define char-set:blank (immutable-char-set (%make-iset 32 32 #f (%make-iset 9 9 #f #f #f) #f))) (define char-set:blank (immutable-char-set (%make-iset 9 32 8388609 #f #f)))
;; char-set:whitespace ;; char-set:whitespace
(define char-set:whitespace (immutable-char-set (%make-iset 32 32 #f (%make-iset 9 13 #f #f #f) #f))) (define char-set:whitespace (immutable-char-set (%make-iset 9 127 8388639 #f #f)))
;; char-set:digit ;; char-set:digit
(define char-set:digit (immutable-char-set (%make-iset 48 57 #f #f #f))) (define char-set:digit (immutable-char-set (%make-iset 48 57 #f #f #f)))
;; char-set:letter+digit ;; char-set:letter+digit
(define char-set:letter+digit (immutable-char-set (%make-iset 65 90 #f (%make-iset 48 57 #f #f #f) (%make-iset 97 122 #f #f #f)))) (define char-set:letter+digit (immutable-char-set (%make-iset 48 127 37778931308803301180415 #f #f)))
;; char-set:hex-digit ;; char-set:hex-digit
(define char-set:hex-digit (immutable-char-set (%make-iset 65 70 #f (%make-iset 48 57 #f #f #f) (%make-iset 97 102 #f #f #f)))) (define char-set:hex-digit (immutable-char-set (%make-iset 48 102 35465847073801215 #f #f)))
;; char-set:iso-control ;; char-set:iso-control
(define char-set:iso-control (immutable-char-set (%make-iset 127 127 #f (%make-iset 0 31 #f #f #f) #f))) (define char-set:iso-control (immutable-char-set (%make-iset 0 127 170141183460469231731687303720179073023 #f #f)))
;; char-set:graphic ;; char-set:graphic
(define char-set:graphic (immutable-char-set (%make-iset 33 126 #f #f #f))) (define char-set:graphic (immutable-char-set (%make-iset 33 127 19807040628566084398385987583 #f #f)))
;; char-set:printing ;; char-set:printing
(define char-set:printing (immutable-char-set (%make-iset 32 126 #f (%make-iset 9 13 #f #f #f) #f))) (define char-set:printing (immutable-char-set (%make-iset 9 127 332306998946228968225951765061697567 #f #f)))

File diff suppressed because one or more lines are too long

View file

@ -76,13 +76,18 @@
;;> Returns true iff \var{x} is a config object. ;;> Returns true iff \var{x} is a config object.
(define-record-type Config (define-record-type Config
(make-conf alist parent source timestamp) (%make-conf alist parent source timestamp)
conf? conf?
(alist conf-alist conf-alist-set!) (alist conf-alist conf-alist-set!)
(parent conf-parent conf-parent-set!) (parent conf-parent conf-parent-set!)
(source conf-source conf-source-set!) (source conf-source conf-source-set!)
(timestamp conf-timestamp conf-timestamp-set!)) (timestamp conf-timestamp conf-timestamp-set!))
(define (make-conf alist parent source timestamp)
(if (not (alist? alist))
(error "config requires an alist" alist)
(%make-conf alist parent source timestamp)))
(define (assq-tail key alist) (define (assq-tail key alist)
(let lp ((ls alist)) (let lp ((ls alist))
(and (pair? ls) (and (pair? ls)
@ -106,7 +111,12 @@
(else (lp (cdr ls) (cons (car ls) rev)))))) (else (lp (cdr ls) (cons (car ls) rev))))))
(define (read-from-file file . opt) (define (read-from-file file . opt)
(guard (exn (else (and (pair? opt) (car opt)))) (guard (exn
(else
(warn "couldn't load config:" file)
(print-exception exn)
(print-stack-trace exn)
(and (pair? opt) (car opt))))
(call-with-input-file file read))) (call-with-input-file file read)))
(define (alist? x) (define (alist? x)

View file

@ -10,6 +10,18 @@
;; This is only used for config verification, it's acceptable to ;; This is only used for config verification, it's acceptable to
;; substitute file existence for the stronger directory check. ;; substitute file existence for the stronger directory check.
(cond-expand (cond-expand
(chibi (import (only (chibi filesystem) file-directory?))) (chibi
(else (begin (define file-directory? file-exists?)))) (import (only (meta) warn))
(import (only (chibi) print-exception print-stack-trace))
(import (only (chibi filesystem) file-directory?)))
(else
(begin
(define file-directory? file-exists?)
(define (print-exception exn) (write exn))
(define (print-stack-trace . o) #f)
(define (warn msg . args)
(let ((err (current-error-port)))
(display msg err)
(for-each (lambda (x) (display " " err) (write x err)) args)
(newline err))))))
(include "config.scm")) (include "config.scm"))

98
lib/chibi/csv-test.sld Normal file
View file

@ -0,0 +1,98 @@
(define-library (chibi csv-test)
(import (scheme base)
(srfi 227)
(chibi csv)
(chibi test))
(export run-tests)
(begin
(define string->csv
(opt-lambda (str (reader (csv-read->list)))
(reader (open-input-string str))))
(define csv->string
(opt-lambda (row (writer (csv-writer)))
(let ((out (open-output-string)))
(writer row out)
(get-output-string out))))
(define (run-tests)
(test-begin "(chibi csv)")
(test-assert (eof-object? (string->csv "")))
(test '("1997" "Ford" "E350")
(string->csv "1997,Ford,E350"))
(test '("1997" "Ford" "E350")
(string->csv "\n1997,Ford,E350"))
(test '(" ")
(string->csv " \n1997,Ford,E350"))
(test '("" "")
(string->csv ",\n1997,Ford,E350"))
(test '("1997" "Ford" "E350")
(string->csv "\"1997\",\"Ford\",\"E350\""))
(test '("1997" "Ford" "E350" "Super, luxurious truck")
(string->csv "1997,Ford,E350,\"Super, luxurious truck\""))
(test '("1997" "Ford" "E350" "Super, \"luxurious\" truck")
(string->csv "1997,Ford,E350,\"Super, \"\"luxurious\"\" truck\""))
(test '("1997" "Ford" "E350" "Go get one now\nthey are going fast")
(string->csv "1997,Ford,E350,\"Go get one now
they are going fast\""))
(test '("1997" "Ford" "E350")
(string->csv
"# this is a comment\n1997,Ford,E350"
(csv-read->list
(csv-parser (csv-grammar '((comment-chars #\#)))))))
(let ((parser (csv-parser (csv-grammar '((quote-non-numeric? . #t))))))
(test-error (string->csv "1997,\"Ford\",E350" (csv-read->list parser)))
(test '(1997 "Ford" "E350")
(string->csv "1997,\"Ford\",\"E350\"" (csv-read->list parser))))
(test '("1997" "Fo\"rd" "E3\"50")
(string->csv "1997\tFo\"rd\tE3\"50"
(csv-read->list (csv-parser default-tsv-grammar))))
(test '#("1997" "Ford" "E350")
(string->csv "1997,Ford,E350" (csv-read->vector)))
(test '#("1997" "Ford" "E350")
(string->csv "1997,Ford,E350" (csv-read->fixed-vector 3)))
(test-error
(string->csv "1997,Ford,E350" (csv-read->fixed-vector 2)))
(let ((city-csv "Los Angeles,34°03N,118°15W
New York City,40°4246″N,74°0021″W
Paris,48°5124″N,2°2103″E"))
(test '(*TOP*
(row (col-0 "Los Angeles")
(col-1 "34°03N")
(col-2 "118°15W"))
(row (col-0 "New York City")
(col-1 "40°4246″N")
(col-2 "74°0021″W"))
(row (col-0 "Paris")
(col-1 "48°5124″N")
(col-2 "2°2103″E")))
((csv->sxml) (open-input-string city-csv)))
(test '(*TOP*
(city (name "Los Angeles")
(latitude "34°03N")
(longitude "118°15W"))
(city (name "New York City")
(latitude "40°4246″N")
(longitude "74°0021″W"))
(city (name "Paris")
(latitude "48°5124″N")
(longitude "2°2103″E")))
((csv->sxml 'city '(name latitude longitude))
(open-input-string city-csv)))
(test 3 (csv-num-rows default-csv-grammar (open-input-string city-csv)))
(test 0 (csv-num-rows default-csv-grammar (open-input-string "")))
(test 1 (csv-num-rows default-csv-grammar (open-input-string "x"))))
(test "1997,Ford,E350\n"
(csv->string '("1997" "Ford" "E350")))
(test "1997,Ford,E350,\"Super, luxurious truck\"\n"
(csv->string '("1997" "Ford" "E350" "Super, luxurious truck")))
(test "1997,Ford,E350,\"Super, \"\"luxurious\"\" truck\"\n"
(csv->string '("1997" "Ford" "E350" "Super, \"luxurious\" truck")))
(test "1997,Ford,E350,\"Go get one now\nthey are going fast\"\n"
(csv->string
'("1997" "Ford" "E350" "Go get one now\nthey are going fast")))
(test "1997,Ford,E350\n"
(csv->string '(1997 "Ford" E350)))
(test "1997,\"Ford\",\"E350\"\n"
(csv->string '(1997 "Ford" E350)
(csv-writer (csv-grammar '((quote-non-numeric? . #t))))))
(test-end))))

498
lib/chibi/csv.scm Normal file
View file

@ -0,0 +1,498 @@
;;> \section{CSV Grammars}
;;> CSV is a simple and compact format for tabular data, which has
;;> made it popular for a variety of tasks since the early days of
;;> computing. Unfortunately, there are many incompatible dialects
;;> requiring a grammar to specify all of the different options.
(define-record-type Csv-Grammar
(make-csv-grammar separator-chars quote-char quote-doubling-escapes? escape-char record-separator comment-chars quote-non-numeric?)
csv-grammar?
(separator-chars csv-grammar-separator-chars csv-grammar-separator-chars-set!)
(quote-char csv-grammar-quote-char csv-grammar-quote-char-set!)
(quote-doubling-escapes? csv-grammar-quote-doubling-escapes? csv-grammar-quote-doubling-escapes?-set!)
(escape-char csv-grammar-escape-char csv-grammar-escape-char-set!)
(record-separator csv-grammar-record-separator csv-grammar-record-separator-set!)
(comment-chars csv-grammar-comment-chars csv-grammar-comment-chars-set!)
(quote-non-numeric? csv-grammar-quote-non-numeric? csv-grammar-quote-non-numeric?-set!))
;; TODO: Other options to consider:
;; - strip-leading/trailing-whitespace?
;; - newlines-in-quotes?
;;> Creates a new CSV grammar from the given spec, an alist of symbols
;;> to values. The following options are supported:
;;>
;;> \itemlist[
;;> \item{\scheme{'separator-chars} - A non-empty list of characters used to delimit fields, by default \scheme{'(#\\,)} (comma-separated).}
;;> \item{\scheme{'quote-char} - A single character used to quote fields containing special characters, or \scheme{#f} to disable quoting, by default \scheme{#\\"} (a double-quote).}
;;> \item{\scheme{'quote-doubling-escapes?} - If true, two successive \scheme{quote-char}s within quotes are treated as a single escaped \scheme{quote-char} (default true).}
;;> \item{\scheme{'escape-char} - A single character used to escape characters within quoted fields, or \scheme{#f} to disable escapes, by default \scheme{#f} (no explicit escape, use quote doubling).}
;;> \item{\scheme{'record-separator} - A single character used to delimit the record (row), or one of the symbols \scheme{'cr}, \scheme{'crlf}, \scheme{'lf} or \scheme{'lax}. These correspond to sequences of carriage return and line feed, or in the case of \scheme{'lax} any of the other three sequences. Defaults to \scheme{'lax}.}
;;> \item{\scheme{'comment-chars} - A list of characters which if found at the start of a record indicate it is a comment, discarding all characters through to the next record-separator. Defaults to the empty list (no comments).}
;;> ]
;;>
;;> Example Gecos grammar:
;;>
;;> \example{
;;> (csv-grammar
;;> '((separator-chars #\\:)
;;> (quote-char . #f)))
;;> }
(define (csv-grammar spec)
(let ((grammar (make-csv-grammar '(#\,) #\" #t #f 'lax '() #f)))
(for-each
(lambda (x)
(case (car x)
((separator-chars delimiter)
(csv-grammar-separator-chars-set! grammar (cdr x)))
((quote-char)
(csv-grammar-quote-char-set! grammar (cdr x)))
((quote-doubling-escapes?)
(csv-grammar-quote-doubling-escapes?-set! grammar (cdr x)))
((escape-char)
(csv-grammar-escape-char-set! grammar (cdr x)))
((record-separator newline-type)
(let ((rec-sep
(case (cdr x)
((crlf lax) (cdr x))
((cr) #\return)
((lf) #\newline)
(else
(if (char? (cdr x))
(cdr x)
(error "invalid record-separator, expected a char or one of 'lax or 'crlf" (cdr x)))))))
(csv-grammar-escape-char-set! grammar (cdr x))))
((comment-chars)
(csv-grammar-comment-chars-set! grammar (cdr x)))
((quote-non-numeric?)
(csv-grammar-quote-non-numeric?-set! grammar (cdr x)))
(else
(error "unknown csv-grammar spec" x))))
spec)
grammar))
;;> The default CSV grammar for convenience, with all of the defaults
;;> from \scheme{csv-grammar}, i.e. comma-delimited with \scheme{#\"}
;;> for quoting, doubled to escape.
(define default-csv-grammar
(csv-grammar '()))
;;> The default TSV grammar for convenience, splitting fields only on
;;> tabs, with no quoting or escaping.
(define default-tsv-grammar
(csv-grammar '((separator-chars #\tab) (quote-char . #f))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;> \section{CSV Parsers}
;;> Parsers are low-level utilities to perform operations on records a
;;> field at a time. You generally want to work with readers, which
;;> build on this to build records into familiar data structures.
;;> Parsers follow the rules of a grammar to parse a single CSV
;;> record, possible comprised of multiple fields. A parser is a
;;> procedure of three arguments which performs a fold operation over
;;> the fields of the record. The parser signature is:
;;> \scheme{(parser kons knil in)}, where \scheme{kons} itself is
;;> a procedure of three arguments: \scheme{(proc acc index field)}.
;;> \scheme{proc} is called on each field of the record, in order,
;;> along with its zero-based \scheme{index} and the accumulated
;;> result of the last call, starting with \scheme{knil}.
;;> Returns a new CSV parser for the given \var{grammar}. The parser
;;> by itself can be used to parse a record at a time.
;;>
;;> \example{
;;> (let ((parse (csv-parser)))
;;> (parse (lambda (vec i field) (vector-set! vec i (string->number field)) vec)
;;> (make-vector 3)
;;> (open-input-string "1,2,3")))
;;> }
(define csv-parser
(opt-lambda ((grammar default-csv-grammar))
(lambda (kons knil in)
(when (pair? (csv-grammar-comment-chars grammar))
(let lp ()
(when (memv (peek-char in) (csv-grammar-comment-chars grammar))
(csv-skip-line in grammar)
(lp))))
(let lp ((acc knil)
(index 0)
(quoted? #f)
(out (open-output-string)))
(define (get-field)
(let ((field (get-output-string out)))
(cond
((and (zero? index) (equal? field "")) field)
((and (csv-grammar-quote-non-numeric? grammar) (not quoted?))
(or (string->number field)
(error "unquoted field is not numeric" field)))
(else field))))
(define (finish-row)
(let ((field (get-field)))
(if (and (zero? index) (equal? field ""))
;; empty row, read again
(lp acc index #f out)
(kons acc index field))))
(let ((ch (read-char in)))
(cond
((eof-object? ch)
(let ((field (get-field)))
(if (and (zero? index) (equal? field ""))
;; no data
ch
(kons acc index field))))
((memv ch (csv-grammar-separator-chars grammar))
(lp (kons acc index (get-field))
(+ index 1)
#f
(open-output-string)))
((eqv? ch (csv-grammar-quote-char grammar))
;; TODO: Consider a strict mode to enforce no text
;; before/after the quoted text.
(csv-read-quoted in out grammar)
(lp acc index #t out))
((eqv? ch (csv-grammar-record-separator grammar))
(finish-row))
((and (eqv? ch #\return)
(memq (csv-grammar-record-separator grammar) '(crlf lax)))
(cond
((eqv? (peek-char in) #\newline)
(read-char in)
(finish-row))
((eq? (csv-grammar-record-separator grammar) 'lax)
(finish-row))
(else
(write-char ch out)
(lp acc (+ index 1) quoted? out))))
((and (eqv? ch #\newline)
(eq? (csv-grammar-record-separator grammar) 'lax))
(finish-row))
(else
(write-char ch out)
(lp acc index quoted? out))))))))
(define (csv-skip-line in grammar)
(let lp ()
(let ((ch (read-char in)))
(cond
((eof-object? ch))
((eqv? ch (csv-grammar-record-separator grammar)))
((and (eqv? ch #\newline)
(eq? (csv-grammar-record-separator grammar) 'lax)))
((and (eqv? ch #\return)
(memq (csv-grammar-record-separator grammar) '(crlf lax)))
(cond
((eqv? (peek-char in) #\newline) (read-char in))
((eq? (csv-grammar-record-separator grammar) 'lax))
(else (lp))))
(else (lp))))))
(define (csv-read-quoted in out grammar)
(let lp ()
(let ((ch (read-char in)))
(cond
((eof-object? ch)
(error "unterminated csv quote" (get-output-string out)))
((eqv? ch (csv-grammar-quote-char grammar))
(when (and (csv-grammar-quote-doubling-escapes? grammar)
(eqv? ch (peek-char in)))
(write-char (read-char in) out)
(lp)))
((eqv? ch (csv-grammar-escape-char grammar))
(write-char (read-char in) out)
(lp))
(else
;; TODO: Consider an option to disable newlines in quotes.
(write-char ch out)
(lp))))))
(define (csv-skip-quoted in grammar)
(let lp ()
(let ((ch (read-char in)))
(cond
((eof-object? ch)
(error "unterminated csv quote"))
((eqv? ch (csv-grammar-quote-char grammar))
(when (and (csv-grammar-quote-doubling-escapes? grammar)
(eqv? ch (peek-char in)))
(read-char in)
(lp)))
((eqv? ch (csv-grammar-escape-char grammar))
(read-char in)
(lp))
(else
(lp))))))
;;> Returns the number of rows in the input.
(define csv-num-rows
(opt-lambda ((grammar default-csv-grammar)
(in (current-input-port)))
(let lp ((num-rows 0) (start? #t))
(let ((ch (read-char in)))
(cond
((eof-object? ch) (if start? num-rows (+ num-rows 1)))
((eqv? ch (csv-grammar-quote-char grammar))
(csv-skip-quoted in grammar)
(lp num-rows #f))
((eqv? ch (csv-grammar-record-separator grammar))
(lp (+ num-rows 1) #f))
((and (eqv? ch #\return)
(memq (csv-grammar-record-separator grammar) '(crlf lax)))
(cond
((eqv? (peek-char in) #\newline)
(read-char in)
(lp (+ num-rows 1) #t))
((eq? (csv-grammar-record-separator grammar) 'lax)
(lp (+ num-rows 1) #t))
(else
(lp num-rows #f))))
((and (eqv? ch #\newline)
(eq? (csv-grammar-record-separator grammar) 'lax))
(lp (+ num-rows 1) #t))
(else
(lp num-rows #f)))))))
;;> \section{CSV Readers}
;;> A CSV reader reads a single record, returning some representation
;;> of it. You can either loop manually with these or pass them to
;;> one of the high-level utilities to operate on a whole CSV file at
;;> a time.
;;> The simplest reader, simply returns the field string values in
;;> order as a list.
;;>
;;> \example{
;;> ((csv-read->list) (open-input-string "foo,bar,baz"))
;;> }
(define csv-read->list
(opt-lambda ((parser (csv-parser)))
(opt-lambda ((in (current-input-port)))
(let ((res (parser (lambda (ls i field) (cons field ls)) '() in)))
(if (pair? res)
(reverse res)
res)))))
;;> The equivalent of \scheme{csv-read->list} but returns a vector.
;;>
;;> \example{
;;> ((csv-read->vector) (open-input-string "foo,bar,baz"))
;;> }
(define csv-read->vector
(opt-lambda ((parser (csv-parser)))
(let ((reader (csv-read->list parser)))
(opt-lambda ((in (current-input-port)))
(let ((res (reader in)))
(if (pair? res)
(list->vector res)
res))))))
;;> The same as \scheme{csv-read->vector} but requires the vector to
;;> be of a fixed size, and may be more efficient.
;;>
;;> \example{
;;> ((csv-read->fixed-vector 3) (open-input-string "foo,bar,baz"))
;;> }
(define csv-read->fixed-vector
(opt-lambda (size (parser (csv-parser)))
(opt-lambda ((in (current-input-port)))
(let ((res (make-vector size)))
(let ((len (parser (lambda (prev-i i field) (vector-set! res i field) i)
0
in)))
(if (zero? len)
(eof-object)
res))))))
;;> Returns an SXML representation of the record, as a row with
;;> multiple named columns.
;;>
;;> \example{
;;> ((csv-read->sxml 'city '(name latitude longitude))
;;> (open-input-string "Tokyo,35°4123″N,139°4132″E"))
;;> }
(define csv-read->sxml
(opt-lambda ((row-name 'row)
(column-names
(lambda (i)
(string->symbol (string-append "col-" (number->string i)))))
(parser (csv-parser)))
(define (get-column-name i)
(if (procedure? column-names)
(column-names i)
(list-ref column-names i)))
(opt-lambda ((in (current-input-port)))
(let ((res (parser (lambda (ls i field)
`((,(get-column-name i) ,field) ,@ls))
(list row-name)
in)))
(if (pair? res)
(reverse res)
res)))))
;;> \section{CSV Utilities}
;;> A folding operation on records. \var{proc} is called successively
;;> on each row and the accumulated result.
;;>
;;> \example{
;;> (csv-fold
;;> (lambda (row acc) (cons (cadr (assq 'name (cdr row))) acc))
;;> '()
;;> (csv-read->sxml 'city '(name latitude longitude))
;;> (open-input-string
;;> "Tokyo,35°4123″N,139°4132″E
;;> Paris,48°5124″N,2°2103″E"))
;;> }
(define csv-fold
(opt-lambda (proc
knil
(reader (csv-read->list))
(in (current-input-port)))
(let lp ((acc knil))
(let ((row (reader in)))
(cond
((eof-object? row) acc)
(else (lp (proc row acc))))))))
;;> An iterator which simply calls \var{proc} on each record in the
;;> input in order.
;;>
;;> \example{
;;> (let ((count 0))
;;> (csv-for-each
;;> (lambda (row) (if (string->number (car row)) (set! count (+ 1 count))))
;;> (csv-read->list)
;;> (open-input-string
;;> "1,foo\\n2,bar\\nthree,baz\\n4,qux"))
;;> count)
;;> }
(define csv-for-each
(opt-lambda (proc
(reader (csv-read->list))
(in (current-input-port)))
(csv-fold (lambda (row acc) (proc row)) #f reader in)))
;;> Returns a list containing the result of calling \var{proc} on each
;;> element in the input.
;;>
;;> \example{
;;> (csv-map
;;> (lambda (row) (string->symbol (cadr row)))
;;> (csv-read->list)
;;> (open-input-string
;;> "1,foo\\n2,bar\\nthree,baz\\n4,qux"))
;;> }
(define csv-map
(opt-lambda (proc
(reader (csv-read->list))
(in (current-input-port)))
(reverse (csv-fold (lambda (row acc) (cons (proc row) acc)) '() reader in))))
;;> Returns a list of all of the read records in the input.
;;>
;;> \example{
;;> (csv->list
;;> (csv-read->list)
;;> (open-input-string
;;> "1,foo\\n2,bar\\nthree,baz\\n4,qux"))
;;> }
(define csv->list
(opt-lambda ((reader (csv-read->list))
(in (current-input-port)))
(csv-map (lambda (row) row) reader in)))
;;> Returns an SXML representation of the CSV.
;;>
;;> \example{
;;> ((csv->sxml 'city '(name latitude longitude))
;;> (open-input-string
;;> "Tokyo,35°4123″N,139°4132″E
;;> Paris,48°5124″N,2°2103″E"))
;;> }
(define csv->sxml
(opt-lambda ((row-name 'row)
(column-names
(lambda (i)
(string->symbol (string-append "col-" (number->string i)))))
(parser (csv-parser)))
(opt-lambda ((in (current-input-port)))
(cons '*TOP*
(csv->list (csv-read->sxml row-name column-names parser) in)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;> \section{CSV Writers}
(define (write->string obj)
(let ((out (open-output-string)))
(write obj out)
(get-output-string out)))
(define (csv-grammar-char-needs-quoting? grammar ch)
(or (eqv? ch (csv-grammar-quote-char grammar))
(eqv? ch (csv-grammar-escape-char grammar))
(memv ch (csv-grammar-separator-chars grammar))
(eqv? ch (csv-grammar-record-separator grammar))
(memv ch '(#\newline #\return))))
(define (csv-write-quoted obj out grammar)
(let ((in (open-input-string (if (string? obj) obj (write->string obj)))))
(write-char (csv-grammar-quote-char grammar) out)
(let lp ()
(let ((ch (read-char in)))
(cond
((eof-object? ch))
((or (eqv? ch (csv-grammar-quote-char grammar))
(eqv? ch (csv-grammar-escape-char grammar)))
(cond
((and (csv-grammar-quote-doubling-escapes? grammar)
(eqv? ch (csv-grammar-quote-char grammar)))
(write-char ch out))
((csv-grammar-escape-char grammar)
=> (lambda (esc) (write-char esc out)))
(else (error "no quote defined for" ch grammar)))
(write-char ch out)
(lp))
(else
(write-char ch out)
(lp)))))
(write-char (csv-grammar-quote-char grammar) out)))
(define csv-writer
(opt-lambda ((grammar default-csv-grammar))
(opt-lambda (row (out (current-output-port)))
(let lp ((ls row) (first? #t))
(when (pair? ls)
(unless first?
(write-char (car (csv-grammar-separator-chars grammar)) out))
(if (or (and (csv-grammar-quote-non-numeric? grammar)
(not (number? (car ls))))
(and (string? (car ls))
(string-any
(lambda (ch) (csv-grammar-char-needs-quoting? grammar ch))
(car ls)))
(and (not (string? (car ls)))
(not (number? (car ls)))
(not (symbol? (car ls)))))
(csv-write-quoted (car ls) out grammar)
(display (car ls) out))
(lp (cdr ls) #f)))
(write-string
(case (csv-grammar-record-separator grammar)
((crlf) "\r\n")
((lf lax) "\n")
((cr) "\r")
(else (string (csv-grammar-record-separator grammar))))
out))))
(define csv-write
(opt-lambda ((writer (csv-writer)))
(opt-lambda (rows (out (current-output-port)))
(for-each
(lambda (row) (writer row out))
rows))))

11
lib/chibi/csv.sld Normal file
View file

@ -0,0 +1,11 @@
(define-library (chibi csv)
(import (scheme base) (scheme write) (srfi 130) (srfi 227))
(export csv-grammar csv-parser csv-grammar?
default-csv-grammar default-tsv-grammar
csv-read->list csv-read->vector csv-read->fixed-vector
csv-read->sxml csv-num-rows
csv-fold csv-map csv->list csv-for-each csv->sxml
csv-writer csv-write
csv-skip-line)
(include "csv.scm"))

63
lib/chibi/diff-test.sld Normal file
View file

@ -0,0 +1,63 @@
(define-library (chibi diff-test)
(import (scheme base) (chibi diff))
(export run-tests)
(cond-expand
(chibi (import (chibi test)))
(else
(import (scheme write))
;; inline (chibi test) to avoid circular dependencies in snow
;; installations
(begin
(define-syntax test
(syntax-rules ()
((test expect expr)
(test 'expr expect expr))
((test name expect expr)
(guard (exn (else (display "!\nERROR: ") (write name) (newline)
(write exn) (newline)))
(let* ((res expr)
(pass? (equal? expect expr)))
(display (if pass? "." "x"))
(cond
((not pass?)
(display "\nFAIL: ") (write name) (newline))))))))
(define (test-begin name)
(display name))
(define (test-end)
(newline)))))
(begin
(define (run-tests)
(test-begin "diff")
(test '((#\A 1 0) (#\C 2 2))
(lcs-with-positions '(#\G #\A #\C) '(#\A #\G #\C #\A #\T)))
(test '(#\A #\C)
(lcs '(#\G #\A #\C) '(#\A #\G #\C #\A #\T)))
(test '((#\G #\A #\C) (#\A #\G #\C #\A #\T) ((#\A 1 0) (#\C 2 2)))
(diff "GAC" "AGCAT" read-char))
(test '((#\A #\G #\C #\A #\T) (#\A #\G #\C #\A #\T)
((#\A 0 0) (#\G 1 1) (#\C 2 2) (#\A 3 3) (#\T 4 4)))
(diff "AGCAT" "AGCAT" read-char))
(test '((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\.
#\G #\A #\C #\. #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\.
#\A #\G #\C #\A #\T #\. #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
((#\0 0 0) (#\1 1 1) (#\2 2 2) (#\3 3 3) (#\4 4 4) (#\5 5 5)
(#\6 6 6) (#\7 7 7) (#\8 8 8) (#\9 9 9) (#\. 10 10)
(#\A 12 11) (#\C 13 13)
(#\. 14 16) (#\0 15 17) (#\1 16 18) (#\2 17 19) (#\3 18 20)
(#\4 19 21) (#\5 20 22) (#\6 21 23) (#\7 22 24) (#\8 23 25)
(#\9 24 26)))
(diff "0123456789.GAC.0123456789"
"0123456789.AGCAT.0123456789"
read-char))
(let ((d (diff "GAC" "AGCAT" read-char)))
(test " »G« AC"
(edits->string (car d) (car (cddr d)) 1))
(test "A «G» C «AT» "
(edits->string (cadr d) (car (cddr d)) 2))
(test "\x1b;[31mG\x1b;[39mAC"
(edits->string/color (car d) (car (cddr d)) 1))
(test "A\x1b;[32mG\x1b;[39mC\x1b;[32mAT\x1b;[39m"
(edits->string/color (cadr d) (car (cddr d)) 2)))
(test-end))))

279
lib/chibi/diff.scm Normal file
View file

@ -0,0 +1,279 @@
;; utility for lcs-with-positions
(define (max-seq . o)
(if (null? o)
(list 0 '())
(let loop ((a (car o)) (ls (cdr o)))
(if (null? ls)
a
(let ((b (car ls)))
(if (>= (car a) (car b))
(loop a (cdr ls))
(loop b (cdr ls))))))))
;;> Finds the Longest Common Subsequence between \var{a-ls} and
;;> \var{b-ls}, comparing elements with \var{eq} (default
;;> \scheme{equal?}. Returns this sequence as a list, using the
;;> elements from \var{a-ls}. Uses quadratic time and space.
(define (lcs a-ls b-ls . o)
(let ((eq (if (pair? o) (car o) equal?)))
(map car (lcs-with-positions a-ls b-ls eq))))
;;> Variant of \scheme{lcs} which returns the annotated sequence. The
;;> result is a list of the common elements, each represented as a
;;> list of 3 values: the element, the zero-indexed position in
;;> \var{a-ls} where the element occurred, and the position in
;;> \var{b-ls}.
(define (lcs-with-positions a-ls b-ls . o)
(let* ((eq (if (pair? o) (car o) equal?))
(a-len (+ 1 (length a-ls)))
(b-len (+ 1 (length b-ls)))
(results (make-vector (* a-len b-len) #f)))
(let loop ((a a-ls) (a-pos 0) (b b-ls) (b-pos 0))
;; cache this step if not already done
(let ((i (+ (* a-pos b-len) b-pos)))
(or (vector-ref results i)
(let ((res
(if (or (null? a) (null? b))
(list 0 '()) ;; base case
(let ((a1 (car a))
(b1 (car b))
(a-tail (loop (cdr a) (+ a-pos 1) b b-pos))
(b-tail (loop a a-pos (cdr b) (+ b-pos 1))))
(cond
((eq a1 b1)
;; match found, we either use it or we don't
(let* ((a-b-tail (loop (cdr a) (+ a-pos 1)
(cdr b) (+ b-pos 1)))
(a-b-res (list (+ 1 (car a-b-tail))
(cons (list a1 a-pos b-pos)
(cadr a-b-tail)))))
(max-seq a-b-res a-tail b-tail)))
(else
;; not a match
(max-seq a-tail b-tail)))))))
(vector-set! results i res)
res))))
(cadr (vector-ref results 0))))
(define (source->list x reader)
(port->list
reader
(cond ((port? x) x)
((string? x) (open-input-string x))
(else (error "don't know how to diff from:" x)))))
;;> Utility to run lcs on text. \var{a} and \var{b} can be strings or
;;> ports, which are tokenized into a sequence by calling \var{reader}
;;> until \var{eof-object} is found. Returns a list of three values,
;;> the sequences read from \var{a} and \var{b}, and the \scheme{lcs}
;;> result. Unless \var{minimal?} is set, we trim common
;;> prefixes/suffixes before computing the lcs.
(define (diff a b . o)
(let-optionals o ((reader read-line)
(eq equal?)
(optimal? #f))
(let ((a-ls (source->list a reader))
(b-ls (source->list b reader)))
(if optimal?
(list a-ls b-ls (lcs-with-positions a-ls b-ls eq))
(let lp1 ((i 0) (a a-ls) (b b-ls))
(cond
((or (null? a) (null? b)) ;; prefix or equal
(if (and (null? a) (null? b))
(let ((n-ls (iota (length a-ls)))) ;; equal
(list a-ls b-ls (map list a-ls n-ls n-ls)))
(list a-ls b-ls (lcs-with-positions a-ls b-ls eq))))
((eq (car a) (car b))
(lp1 (+ i 1) (cdr a) (cdr b)))
(else
(let lp2 ((j 0) (ra (reverse a)) (rb (reverse b)))
(cond
((or (null? ra) (null? rb)) ;; can't happen
(list a-ls b-ls (lcs-with-positions a-ls b-ls eq)))
((eq (car ra) (car rb))
(lp2 (+ j 1) (cdr ra) (cdr rb)))
(else
(let* ((a-ls2 (reverse ra))
(b-ls2 (reverse rb))
(a-left-len (+ i (length a-ls2)))
(b-left-len (+ i (length b-ls2))))
(list a-ls
b-ls
(append
(map (lambda (x i) (list x i i))
(take a-ls i)
(iota i))
(map (lambda (x)
(list (car x)
(+ i (cadr x))
(+ i (car (cddr x)))))
(lcs-with-positions a-ls2 b-ls2 eq))
(map (lambda (x i)
(list x (+ i a-left-len) (+ i b-left-len)))
(take-right a j)
(iota j))))))
)))))))))
;;> Utility to format the result of a \var{diff} to output port
;;> \var{out} (default \scheme{(current-output-port)}). Applies
;;> \var{writer} to successive diff chunks. \var{writer} should be a
;;> procedure of three arguments: \scheme{(writer subsequence type
;;> out). \var{subsequence} is a subsequence from the original input,
;;> \var{type} is a symbol indicating the type of diff: \scheme{'same}
;;> if this is part of the lcs, \scheme{'add} if it is unique to the
;;> second input, or \scheme{'remove} if it is unique to the first
;;> input. \var{writer} defaults to \scheme{write-line-diffs},
;;> assuming the default line diffs.
(define (write-diff diff . o)
(let-optionals o ((writer write-line-diffs)
(out (current-output-port)))
(let* ((a-ls (car diff))
(b-ls (cadr diff))
(d-ls (car (cddr diff))))
;; context diff
(let lp ((d d-ls) (a a-ls) (a-pos 0) (b b-ls) (b-pos 0))
(unless (null? d)
(let* ((d1 (car d))
(a-off (cadr d1))
(a-skip (- a-off a-pos))
(b-off (car (cddr d1)))
(b-skip (- b-off b-pos)))
(let-values (((a-head a-tail) (split-at a a-skip))
((b-head b-tail) (split-at b b-skip)))
;; elements only in a have been removed
(if (pair? a-head)
(writer (cdr a-head) 'remove out))
;; elements only in b have been added
(if (pair? b-head)
(writer (cdr b-head) 'add out))
;; reprint this common element
(writer (list (car d1)) 'same out)
;; recurse
(lp (cdr d) a-tail a-off b-tail b-off))))))))
;;> Equivalent to \scheme{write-diff} but collects the output to a string.
(define (diff->string diff . o)
(let ((out (open-output-string)))
(write-diff diff (if (pair? o) (car o) write-line-diffs) out)
(get-output-string out)))
;;> The default writer for \scheme{write-diff}, annotates simple +/-
;;> prefixes for added/removed lines.
(define (write-line-diffs lines type out)
(for-each
(lambda (line)
(case type
((add)
(write-char #\+ out))
((remove)
(write-char #\- out))
((same)
(write-char #\space out))
(else (error "unknown diff type:" type)))
(write-string line out)
(newline out))
lines))
;;> A variant of \scheme{write-line-diffs} which adds red/green ANSI
;;> coloring to the +/- prefix.
(define (write-line-diffs/color lines type out)
(for-each
(lambda (line)
(case type
((add)
(write-string (green "+") out)
(write-string (green line) out))
((remove)
(write-string (red "-") out)
(write-string (red line) out))
((same)
(write-char #\space out)
(write-string line out))
(else (error "unknown diff type:" type)))
(newline out))
lines))
;;> A diff writer for sequences of characters (when a diff was
;;> generated with \scheme{read-char}), enclosing added characters in
;;> «...» brackets and removed characters in »...«.
(define (write-char-diffs chars type out)
(case type
((add)
(write-string " «" out)
(write-string (list->string chars) out)
(write-string "» " out))
((remove)
(write-string " »" out)
(write-string (list->string chars) out)
(write-string "« " out))
((same)
(write-string (list->string chars) out))
(else (error "unknown diff type:" type))))
;;> A diff writer for sequences of characters (when a diff was
;;> generated with \scheme{read-char}), formatting added characters in
;;> green and removed characters in red.
(define (write-char-diffs/color chars type out)
(case type
((add)
(write-string (green (list->string chars)) out))
((remove)
(write-string (red (list->string chars)) out))
((same)
(write-string (list->string chars) out))
(else (error "unknown diff type:" type))))
;;> Utility to format the result of a \scheme{diff} with respect to a
;;> single input sequence \var{ls}. \var{lcs} is the annotated common
;;> sequence from \scheme{diff} or \scheme{lcs-with-positions}, and
;;> \var{index} is the index (0 or 1, default 1) of \var{ls} in the
;;> original call. Since we have no information about the other
;;> input, we can only format what is the same and what is different,
;;> formatting the differences as either added (if \var{index} is 0)
;;> or removed (if \var{index} is 1).
(define (write-edits ls lcs . o)
(let-optionals o ((index 1)
(writer write-line-diffs)
(out (current-output-port)))
(let ((type (if (eq? index 1) 'remove 'add)))
(let lp ((ls ls) (lcs lcs) (buf '(#f)) (i 0))
(define (output ch type)
(cond
((eq? type (car buf))
(cons type (cons ch (cdr buf))))
(else
(if (car buf)
(writer (reverse (cdr buf)) (car buf) out))
(list type ch))))
(cond
((null? ls) (output #f 'done))
((null? lcs)
(lp (cdr ls) lcs (output (car ls) type) (+ i 1)))
((= i (list-ref (car lcs) index))
(lp (cdr ls) (cdr lcs) (output (car ls) 'same) (+ i 1)))
(else
(lp (cdr ls) lcs (output (car ls) type) (+ i 1))))))))
;;> Equivalent to \scheme{write-edits} but collects the output to a string.
(define (edits->string ls lcs . o)
(let-optionals o ((type 'add)
(writer (if (and (pair? ls) (char? (car ls)))
write-char-diffs
write-line-diffs)))
(let ((out (open-output-string)))
(write-edits ls lcs type writer out)
(get-output-string out))))
;;> Equivalent to \scheme{write-edits} but collects the output to a
;;> string and uses a color-aware writer by default. Note with a
;;> character diff this returns the original input string as-is, with
;;> only ANSI escapes indicating what changed.
(define (edits->string/color ls lcs . o)
(let-optionals o ((type 'add)
(writer (if (and (pair? ls) (char? (car ls)))
write-char-diffs/color
write-line-diffs/color)))
(let ((out (open-output-string)))
(write-edits ls lcs type writer out)
(get-output-string out))))

21
lib/chibi/diff.sld Normal file
View file

@ -0,0 +1,21 @@
(define-library (chibi diff)
(import (scheme base) (srfi 1) (chibi optional) (chibi term ansi))
(export lcs lcs-with-positions
diff write-diff diff->string
write-edits edits->string edits->string/color
write-line-diffs
write-line-diffs/color
write-char-diffs
write-char-diffs/color)
(cond-expand
(chibi (import (only (chibi io) port->list)))
(else
(begin
(define (port->list reader port)
(let lp ((res '()))
(let ((x (reader port)))
(if (eof-object? x)
(reverse res)
(lp (cons x res)))))))))
(include "diff.scm"))

View file

@ -22,13 +22,13 @@
static void sexp_write_pointer (sexp ctx, void *p, sexp out) { static void sexp_write_pointer (sexp ctx, void *p, sexp out) {
char buf[32]; char buf[32];
sprintf(buf, "%p", p); snprintf(buf, sizeof(buf), "%p", p);
sexp_write_string(ctx, buf, out); sexp_write_string(ctx, buf, out);
} }
static void sexp_write_integer (sexp ctx, sexp_sint_t n, sexp out) { static void sexp_write_integer (sexp ctx, sexp_sint_t n, sexp out) {
char buf[32]; char buf[32];
sprintf(buf, SEXP_PRId, n); snprintf(buf, sizeof(buf), SEXP_PRId, n);
sexp_write_string(ctx, buf, out); sexp_write_string(ctx, buf, out);
} }
@ -92,6 +92,12 @@ static sexp disasm (sexp ctx, sexp self, sexp bc, sexp out, int depth) {
if (off >= 0 && off < (int)sexp_bytecode_length(bc) && labels[off] == 0) if (off >= 0 && off < (int)sexp_bytecode_length(bc) && labels[off] == 0)
labels[off] = label++; labels[off] = label++;
case SEXP_OP_CALL: case SEXP_OP_CALL:
case SEXP_OP_FCALL0:
case SEXP_OP_FCALL1:
case SEXP_OP_FCALL2:
case SEXP_OP_FCALL3:
case SEXP_OP_FCALL4:
case SEXP_OP_FCALLN:
case SEXP_OP_CLOSURE_REF: case SEXP_OP_CLOSURE_REF:
case SEXP_OP_GLOBAL_KNOWN_REF: case SEXP_OP_GLOBAL_KNOWN_REF:
case SEXP_OP_GLOBAL_REF: case SEXP_OP_GLOBAL_REF:
@ -178,6 +184,7 @@ static sexp disasm (sexp ctx, sexp self, sexp bc, sexp out, int depth) {
case SEXP_OP_FCALL2: case SEXP_OP_FCALL2:
case SEXP_OP_FCALL3: case SEXP_OP_FCALL3:
case SEXP_OP_FCALL4: case SEXP_OP_FCALL4:
case SEXP_OP_FCALLN:
sexp_write_pointer(ctx, ((sexp*)ip)[0], out); sexp_write_pointer(ctx, ((sexp*)ip)[0], out);
sexp_write_char(ctx, ' ', out); sexp_write_char(ctx, ' ', out);
sexp_write(ctx, sexp_opcode_name(((sexp*)ip)[0]), out); sexp_write(ctx, sexp_opcode_name(((sexp*)ip)[0]), out);

View file

@ -25,4 +25,25 @@
(index (if (pair? o) (car o) 0)) (index (if (pair? o) (car o) 0))
(acc knil)) (acc knil))
(f p index fk))))) (f p index fk)))))
(test "hello" (ansi->sxml "hello"))
(test '(span "[ " (span (@ (style . "color:red")) "FAIL") "]")
(ansi->sxml "[ \x1B;[31mFAIL\x1B;[39m]"))
(test '(span (u "under " (span (@ (style . "color:red")) "red") " line"))
(ansi->sxml "\x1B;[4munder \x1B;[31mred\x1B;[39m line\x1B;[24m"))
(test '(span "plain "
(u "under "
(span (@ (style . "color:red")) "red")
" line"))
(ansi->sxml
"plain \x1B;[4munder \x1B;[31mred\x1B;[39m line\x1B;[24m"))
(test '(code "(" "string?" " "
(span (@ (class . "string")) "\"hello\"")
")")
(expand-docs '(scheme "(string? \"hello\")")
(make-default-doc-env)))
(test '(code "(" "string?" " "
(span (@ (class . "string")) "\"<hello>\"")
")")
(expand-docs '(scheme "(string? \"<hello>\")")
(make-default-doc-env)))
(test-end)))) (test-end))))

View file

@ -79,6 +79,95 @@
(define (sxml->sexp-list x) (define (sxml->sexp-list x)
(call-with-input-string (sxml-strip x) port->sexp-list)) (call-with-input-string (sxml-strip x) port->sexp-list))
;;> Replace ansi escape sequences in a \var{str} with the corresponding sxml.
(define (ansi->sxml str)
;; TODO: ick
(let ((start (string-cursor-start str))
(end (string-cursor-end str)))
(let lp1 ((from start)
(to start)
(res '()))
(define (lookup str)
(case (string->number str)
((0) '/) ((1) 'b) ((3) 'i) ((4) 'u) ((9) 's)
((22) '/b) ((23) '/i) ((24) '/u) ((29) '/s)
((30) 'black) ((31) 'red) ((32) 'green) ((33) 'yellow)
((34) 'blue) ((35) 'magenta) ((36) 'cyan) ((37) 'white)
((39) '/color)
(else #f)))
(define (collect from to res)
(if (string-cursor<? from to)
(cons (substring-cursor str from to) res)
res))
(define (finish)
(let ((ls (reverse (collect from to res))))
(if (and (= 1 (length ls)) (string? (car ls)))
(car ls)
(let lp1 ((ls ls) (cur '()) (res '()))
(define (close to)
(let lp2 ((ls cur) (tmp '()))
(cond
((null? ls)
(list '() `(,@(reverse tmp) ,@res)))
((eq? to (car ls))
(list (cdr ls) `((,to ,@tmp) ,@res)))
((and (eq? to 'color) (memq (car ls) '(b i u s)))
;; color close came to an open non-color
;; back off and leave this open
(let ((s `(,(car ls) ,@(take-while string? tmp)))
(tmp (drop-while string? tmp)))
(list `(,@(reverse tmp) ,@(reverse s)) res)))
((symbol? (car ls))
(lp2 (cdr ls) `((,(car ls) ,@(reverse tmp)))))
((and (pair? (car ls)) (eq? 'color to))
(lp2 (cdr ls) `((,@(car ls) ,@(reverse tmp)))))
((pair? (car ls))
(lp2 (cdr ls) `(,(car ls) ,@(reverse tmp))))
(else
(lp2 (cdr ls) `(,(car ls) ,@tmp))))))
(cond
((null? ls)
`(span ,@(reverse (cadr (close #f)))))
((and (string? (car ls)) (pair? cur))
(lp1 (cdr ls) (cons (car ls) cur) res))
((string? (car ls))
(lp1 (cdr ls) cur (cons (car ls) res)))
(else
(case (car ls)
((b i u s) (lp1 (cdr ls) (cons (car ls) cur) res))
((/b) (apply lp1 (cdr ls) (close 'b)))
((/i) (apply lp1 (cdr ls) (close 'i)))
((/u) (apply lp1 (cdr ls) (close 'u)))
((/s) (apply lp1 (cdr ls) (close 's)))
((/) (apply lp1 (cdr ls) (close 'all)))
((/color) (apply lp1 (cdr ls) (close 'color)))
(else
(let ((style (string-append "color:"
(symbol->string (car ls)))))
(lp1 (cdr ls)
(cons `(span (@ (style . ,style))) cur)
res))))))))))
(if (string-cursor>=? to end)
(finish)
(let ((c (string-cursor-ref str to))
(sc2 (string-cursor-next str to)))
(if (and (= 27 (char->integer c))
(string-cursor<? sc2 end)
(eqv? #\[ (string-cursor-ref str sc2)))
(let ((sc3 (string-cursor-next str sc2)))
(let lp2 ((sc4 sc3))
(if (string-cursor>=? sc4 end)
(finish)
(let ((c2 (string-cursor-ref str sc4))
(sc5 (string-cursor-next str sc4)))
(if (eqv? #\m c2)
(let ((code (lookup
(substring-cursor str sc3 sc4)))
(res (collect from to res)))
(lp1 sc5 sc5 (if code (cons code res) res)))
(lp2 sc5))))))
(lp1 from sc2 res)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;> Extract the literate Scribble docs for module \var{mod-name} and ;;> Extract the literate Scribble docs for module \var{mod-name} and
@ -88,9 +177,11 @@
(define (print-module-docs mod-name . o) (define (print-module-docs mod-name . o)
(let ((out (if (pair? o) (car o) (current-output-port))) (let ((out (if (pair? o) (car o) (current-output-port)))
(render (or (and (pair? o) (pair? (cdr o)) (cadr o)) (render (or (and (pair? o) (pair? (cdr o)) (cadr o))
sxml-display-as-text))) sxml-display-as-text))
(unexpanded?
(and (pair? o) (pair? (cdr o)) (pair? (cddr o)) (car (cddr o)))))
(render (render
(generate-docs ((if unexpanded? (lambda (sxml env) (fixup-docs sxml)) generate-docs)
`((title ,(write-to-string mod-name)) `((title ,(write-to-string mod-name))
,@(extract-module-docs mod-name #f)) ,@(extract-module-docs mod-name #f))
(make-module-doc-env mod-name)) (make-module-doc-env mod-name))
@ -176,6 +267,8 @@
(url . ,expand-url) (url . ,expand-url)
(hyperlink . ,expand-hyperlink) (hyperlink . ,expand-hyperlink)
(rawcode . code) (rawcode . code)
(pre . pre)
(bibitem . ,(lambda (x env) '())) ;; TODO: bibtex
(code . ,expand-code) (code . ,expand-code)
(codeblock . ,expand-codeblock) (codeblock . ,expand-codeblock)
(ccode (ccode
@ -274,14 +367,29 @@
(force (or (env-ref env 'example-env) (current-environment))))) (force (or (env-ref env 'example-env) (current-environment)))))
`(div `(div
,(expand-codeblock `(,(car x) language: scheme ,@(cdr x)) env) ,(expand-codeblock `(,(car x) language: scheme ,@(cdr x)) env)
(code ,(let* ((res-out (open-output-string))
(div (@ (class . "result")) (tmp-out (open-output-string))
,(call-with-output-string (tmp-err (open-output-string))
(lambda (out) (res (parameterize ((current-output-port tmp-out)
(protect (exn (#t (print-exception exn out))) (current-error-port tmp-err))
(let ((res (eval expr example-env))) (protect (exn (#t (print-exception exn tmp-err)))
(display "=> " out) (eval expr example-env)))))
(write res out)))))))))) (display "=> " res-out)
(write res res-out)
(let ((res-str (get-output-string res-out))
(out-str (get-output-string tmp-out))
(err-str (get-output-string tmp-err)))
`(,@(if (string-null? out-str)
'()
`((div (@ (class . "output")) (pre ,(ansi->sxml out-str)))))
,@(if (string-null? err-str)
'()
`((div (@ (class . "error")) (pre ,(ansi->sxml err-str)))))
,@(if (and (or (not (string-null? err-str))
(not (string-null? out-str)))
(eq? res (if #f #f)))
'()
`((div (@ (class . "result")) (code ,res-str))))))))))
(define (expand-example-import x env) (define (expand-example-import x env)
(eval `(import ,@(cdr x)) (eval `(import ,@(cdr x))
@ -321,7 +429,7 @@
sxml))) sxml)))
(define (expand-procedure sxml env) (define (expand-procedure sxml env)
((expand-section 'h3) `(,(car sxml) (rawcode ,@(cdr sxml))) env)) ((expand-section 'h4) `(,(car sxml) (rawcode ,@(cdr sxml))) env))
(define (expand-macro sxml env) (define (expand-macro sxml env)
(expand-procedure sxml env)) (expand-procedure sxml env))
@ -360,31 +468,45 @@
(define (get-contents x) (define (get-contents x)
(if (null? x) (if (null? x)
'() '()
(let ((d (caar x))) (let lp ((ls (cdr x))
(let lp ((ls (cdr x)) (parent (car (cdar x))) (kids '()) (res '())) (depth (caar x))
(parent (cadr (car x)))
(kids '())
(res '()))
(define (collect) (define (collect)
(cons `(li ,parent ,(get-contents (reverse kids))) res)) (cons `(li ,parent ,(get-contents (reverse kids))) res))
;; take a span of all sub-headers, recurse and repeat on next span ;; take a span of all sub-headers, recurse and repeat on next span
(cond (cond
((null? ls) ((null? ls)
`(ol ,@(reverse (collect)))) `(ol ,@(reverse (collect))))
((> (caar ls) d) ((> (caar ls) depth)
(lp (cdr ls) parent (cons (car ls) kids) res)) (lp (cdr ls) depth parent (cons (car ls) kids) res))
(else (else
(lp (cdr ls) (car (cdar ls)) '() (collect)))))))) (lp (cdr ls) (caar ls) (cadr (car ls)) '() (collect)))))))
(define (fix-header x) (define (fix-header x)
`(html (head ,@(cond ((assq 'title x) => (lambda (x) (list x))) `((!DOCTYPE html)
(html (head ,@(cond ((assq 'title x) => (lambda (x) (list x)))
(else '())) (else '()))
"\n" "\n"
(meta (@ (charset . "UTF-8")))
(style (@ (type . "text/css")) (style (@ (type . "text/css"))
" "
body {color: #000; background-color: #FFF} body {color: #000; background-color: #FFFFF8;}
div#menu {font-size: smaller; position: absolute; top: 50px; left: 0; width: 190px; height: 100%} div#menu {font-size: smaller; position: absolute; top: 50px; left: 0; width: 250px; height: 100%}
div#main {position: absolute; top: 0; left: 200px; width: 540px; height: 100%} div#menu a:link {text-decoration: none}
div#notes {position: relative; top: 2em; left: 570px; max-width: 200px; height: 0px; font-size: smaller;} div#main {font-size: large; position: absolute; top: 0; left: 260px; max-width: 590px; height: 100%}
div#notes {position: relative; top: 2em; left: 620px; width: 200px; height: 0px; font-size: smaller;}
div#footer {padding-bottom: 50px} div#footer {padding-bottom: 50px}
div#menu ol {list-style-position:inside; padding-left: 5px; margin-left: 5px}
div#menu ol ol {list-style: lower-alpha; padding-left: 15px; margin-left: 15px}
div#menu ol ol ol {list-style: decimal; padding-left: 5px; margin-left: 5px}
h2 { color: #888888; border-top: 3px solid #4588ba; }
h3 { color: #666666; border-top: 2px solid #4588ba; }
h4 { color: #222288; border-top: 1px solid #4588ba; }
.result { color: #000; background-color: #FFEADF; width: 100%; padding: 3px} .result { color: #000; background-color: #FFEADF; width: 100%; padding: 3px}
.output { color: #000; background-color: beige; width: 100%; padding: 3px}
.error { color: #000; background-color: #F0B0B0; width: 100%; padding: 3px}
.command { color: #000; background-color: #FFEADF; width: 100%; padding: 5px} .command { color: #000; background-color: #FFEADF; width: 100%; padding: 5px}
" "
,(highlight-style)) ,(highlight-style))
@ -403,7 +525,7 @@ div#footer {padding-bottom: 50px}
(cons 'h1 (cdr x)) (cons 'h1 (cdr x))
x)) x))
x) x)
(div (@ (id . "footer"))))))) (div (@ (id . "footer"))))))))
(define (fix-paragraphs x) (define (fix-paragraphs x)
(let lp ((ls x) (p '()) (res '())) (let lp ((ls x) (p '()) (res '()))
@ -573,8 +695,6 @@ div#footer {padding-bottom: 50px}
(('begin body0 ... body) (get-value-signature mod id proc name body)) (('begin body0 ... body) (get-value-signature mod id proc name body))
(else (get-procedure-signature mod id proc)))) (else (get-procedure-signature mod id proc))))
;; TODO: analyze and match on AST instead of making assumptions about
;; bindings
(define (get-signature mod id proc source form) (define (get-signature mod id proc source form)
(match form (match form
(('define (name args ...) . body) (('define (name args ...) . body)
@ -588,7 +708,11 @@ div#footer {padding-bottom: 50px}
(map (lambda (x) (cons name (cdr x))) (map (lambda (x) (cons name (cdr x)))
(filter external-clause? clause))) (filter external-clause? clause)))
(else (else
(get-procedure-signature mod id proc)))) (cond
((procedure-analysis proc mod)
=> (lambda (lam) (list (cons (lambda-name lam) (lambda-params lam)))))
(else
(get-procedure-signature mod id proc))))))
(define (get-ffi-signatures form) (define (get-ffi-signatures form)
(match form (match form
@ -601,6 +725,8 @@ div#footer {padding-bottom: 50px}
args))))) args)))))
(('define-c-const type (or (name _) name)) (('define-c-const type (or (name _) name))
(list (list 'const: type name))) (list (list 'const: type name)))
(('cond-expand (test . clauses) . rest)
(append-map get-ffi-signatures clauses))
(((or 'define-c-struct 'define-c-class 'define-c-type) name . rest) (((or 'define-c-struct 'define-c-class 'define-c-type) name . rest)
(let lp ((ls rest) (res '())) (let lp ((ls rest) (res '()))
(cond (cond
@ -629,7 +755,7 @@ div#footer {padding-bottom: 50px}
(let ((sections '(section subsection subsubsection subsubsubsection))) (let ((sections '(section subsection subsubsection subsubsubsection)))
(lambda (x) (lambda (x)
(cond ((memq x sections) => length) (cond ((memq x sections) => length)
((memq x '(procedure macro)) (section-number 'subsection)) ((memq x '(procedure macro)) (section-number 'subsubsection))
(else 0))))) (else 0)))))
(define (section>=? x n) (define (section>=? x n)
@ -687,9 +813,10 @@ div#footer {padding-bottom: 50px}
(write-to-string sig))) (write-to-string sig)))
(define (insert-signature orig-ls name sig) (define (insert-signature orig-ls name sig)
(let ((sig (if (pair? sig) sig (and name (list name)))))
(cond (cond
((not (pair? sig)) ((not (pair? sig))
orig-ls) '())
(else (else
(let ((name (let ((name
(cond (cond
@ -700,15 +827,16 @@ div#footer {padding-bottom: 50px}
(let lp ((ls orig-ls) (rev-pre '())) (let lp ((ls orig-ls) (rev-pre '()))
(cond (cond
((or (null? ls) ((or (null? ls)
(section>=? (car ls) (section-number 'subsection))) (section>=? (car ls) (section-number 'subsubsection)))
`(,@(reverse rev-pre) `(,@(reverse rev-pre)
,@(if (and (pair? ls) ,@(if (and (pair? ls)
(section-describes? (section-describes?
(extract-sxml '(subsection procedure macro) (extract-sxml
'(subsubsection procedure macro)
(car ls)) (car ls))
name)) name))
'() '()
`((subsection `((subsubsection
tag: ,(write-to-string name) tag: ,(write-to-string name)
(rawcode (rawcode
,@(if (and (pair? (car sig)) (eq? 'const: (caar sig))) ,@(if (and (pair? (car sig)) (eq? 'const: (caar sig)))
@ -717,7 +845,7 @@ div#footer {padding-bottom: 50px}
(intersperse (map write-signature sig) '(br))))))) (intersperse (map write-signature sig) '(br)))))))
,@ls)) ,@ls))
(else (else
(lp (cdr ls) (cons (car ls) rev-pre))))))))) (lp (cdr ls) (cons (car ls) rev-pre))))))))))
;;> Extract inline Scribble documentation (with the ;;> prefix) from ;;> Extract inline Scribble documentation (with the ;;> prefix) from
;;> the source file \var{file}, associating any signatures from the ;;> the source file \var{file}, associating any signatures from the
@ -725,17 +853,22 @@ div#footer {padding-bottom: 50px}
(define (extract-file-docs mod file all-defs strict? . o) (define (extract-file-docs mod file all-defs strict? . o)
;; extract (<file> . <line>) macro source or ;; extract (<file> . <line>) macro source or
;; (<offset> <file . <line>>) procedure source ;; (<offset> <file . <line>) procedure source or
;; ((<offset> <file . <line>) ...) bytecode sources
(define (source-line source) (define (source-line source)
(and (pair? source) (and (pair? source)
(if (string? (car source)) (cond
((string? (car source))
(and (equal? file (car source)) (and (equal? file (car source))
(number? (cdr source)) (number? (cdr source))
(cdr source)) (cdr source)))
((pair? (car source))
(source-line (car source)))
(else
(and (number? (car source)) (and (number? (car source))
(pair? (cdr source)) (pair? (cdr source))
(equal? file (cadr source)) (equal? file (cadr source))
(cddr source))))) (cddr source))))))
(define (read-to-paren in) (define (read-to-paren in)
(let lp1 ((res '())) (let lp1 ((res '()))
(let ((ch (peek-char in))) (let ((ch (peek-char in)))
@ -908,7 +1041,8 @@ div#footer {padding-bottom: 50px}
(define (extract-module-docs-from-files mod srcs includes stubs strict? exports . o) (define (extract-module-docs-from-files mod srcs includes stubs strict? exports . o)
(let ((dir (or (and (pair? o) (car o)) (module-dir mod))) (let ((dir (or (and (pair? o) (car o)) (module-dir mod)))
(defs (map (lambda (x) (defs (map (lambda (x)
(let ((val (and mod (module-ref mod x)))) (let ((val (and mod (protect (exn (else #f))
(module-ref mod x)))))
`(,x ,val ,(object-source val)))) `(,x ,val ,(object-source val))))
exports))) exports)))
(define (resolve-file file) (define (resolve-file file)

View file

@ -1,7 +1,7 @@
(define-library (chibi doc) (define-library (chibi doc)
(import (import
(except (chibi) eval) (scheme eval) (srfi 1) (srfi 95) (except (chibi) eval) (scheme eval) (srfi 1) (srfi 39) (srfi 95)
(chibi modules) (chibi ast) (chibi io) (chibi match) (chibi modules) (chibi ast) (chibi io) (chibi match)
(chibi time) (chibi filesystem) (chibi process) (chibi pathname) (chibi time) (chibi filesystem) (chibi process) (chibi pathname)
(chibi string) (chibi scribble) (chibi sxml) (chibi highlight) (chibi string) (chibi scribble) (chibi sxml) (chibi highlight)
@ -11,5 +11,6 @@
generate-docs expand-docs fixup-docs generate-docs expand-docs fixup-docs
extract-module-docs extract-module-file-docs extract-file-docs extract-module-docs extract-module-file-docs extract-file-docs
make-default-doc-env make-module-doc-env make-default-doc-env make-module-doc-env
get-optionals-signature) get-optionals-signature
ansi->sxml)
(include "doc.scm")) (include "doc.scm"))

View file

@ -0,0 +1,14 @@
(define-library (chibi edit-distance-test)
(export run-tests)
(import (scheme base) (chibi edit-distance) (chibi test))
(begin
(define (run-tests)
(test-begin "(chibi edit-distance)")
(test 0 (edit-distance "" ""))
(test 0 (edit-distance "same" "same"))
(test 1 (edit-distance "same" "game"))
(test 2 (edit-distance "same" "sand"))
(test 3 (edit-distance "kitten" "sitting"))
(test 3 (edit-distance "Saturday" "Sunday"))
(test-end))))

View file

@ -0,0 +1,52 @@
(define-library (chibi edit-distance)
(export edit-distance find-nearest-edits)
(import (scheme base) (srfi 130))
(begin
;;> Returns the levenshtein distance between s1 and s2 - a cost of
;;> 1 per character insertion, deletion or update. Runs in
;;> quadratic time and linear memory.
;;>
;;> \example{(edit-distance "same" "same")}
;;> \example{(edit-distance "same" "sand")}
;;> \example{(edit-distance "Saturday" "Sunday")}
(define (edit-distance s1 s2)
(let* ((len1 (string-length s1))
(len2 (string-length s2))
(vec (make-vector (+ len1 1) 0)))
(do ((i 0 (+ i 1)))
((> i len1))
(vector-set! vec i i))
(do ((i 1 (+ i 1))
(sc2 (string-cursor-start s2) (string-cursor-next s2 sc2)))
((> i len2)
(vector-ref vec len1))
(vector-set! vec 0 i)
(let ((ch2 (string-ref/cursor s2 sc2)))
(let lp ((j 1)
(sc1 (string-cursor-start s1))
(last-diag (- i 1)))
(when (<= j len1)
(let ((old-diag (vector-ref vec j))
(ch1 (string-ref/cursor s1 sc1)))
(vector-set! vec j (min (+ (vector-ref vec j) 1)
(+ (vector-ref vec (- j 1)) 1)
(+ last-diag
(if (eqv? ch1 ch2) 0 1))))
(lp (+ j 1)
(string-cursor-next s1 sc1)
old-diag))))))))
;;> Returns a list of strings in \var{str-ls} with the smallest
;;> edit distance to \var{str}, preserving order. If
;;> \var{max-distance} is provided and positive, only return if
;;> the edits are less or equal to that distance.
(define (find-nearest-edits str str-ls . o)
(let ((max-distance (if (pair? o) (car o) 1e100)))
(let lp ((ls str-ls) (dist (+ max-distance 1)) (res '()))
(if (null? ls)
(reverse res)
(let ((ed (edit-distance str (car ls))))
(cond
((= ed dist) (lp (cdr ls) dist (cons (car ls) res)))
((< ed dist) (lp (cdr ls) ed (list (car ls))))
(else (lp (cdr ls) dist res))))))))))

View file

@ -45,5 +45,5 @@
(lp (- i 1)))))))))) (lp (- i 1))))))))))
(else (else
(equal? a b)))) (equal? a b))))
(let ((res (equal?/bounded a b 100000 100000))) (let ((res (equal?/bounded a b 10000 10000)))
(and res (or (> res 0) (equiv? a b)) #t)))) (and res (or (> res 0) (equiv? a b)) #t))))

View file

@ -104,7 +104,9 @@
(define (with-directory dir thunk) (define (with-directory dir thunk)
(let ((pwd (current-directory))) (let ((pwd (current-directory)))
(dynamic-wind (dynamic-wind
(lambda () (change-directory dir)) (lambda ()
(if (not (change-directory dir))
(error "couldn't change directory" dir)))
thunk thunk
(lambda () (change-directory pwd))))) (lambda () (change-directory pwd)))))

View file

@ -33,7 +33,7 @@
open/append open/non-block open/append open/non-block
file-lock file-truncate file-lock file-truncate
file-is-readable? file-is-writable? file-is-executable? file-is-readable? file-is-writable? file-is-executable?
chmod is-a-tty?) chmod chown is-a-tty?)
(cond-expand (cond-expand
(chibi (chibi
(export lock/shared lock/exclusive lock/non-blocking lock/unlock) (export lock/shared lock/exclusive lock/non-blocking lock/unlock)

View file

@ -267,6 +267,12 @@
(define-c int chmod (string int)) (define-c int chmod (string int))
;;> Sets the file owner and group as in chown.
(cond-expand
((not windows)
(define-c int chown (string uid_t gid_t))))
;;> Returns \scheme{#t} if the given port of file descriptor ;;> Returns \scheme{#t} if the given port of file descriptor
;;> if backed by a TTY object, and \scheme{#f} otherwise. ;;> if backed by a TTY object, and \scheme{#f} otherwise.

View file

@ -121,10 +121,6 @@
(cond (cond
((eof-object? c) (reverse-list->string ls)) ((eof-object? c) (reverse-list->string ls))
((eqv? c term) (reverse-list->string (cons c ls))) ((eqv? c term) (reverse-list->string (cons c ls)))
((eqv? c #\<) (read-escaped in term `(#\; #\t #\l #\& ,@ls)))
;;((eqv? c #\>) (read-escaped in term `(#\; #\t #\g #\& ,@ls)))
((eqv? c #\&) (read-escaped in term `(#\; #\p #\m #\a #\& ,@ls)))
;;((eqv? c #\\) (read-escaped in term (cons (read-char in) (cons c ls))))
(else (read-escaped in term (cons c ls)))))) (else (read-escaped in term (cons c ls))))))
(define (read-to-eol in ls) (define (read-to-eol in ls)
@ -134,9 +130,6 @@
((eqv? c #\newline) (reverse-list->string (cons c ls))) ((eqv? c #\newline) (reverse-list->string (cons c ls)))
(else (read-to-eol in (cons c ls)))))) (else (read-to-eol in (cons c ls))))))
(define (html-escape str)
(call-with-input-string str (lambda (in) (read-escaped in #f '()))))
(define (collect str res) (define (collect str res)
(if (pair? str) (cons (reverse-list->string str) res) res)) (if (pair? str) (cons (reverse-list->string str) res) res))
@ -162,7 +155,8 @@
syntax-case parameterize module library require syntax-case parameterize module library require
require-extension use use-modules import import-immutable require-extension use use-modules import import-immutable
define-module select-module provide autoload export define-module select-module provide autoload export
only except rename prefix include include-shared only except rename prefix drop-prefix alias-for
include include-ci include-shared
condition-case guard protect cond-expand for with to by condition-case guard protect cond-expand for with to by
in-list in-lists in-string in-string-reverse in-list in-lists in-string in-string-reverse
in-vector in-vector-reverse in-file listing appending in-vector in-vector-reverse in-file listing appending

224
lib/chibi/ieee-754.scm Normal file
View file

@ -0,0 +1,224 @@
;;; Copyright (c) 2004-2018 by Alex Shinn.
;; Adapted from SRFI 56.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; syntax
(define-syntax combine
(syntax-rules ()
((combine) 0)
((combine b1) b1)
((combine b1 b2 b3 ...)
(combine (+ (arithmetic-shift b1 8) b2) b3 ...))))
(define-syntax bytes-u8-set-all!
(syntax-rules ()
((_) bv off i)
((_ bv off i b1) (bytevector-u8-set! bv (+ off i) b1))
((_ bv off i b1 b2 b3 ...)
(begin
(bytevector-u8-set! bv (+ off i) b1)
(bytes-u8-set-all! bv off (+ i 1) b2 b3 ...)))))
(define-syntax bytevector-u8-set-all!
(syntax-rules ()
((_ bvapp iapp b1 ...)
(let ((bv bvapp)
(i iapp))
(bytes-u8-set-all! bv i 0 b1 ...)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; reading floating point numbers
;; Inspired by Oleg's implementation from
;; http://okmij.org/ftp/Scheme/reading-IEEE-floats.txt
;; but removes mutations and magic numbers and allows for manually
;; specifying the endianness.
;;
;; See also
;; http://www.cs.auckland.ac.nz/~jham1/07.211/floats.html
;; and
;; http://babbage.cs.qc.edu/courses/cs341/IEEE-754references.html
;; as references to IEEE 754.
(define (bytevector-ieee-single-ref bytevector k endianness)
(define (mantissa expn b2 b3 b4)
(case expn
((255) ; special exponents
(if (zero? (combine b2 b3 b4)) (/ 1. 0.) (/ 0. 0.)))
((0) ; denormalized
(inexact (* (expt 2.0 (- 1 (+ 127 23))) (combine b2 b3 b4))))
(else
(inexact
(* (expt 2.0 (- expn (+ 127 23)))
(combine (+ b2 128) b3 b4)))))) ; hidden bit
(define (exponent b1 b2 b3 b4)
(if (> b2 127) ; 1st bit of b2 is low bit of expn
(mantissa (+ (* 2 b1) 1) (- b2 128) b3 b4)
(mantissa (* 2 b1) b2 b3 b4)))
(define (sign b1 b2 b3 b4)
(if (> b1 127) ; 1st bit of b1 is sign
(- (exponent (- b1 128) b2 b3 b4))
(exponent b1 b2 b3 b4)))
(let* ((b1 (bytevector-u8-ref bytevector (+ k 0)))
(b2 (bytevector-u8-ref bytevector (+ k 1)))
(b3 (bytevector-u8-ref bytevector (+ k 2)))
(b4 (bytevector-u8-ref bytevector (+ k 3))))
(if (eq? endianness 'big)
(sign b1 b2 b3 b4)
(sign b4 b3 b2 b1))))
(define (bytevector-ieee-single-native-ref bytevector k)
(bytevector-ieee-single-ref bytevector k (native-endianness)))
(define (bytevector-ieee-double-ref bytevector k endianness)
(define (mantissa expn b2 b3 b4 b5 b6 b7 b8)
(case expn
((255) ; special exponents
(if (zero? (combine b2 b3 b4 b5 b6 b7 b8)) (/ 1. 0.) (/ 0. 0.)))
((0) ; denormalized
(inexact (* (expt 2.0 (- 1 (+ 1023 52)))
(combine b2 b3 b4 b5 b6 b7 b8))))
(else
(inexact
(* (expt 2.0 (- expn (+ 1023 52)))
(combine (+ b2 16) b3 b4 b5 b6 b7 b8)))))) ; hidden bit
(define (exponent b1 b2 b3 b4 b5 b6 b7 b8)
(mantissa (bitwise-ior (arithmetic-shift b1 4) ; 7 bits
(arithmetic-shift b2 -4)) ; + 4 bits
(bitwise-and b2 #b1111)
b3 b4 b5 b6 b7 b8))
(define (sign b1 b2 b3 b4 b5 b6 b7 b8)
(if (> b1 127) ; 1st bit of b1 is sign
(- (exponent (- b1 128) b2 b3 b4 b5 b6 b7 b8))
(exponent b1 b2 b3 b4 b5 b6 b7 b8)))
(let* ((b1 (bytevector-u8-ref bytevector (+ k 0)))
(b2 (bytevector-u8-ref bytevector (+ k 1)))
(b3 (bytevector-u8-ref bytevector (+ k 2)))
(b4 (bytevector-u8-ref bytevector (+ k 3)))
(b5 (bytevector-u8-ref bytevector (+ k 4)))
(b6 (bytevector-u8-ref bytevector (+ k 5)))
(b7 (bytevector-u8-ref bytevector (+ k 6)))
(b8 (bytevector-u8-ref bytevector (+ k 7))))
(if (eq? endianness 'big)
(sign b1 b2 b3 b4 b5 b6 b7 b8)
(sign b8 b7 b6 b5 b4 b3 b2 b1))))
(define (bytevector-ieee-double-native-ref bytevector k)
(bytevector-ieee-double-ref bytevector k (native-endianness)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; writing floating point numbers
;; Underflow rounds down to zero as in IEEE-754, and overflow gets
;; written as +/- Infinity.
;; Break a real number down to a normalized mantissa and exponent.
;; Default base=2, mant-size=23 (52), exp-size=8 (11) for IEEE singles
;; (doubles).
;;
;; Note: This should never be used in practice, since it can be
;; implemented much faster in C. See decode-float in ChezScheme or
;; Gauche.
(define (call-with-mantissa&exponent num base mant-size exp-size proc)
(cond
((negative? num)
(call-with-mantissa&exponent (- num) base mant-size exp-size proc))
((zero? num) (proc 0 0))
(else
(let* ((bot (expt base mant-size))
(top (* base bot)))
(let loop ((n (inexact num)) (e 0))
(cond
((>= n top)
(loop (/ n base) (+ e 1)))
((< n bot)
(loop (* n base) (- e 1)))
(else
(proc (exact (round n)) e))))))))
(define (bytevector-ieee-single-set! bytevector k num endianness)
(define output
(if (eq? endianness 'big)
(lambda (b1 b2 b3 b4) (bytevector-u8-set-all! bytevector k b1 b2 b3 b4))
(lambda (b1 b2 b3 b4) (bytevector-u8-set-all! bytevector k b4 b3 b2 b1))))
(define (compute)
(call-with-mantissa&exponent num 2 23 8
(lambda (f e)
(let ((e0 (+ e 127 23)))
(cond
((negative? e0)
(let* ((f1 (exact (round (* f (expt 2 (- e0 1))))))
(b2 (bit-field f1 16 24)) ; mant:16-23
(b3 (bit-field f1 8 16)) ; mant:8-15
(b4 (bit-field f1 0 8))) ; mant:0-7
(output (if (negative? num) 128 0) b2 b3 b4)))
((> e0 255) ; infinity
(output (if (negative? num) 255 127) 128 0 0))
(else
(let* ((b0 (arithmetic-shift e0 -1))
(b1 (if (negative? num) (+ b0 128) b0)) ; sign + exp:1-7
(b2 (bitwise-ior
(if (odd? e0) 128 0) ; exp:0
(bit-field f 16 23))) ; + mant:16-23
(b3 (bit-field f 8 16)) ; mant:8-15
(b4 (bit-field f 0 8))) ; mant:0-7
(output b1 b2 b3 b4))))))))
(cond
((zero? num) (output 0 0 0 0))
((nan? num) (output #xff #xff #xff #xff))
(else (compute))))
(define (bytevector-ieee-single-native-set! bytevector k num)
(bytevector-ieee-single-set! bytevector k num (native-endianness)))
(define (bytevector-ieee-double-set! bytevector k num endianness)
(define output
(if (eq? endianness 'big)
(lambda (b1 b2 b3 b4 b5 b6 b7 b8)
(bytevector-u8-set-all! bytevector k b1 b2 b3 b4 b5 b6 b7 b8))
(lambda (b1 b2 b3 b4 b5 b6 b7 b8)
(bytevector-u8-set-all! bytevector k b8 b7 b6 b5 b4 b3 b2 b1))))
(define (compute)
(call-with-mantissa&exponent num 2 52 11
(lambda (f e)
(let ((e0 (+ e 1023 52)))
(cond
((negative? e0)
(let* ((f1 (exact (round (* f (expt 2 (- e0 1))))))
(b2 (bit-field f1 48 52))
(b3 (bit-field f1 40 48))
(b4 (bit-field f1 32 40))
(b5 (bit-field f1 24 32))
(b6 (bit-field f1 16 24))
(b7 (bit-field f1 8 16))
(b8 (bit-field f1 0 8)))
(output (if (negative? num) 128 0) b2 b3 b4 b5 b6 b7 b8)))
((> e0 4095) ; infinity
(output (if (negative? num) 255 127) 224 0 0 0 0 0 0))
(else
(let* ((b0 (bit-field e0 4 11))
(b1 (if (negative? num) (+ b0 128) b0))
(b2 (bitwise-ior (arithmetic-shift
(bit-field e0 0 4)
4)
(bit-field f 48 52)))
(b3 (bit-field f 40 48))
(b4 (bit-field f 32 40))
(b5 (bit-field f 24 32))
(b6 (bit-field f 16 24))
(b7 (bit-field f 8 16))
(b8 (bit-field f 0 8)))
(output b1 b2 b3 b4 b5 b6 b7 b8))))))))
(cond
((zero? num) (output 0 0 0 0 0 0 0 0))
((nan? num) (output #xff #xff #xff #xff #xff #xff #xff #xff))
(else (compute))))
(define (bytevector-ieee-double-native-set! bytevector k num)
(bytevector-ieee-double-set! bytevector k num (native-endianness)))
;; Local Variables:
;; eval: (put 'call-with-mantissa&exponent 'scheme-indent-function 4)
;; End:

View file

@ -134,6 +134,20 @@
(read-string 4096 in) (read-string 4096 in)
(read-line in))) (read-line in)))
(let ((bv (string->utf8 "日本語")))
(test #\日 (utf8-ref bv 0))
(test #\本 (utf8-ref bv 3))
(test #\語 (utf8-ref bv 6))
(test 3 (utf8-next bv 0 9))
(test 6 (utf8-next bv 3 9))
(test 9 (utf8-next bv 6 9))
(test #f (utf8-next bv 9 9))
(test 6 (utf8-prev bv 9 0))
(test 3 (utf8-prev bv 6 0))
(test 0 (utf8-prev bv 3 0))
(test #f (utf8-prev bv 0 0))
)
(test #u8(0 1 2) (test #u8(0 1 2)
(let ((in (bytevectors->input-port (list #u8(0 1 2))))) (let ((in (bytevectors->input-port (list #u8(0 1 2)))))
(read-bytevector 3 in))) (read-bytevector 3 in)))
@ -179,7 +193,7 @@
(lambda (bv start end) (lambda (bv start end)
(do ((i start (+ i 1)) (do ((i start (+ i 1))
(x 0 (+ x (bytevector-u8-ref bv i)))) (x 0 (+ x (bytevector-u8-ref bv i))))
((= i end) (set! sum x))))))) ((= i end) (set! sum (+ sum x))))))))
(write-bytevector #u8(0 1 2 3) out) (write-bytevector #u8(0 1 2 3) out)
(flush-output out) (flush-output out)
(test 6 sum) (test 6 sum)
@ -187,6 +201,19 @@
(flush-output out) (flush-output out)
(test 106 sum)) (test 106 sum))
(let* ((ls '())
(out (make-custom-output-port
(lambda (str start end)
(set! ls (cons (substring str start end) ls))
(- end start)))))
(display "Test1\n" out)
(flush-output out)
(display "Test2\n" out)
(flush-output out)
(display "Test3\n" out)
(flush-output out)
(test "Test1\nTest2\nTest3\n" (string-concatenate (reverse ls))))
(test "file-position" (test "file-position"
'(0 1 2) '(0 1 2)
(let* ((p (open-input-file "/etc/passwd")) (let* ((p (open-input-file "/etc/passwd"))

View file

@ -1,6 +1,6 @@
(define-library (chibi io) (define-library (chibi io)
(export read-string read-string! read-line write-line (export read-string read-string! read-line write-line %%read-line
port-fold port-fold-right port-map port-fold port-fold-right port-map
port->list port->string-list port->sexp-list port->list port->string-list port->sexp-list
port->string port->bytevector port->string port->bytevector
@ -14,7 +14,8 @@
make-filtered-output-port make-filtered-input-port make-filtered-output-port make-filtered-input-port
string-count-chars string-count-chars
open-input-bytevector open-output-bytevector get-output-bytevector open-input-bytevector open-output-bytevector get-output-bytevector
string->utf8 utf8->string string->utf8 string->utf8! string-offset utf8->string utf8->string!
utf8-ref utf8-next utf8-prev
write-string write-u8 read-u8 peek-u8 send-file write-string write-u8 read-u8 peek-u8 send-file
is-a-socket? is-a-socket?
call-with-input-file call-with-output-file) call-with-input-file call-with-output-file)

View file

@ -9,25 +9,10 @@
(call-with-input-string " " (call-with-input-string " "
(lambda (in) (read-char in) (read-char in)))) (lambda (in) (read-char in) (read-char in))))
;; Copy whole characters from the given cursor positions.
;; Return the src cursor position of the next unwritten char,
;; which may be before `to' if the char would overflow.
;; Now provided as a primitive from (chibi ast).
;; (define (string-cursor-copy! dst start src from to)
;; (let lp ((i from)
;; (j (string-cursor->index dst start)))
;; (let ((i2 (string-cursor-next src i)))
;; (cond ((> i2 to) i)
;; (else
;; (string-set! dst j (string-cursor-ref src i))
;; (lp i2 (+ j 1)))))))
(define (utf8->string vec . o) (define (utf8->string vec . o)
(if (pair? o) (let ((start (if (pair? o) (car o) 0))
(let ((start (car o)) (end (if (and (pair? o) (pair? (cdr o))) (cadr o) (bytevector-length vec))))
(end (if (pair? (cdr o)) (cadr o) (bytevector-length vec)))) (string-copy (utf8->string! vec start end))))
(utf8->string (subbytes vec start end)))
(string-copy (utf8->string! vec))))
(define (string->utf8 str . o) (define (string->utf8 str . o)
(if (pair? o) (if (pair? o)
@ -75,9 +60,12 @@
;;> a string not including the newline. Reads at most \var{n} ;;> a string not including the newline. Reads at most \var{n}
;;> characters, defaulting to 8192. ;;> characters, defaulting to 8192.
(cond-expand
((not string-streams)
(define (%read-line n in) (define (%read-line n in)
(cond
((stream-port? in) ;;(port-fileno in)
(port-line-set! in (+ 1 (port-line in)))
(%%read-line n in))
(else
(let ((out (open-output-string))) (let ((out (open-output-string)))
(let lp ((i 0)) (let lp ((i 0))
(let ((ch (peek-char in))) (let ((ch (peek-char in)))
@ -103,13 +91,10 @@
(let ((in (if (pair? o) (car o) (current-input-port))) (let ((in (if (pair? o) (car o) (current-input-port)))
(n (if (and (pair? o) (pair? (cdr o))) (car (cdr o)) 8192))) (n (if (and (pair? o) (pair? (cdr o))) (car (cdr o)) 8192)))
(let ((res (%read-line n in))) (let ((res (%read-line n in)))
(cond-expand
(string-streams
(port-line-set! in (+ 1 (port-line in)))))
(if (not res) (if (not res)
eof eof
(let ((len (string-length res))) (let ((len (string-length res)))
(cond (cond ;; strip crlf
((and (> len 0) (eqv? #\newline (string-ref res (- len 1)))) ((and (> len 0) (eqv? #\newline (string-ref res (- len 1))))
(if (and (> len 1) (eqv? #\return (string-ref res (- len 2)))) (if (and (> len 1) (eqv? #\return (string-ref res (- len 2))))
(substring res 0 (- len 2)) (substring res 0 (- len 2))
@ -128,9 +113,11 @@
;;> than \var{n} characters if the end of file is reached, ;;> than \var{n} characters if the end of file is reached,
;;> or the eof-object if no characters are available. ;;> or the eof-object if no characters are available.
(cond-expand
((not string-streams)
(define (%read-string n in) (define (%read-string n in)
(cond
;;((port-fileno in)
;; (%%read-string n in))
(else
(let ((out (open-output-string))) (let ((out (open-output-string)))
(let lp ((i 0)) (let lp ((i 0))
(cond ((or (= i n) (eof-object? (peek-char in))) (cond ((or (= i n) (eof-object? (peek-char in)))
@ -159,9 +146,11 @@
;;> An error is signalled if the length of \var{str} is smaller ;;> An error is signalled if the length of \var{str} is smaller
;;> than \var{n}. ;;> than \var{n}.
(cond-expand
((not string-streams)
(define (%read-string! str n in) (define (%read-string! str n in)
(cond
;;((port-fileno in)
;; (%%read-string! str n in))
(else
(let lp ((i 0)) (let lp ((i 0))
(cond ((or (= i n) (eof-object? (peek-char in))) i) (cond ((or (= i n) (eof-object? (peek-char in))) i)
(else (string-set! str i (read-char in)) (lp (+ i 1)))))))) (else (string-set! str i (read-char in)) (lp (+ i 1))))))))

View file

@ -1,15 +1,12 @@
(cond-expand (define-c non-null-string (%%read-line "fgets")
(string-streams
(define-c non-null-string (%read-line "fgets")
((result (array char arg1)) int (default (current-input-port) input-port))) ((result (array char arg1)) int (default (current-input-port) input-port)))
(define-c size_t (%read-string "fread") ;;(define-c size_t (%%read-string "fread")
((result (array char (result arg2))) (value 1 size_t) size_t (default (current-input-port) input-port))) ;; ((result (array char (result arg2))) (value 1 size_t) size_t (default (current-input-port) input-port)))
(define-c size_t (%read-string! "fread") ;;(define-c size_t (%%read-string! "fread")
(string (value 1 size_t) size_t (default (current-input-port) input-port))) ;; (string (value 1 size_t) size_t (default (current-input-port) input-port)))
))
(c-include-verbatim "port.c") (c-include-verbatim "port.c")
@ -53,8 +50,19 @@
((value ctx sexp) (value self sexp) sexp sexp sexp (default NULL sexp))) ((value ctx sexp) (value self sexp) sexp sexp sexp (default NULL sexp)))
(define-c sexp (%string->utf8 "sexp_string_to_utf8") (define-c sexp (%string->utf8 "sexp_string_to_utf8")
((value ctx sexp) (value self sexp) sexp)) ((value ctx sexp) (value self sexp) sexp))
(define-c sexp (utf8->string! "sexp_utf8_to_string_x") (define-c sexp (string->utf8! "sexp_string_to_utf8_x")
((value ctx sexp) (value self sexp) sexp)) ((value ctx sexp) (value self sexp) sexp))
(define-c sexp (string-offset "sexp_string_offset_op")
((value ctx sexp) (value self sexp) sexp))
(define-c sexp (utf8->string! "sexp_utf8_to_string_x")
((value ctx sexp) (value self sexp) sexp sexp sexp))
(define-c sexp (utf8-ref "sexp_utf8_ref")
((value ctx sexp) (value self sexp) sexp sexp))
(define-c sexp (utf8-next "sexp_utf8_next")
((value ctx sexp) (value self sexp) sexp sexp sexp))
(define-c sexp (utf8-prev "sexp_utf8_prev")
((value ctx sexp) (value self sexp) sexp sexp sexp))
(define-c sexp (write-u8 "sexp_write_u8") (define-c sexp (write-u8 "sexp_write_u8")
((value ctx sexp) (value self sexp) sexp (default (current-output-port) sexp))) ((value ctx sexp) (value self sexp) sexp (default (current-output-port) sexp)))

View file

@ -258,15 +258,15 @@ sexp sexp_make_custom_binary_output_port (sexp ctx, sexp self,
return res; return res;
} }
sexp sexp_bytes_to_string (sexp ctx, sexp vec) { sexp sexp_bytes_to_string (sexp ctx, sexp vec, sexp_uint_t offset, sexp_uint_t size) {
sexp res; sexp res;
#if SEXP_USE_PACKED_STRINGS #if SEXP_USE_PACKED_STRINGS
res = sexp_c_string(ctx, sexp_bytes_data(vec), sexp_bytes_length(vec)); res = sexp_c_string(ctx, sexp_bytes_data(vec) + offset, size);
#else #else
res = sexp_alloc_type(ctx, string, SEXP_STRING); res = sexp_alloc_type(ctx, string, SEXP_STRING);
sexp_string_bytes(res) = vec; sexp_string_bytes(res) = vec;
sexp_string_offset(res) = 0; sexp_string_offset(res) = offset;
sexp_string_size(res) = sexp_bytes_length(vec); sexp_string_size(res) = size - offset;
#endif #endif
return res; return res;
} }
@ -275,7 +275,7 @@ sexp sexp_open_input_bytevector (sexp ctx, sexp self, sexp vec) {
sexp_gc_var2(str, res); sexp_gc_var2(str, res);
sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, vec); sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, vec);
sexp_gc_preserve2(ctx, str, res); sexp_gc_preserve2(ctx, str, res);
str = sexp_bytes_to_string(ctx, vec); str = sexp_bytes_to_string(ctx, vec, 0, sexp_bytes_length(vec));
res = sexp_open_input_string(ctx, str); res = sexp_open_input_string(ctx, str);
sexp_port_binaryp(res) = 1; sexp_port_binaryp(res) = 1;
sexp_gc_release2(ctx); sexp_gc_release2(ctx);
@ -341,10 +341,72 @@ sexp sexp_string_to_utf8 (sexp ctx, sexp self, sexp str) {
return sexp_string_to_bytes(ctx, res); return sexp_string_to_bytes(ctx, res);
} }
/* TODO: add validation */ sexp sexp_string_to_utf8_x (sexp ctx, sexp self, sexp str) {
sexp sexp_utf8_to_string_x (sexp ctx, sexp self, sexp vec) { sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
#if SEXP_USE_PACKED_STRINGS
return sexp_string_to_utf8(ctx, self, str);
#else
return sexp_string_bytes(str);
#endif
}
sexp sexp_string_offset_op (sexp ctx, sexp self, sexp str) {
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
#if SEXP_USE_PACKED_STRINGS
return SEXP_ZERO;
#else
return sexp_make_fixnum(sexp_string_offset(str));
#endif
}
sexp sexp_utf8_ref (sexp ctx, sexp self, sexp bv, sexp offset) {
sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, bv);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, offset);
unsigned char *p=(unsigned char*)sexp_bytes_data(bv) + sexp_unbox_fixnum(offset);
if (*p < 0x80)
return sexp_make_character(*p);
else if ((*p < 0xC0) || (*p > 0xF7))
return sexp_user_exception(ctx, NULL, "utf8-ref: invalid utf8 byte", offset);
else if (*p < 0xE0)
return sexp_make_character(((p[0]&0x3F)<<6) + (p[1]&0x3F));
else if (*p < 0xF0)
return sexp_make_character(((p[0]&0x1F)<<12) + ((p[1]&0x3F)<<6) + (p[2]&0x3F));
else
return sexp_make_character(((p[0]&0x0F)<<18) + ((p[1]&0x3F)<<12) + ((p[2]&0x3F)<<6) + (p[3]&0x3F));
}
/* computes length, consider scanning permissively */
sexp sexp_utf8_next (sexp ctx, sexp self, sexp bv, sexp offset, sexp end) {
sexp_sint_t initial, res;
sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, bv);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, offset);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, end);
if (sexp_unbox_fixnum(offset) >= sexp_unbox_fixnum(end)) return SEXP_FALSE;
initial = ((unsigned char*)sexp_bytes_data(bv) + sexp_unbox_fixnum(offset))[0];
res = sexp_unbox_fixnum(offset) + (initial < 0xC0 ? 1 : initial < 0xE0 ? 2 : 3 + ((initial>>4)&1));
return res > sexp_unbox_fixnum(end) ? SEXP_FALSE : sexp_make_fixnum(res);
}
/* scans backwards permissively */
sexp sexp_utf8_prev (sexp ctx, sexp self, sexp bv, sexp offset, sexp start) {
sexp_sint_t i, limit;
sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, bv);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, offset);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, start);
unsigned char *p=(unsigned char*)sexp_bytes_data(bv);
i = sexp_unbox_fixnum(offset) - 1;
limit = sexp_unbox_fixnum(start);
while (i >= limit && ((p[i]>>6) == 2))
--i;
return i < limit ? SEXP_FALSE : sexp_make_fixnum(i);
}
/* TODO: add optional encoding validation */
sexp sexp_utf8_to_string_x (sexp ctx, sexp self, sexp vec, sexp offset, sexp size) {
sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, vec); sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, vec);
return sexp_bytes_to_string(ctx, vec); sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, offset);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, size);
return sexp_bytes_to_string(ctx, vec, sexp_unbox_fixnum(offset), sexp_unbox_fixnum(size));
} }
sexp sexp_write_u8 (sexp ctx, sexp self, sexp u8, sexp out) { sexp sexp_write_u8 (sexp ctx, sexp self, sexp u8, sexp out) {

View file

@ -123,6 +123,11 @@
((1 2 3 4 1001 1002 1003 1004 2001 2003 2004) ((1 2 3 4 1001 1002 1003 1004 2001 2003 2004)
(i 1 2 3 4 1001 1004 1005 2000 2001) (i 1 2 3 4 1001 1004 1005 2000 2001)
(= 1 2 3 4 1001 1004 2001)) (= 1 2 3 4 1001 1004 2001))
((0 1 2 3 4 5 6 7 8 9
101 102 103 104 105
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009)
(i 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120)
(= 101 102 103 104 105))
;; difference ;; difference
((1 2 3 4 5) (d 1) (!? 0) (? 2 3 4 5) (!? 6)) ((1 2 3 4 5) (d 1) (!? 0) (? 2 3 4 5) (!? 6))
((1 2 3 4 5) (d 1 2) (!? 0) (? 3 4 5) (!? 6)) ((1 2 3 4 5) (d 1 2) (!? 0) (? 3 4 5) (!? 6))
@ -238,4 +243,17 @@
(test-assert (iset-contains? (iset-union a b) 119)) (test-assert (iset-contains? (iset-union a b) 119))
(test-assert (iset-contains? (iset-union b a) 119))) (test-assert (iset-contains? (iset-union b a) 119)))
(let* ((elts '(0 1 5 27 42 113 114 256))
(is (list->iset elts)))
(test (iota (length elts))
(map (lambda (elt) (iset-rank is elt)) elts))
(test elts
(map (lambda (i) (iset-select is i)) (iota (length elts)))))
(let* ((elts '(903 595 694 581 91 628 648 152 188 29 347 876 381 945 508 890 816 654 871 228 200 397 116 952 60 878 361 205 691 318 87 998 35 886 580 787 856 535 964 133 245 314 711 598 180 984 458 235 599 692 568 1 740 514 995 930 625 638 881 997 412 151 195 512 857 948 956 750 896 813 988 40 85 426 740 83 294 249 235 45 20 784 837 640 56 519 211 780 771 684 408 510 677 773 574 114 537 934 477 136))
(is (list->iset elts)))
(test elts
(map (lambda (i) (iset-select is i))
(map (lambda (elt) (iset-rank is elt)) elts))))
(test-end)))) (test-end))))

View file

@ -19,4 +19,5 @@
iset-difference iset-difference! iset-difference iset-difference!
iset-empty? iset-fold iset-fold-node iset-for-each iset-for-each-node iset-empty? iset-fold iset-fold-node iset-for-each iset-for-each-node
iset-map iset->list iset-size iset= iset<= iset>= iset-map iset->list iset-size iset= iset<= iset>=
iset-cursor iset-cursor? iset-cursor-next iset-ref end-of-iset?)) iset-cursor iset-cursor? iset-cursor-next iset-ref end-of-iset?
iset-rank iset-select))

View file

@ -262,11 +262,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; High-level set operations. ;; High-level set operations.
;;
;; Union is optimized to work at the node level. Intersection and
;; difference iterate over individual elements and so have a lot of
;; room for improvement, at the expense of the complexity of
;; iset-adjoin-node!.
(define (iset-union2! a b) (define (iset-union2! a b)
(iset-for-each-node (iset-for-each-node
@ -295,25 +290,23 @@
(define (iset-intersection2! a b) (define (iset-intersection2! a b)
(let lp ((nodes-a (iset->node-list a)) (let lp ((nodes-a (iset->node-list a))
(nodes-b (iset->node-list b))) (nodes-b (iset->node-list b))
(res '()))
(cond (cond
((null? nodes-a) ((or (null? nodes-a) (null? nodes-b))
a) (let ((is (iset)))
((null? nodes-b) (for-each (lambda (x) (iset-adjoin-node! is x)) res)
(iset-bits-set! (car nodes-a) 0) is))
(iset-right-set! (car nodes-a) #f)
a)
((> (iset-start (car nodes-b)) (iset-end (car nodes-a))) ((> (iset-start (car nodes-b)) (iset-end (car nodes-a)))
(iset-bits-set! (car nodes-a) 0) (lp (cdr nodes-a) nodes-b res))
(lp (cdr nodes-a) nodes-b))
((> (iset-start (car nodes-a)) (iset-end (car nodes-b))) ((> (iset-start (car nodes-a)) (iset-end (car nodes-b)))
(lp nodes-a (cdr nodes-b))) (lp nodes-a (cdr nodes-b) res))
(else (else
(let* ((a (car nodes-a)) (let* ((a (car nodes-a))
(b (car nodes-b)) (b (car nodes-b))
(a-ls (iset-node-split a (iset-start b) (iset-end b))) (a-ls (iset-node-split a (iset-start b) (iset-end b)))
(overlap (cadr a-ls)) (overlap (cadr a-ls))
(right (car (cddr a-ls))) (a-right (car (cddr a-ls)))
(b-ls (iset-node-split b (iset-start overlap) (iset-end overlap))) (b-ls (iset-node-split b (iset-start overlap) (iset-end overlap)))
(b-overlap (cadr b-ls)) (b-overlap (cadr b-ls))
(b-right (car (cddr b-ls)))) (b-right (car (cddr b-ls))))
@ -325,18 +318,16 @@
(b-bits (iset-bits b-overlap))) (b-bits (iset-bits b-overlap)))
(iset-bits-set! a (bitwise-and a-bits b-bits))) (iset-bits-set! a (bitwise-and a-bits b-bits)))
(iset-bits-set! a (iset-bits overlap))) (iset-bits-set! a (iset-bits overlap)))
(if right (lp (if a-right (cons a-right (cdr nodes-a)) (cdr nodes-a))
(iset-insert-right! a right)) (if b-right (cons b-right (cdr nodes-b)) (cdr nodes-b))
(lp (if right (cons right (cdr nodes-a)) (cdr nodes-a)) (cons a res)))))))
(if b-right (cons b-right (cdr nodes-b)) (cdr nodes-b))))))))
(define (iset-intersection! a . args) (define (iset-intersection! a . args)
(let ((b (and (pair? args) (car args)))) (let lp ((a a) (ls args))
(cond (if (null? ls)
(b a
(iset-intersection2! a b) (lp (iset-intersection2! a (car ls))
(apply iset-intersection! a (cdr args))) (cdr ls)))))
(else a))))
;;> Returns an iset containing all integers which occur in \var{a} and ;;> Returns an iset containing all integers which occur in \var{a} and
;;> every of the isets \var{args}. If no \var{args} are present ;;> every of the isets \var{args}. If no \var{args} are present

View file

@ -95,6 +95,75 @@
(not (iset-right node)) (not (iset-right node))
(null? (iset-cursor-stack cur))))) (null? (iset-cursor-stack cur)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rank/Select operations, acting directly on isets without an
;; optimized data structure.
(define (iset-node-size iset)
(if (iset-bits iset)
(bit-count (iset-bits iset))
(+ 1 (- (iset-end iset) (iset-start iset)))))
;; Number of bits set in i below index n.
(define (bit-rank i n)
(bit-count (bitwise-and i (- (arithmetic-shift 1 n) 1))))
;;> Returns the rank (i.e. index within the iset) of the given
;;> element, a number in [0, size). This can be used to compress an
;;> integer set to a minimal consecutive set of integets. Can also be
;;> thought of as the number of elements in iset smaller than element.
(define (iset-rank iset element)
(let lp ((iset iset) (count 0))
(cond
((< element (iset-start iset))
(if (iset-left iset)
(lp (iset-left iset) count)
(error "integer not in iset" iset element)))
((> element (iset-end iset))
(if (iset-right iset)
(lp (iset-right iset)
(+ count
(cond ((iset-left iset) => iset-size) (else 0))
(iset-node-size iset)))
(error "integer not in iset" iset element)))
((iset-bits iset)
(+ count
(cond ((iset-left iset) => iset-size) (else 0))
(bit-rank (iset-bits iset)
(- element (iset-start iset)))))
(else
(+ count
(cond ((iset-left iset) => iset-size) (else 0))
(integer-length (- element (iset-start iset))))))))
(define (nth-set-bit i n)
;; TODO: optimize
(if (zero? n)
(first-set-bit i)
(nth-set-bit (bitwise-and i (- i 1)) (- n 1))))
;;> Selects the index-th element of iset starting at 0. The inverse
;;> operation of \scheme{iset-rank}.
(define (iset-select iset index)
(let lp ((iset iset) (index index) (stack '()))
(if (and iset (iset-left iset))
(lp (iset-left iset) index (cons iset stack))
(let ((iset (if iset iset (car stack)))
(stack (if iset stack (cdr stack))))
(let ((node-size (iset-node-size iset)))
(cond
((and (< index node-size) (iset-bits iset))
(+ (iset-start iset)
(nth-set-bit (iset-bits iset) index)))
((< index node-size)
(+ (iset-start iset) index))
((iset-right iset)
(lp (iset-right iset) (- index node-size) stack))
((pair? stack)
(lp #f (- index node-size) stack))
(else
(error "iset index out of range" iset index))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Equality ;; Equality
@ -201,10 +270,6 @@
(define (iset-size iset) (define (iset-size iset)
(iset-fold-node (iset-fold-node
(lambda (is acc) (lambda (is acc) (+ acc (iset-node-size is)))
(let ((bits (iset-bits is)))
(+ acc (if bits
(bit-count bits)
(+ 1 (- (iset-end is) (iset-start is)))))))
0 0
iset)) iset))

View file

@ -12,5 +12,7 @@
(export (export
iset-empty? iset-fold iset-fold-node iset-for-each iset-for-each-node iset-empty? iset-fold iset-fold-node iset-for-each iset-for-each-node
iset->list iset-size iset= iset<= iset>= iset->list iset-size iset= iset<= iset>=
;; rank/select
iset-rank iset-select
;; low-level cursors ;; low-level cursors
iset-cursor iset-cursor? iset-cursor-next iset-ref end-of-iset?)) iset-cursor iset-cursor? iset-cursor-next iset-ref end-of-iset?))

View file

@ -168,3 +168,23 @@
,(iset-bits iset) ,(iset-bits iset)
,(iset->code (iset-left iset)) ,(iset->code (iset-left iset))
,(iset->code (iset-right iset))))) ,(iset->code (iset-right iset)))))
;; uses only if, <, <=, >, and SRFI 151 bit-set?
(define (iset->code/lambda iset)
(define (code iset)
(and iset
(if (and (not (iset-left iset))
(not (iset-right iset))
(not (iset-bits iset)))
`(<= ,(iset-start iset) n ,(iset-end iset))
`(if (< n ,(iset-start iset))
,(code (iset-left iset))
,(if (and (not (iset-right iset)) (not (iset-bits iset)))
`(<= n ,(iset-end iset))
`(if (> n ,(iset-end iset))
,(code (iset-right iset))
,(if (iset-bits iset)
`(bit-set? (- n ,(iset-start iset))
,(iset-bits iset))
#t)))))))
`(lambda (n) ,(code iset)))

View file

@ -17,4 +17,5 @@
(bitwise-and (%mask size) (arithmetic-shift n (- position))))))) (bitwise-and (%mask size) (arithmetic-shift n (- position)))))))
(include "optimize.scm") (include "optimize.scm")
(export (export
iset-balance iset-balance! iset-optimize iset-optimize! iset->code)) iset-balance iset-balance! iset-optimize iset-optimize!
iset->code iset->code/lambda))

157
lib/chibi/json-test.sld Normal file
View file

@ -0,0 +1,157 @@
(define-library (chibi json-test)
(import (scheme base) (chibi json) (chibi test))
(export run-tests)
(begin
(define (run-tests)
(test-begin "json")
(test-begin "string->json")
(test 1 (string->json "1"))
(test 1.5 (string->json "1.5"))
(test 1000.0 (string->json "1e3"))
(test 'null (string->json "null"))
(test '((null . 3)) (string->json "{\"null\": 3}"))
(test "á" (string->json "\"\\u00e1\""))
(test "𐐷" (string->json "\"\\uD801\\uDC37\""))
(test "😐" (string->json "\"\\uD83D\\uDE10\""))
(test '((glossary
(title . "example glossary")
(GlossDiv
(title . "S")
(GlossList
(GlossEntry
(ID . "SGML")
(SortAs . "SGML")
(GlossTerm . "Standard Generalized Markup Language")
(Acronym . "SGML")
(Abbrev . "ISO 8879:1986")
(GlossDef
(para . "A meta-markup language, used to create markup languages such as DocBook.")
(GlossSeeAlso . #("GML" "XML")))
(GlossSee . "markup"))))))
(string->json "{
\"glossary\": {
\"title\": \"example glossary\",
\"GlossDiv\": {
\"title\": \"S\",
\"GlossList\": {
\"GlossEntry\": {
\"ID\": \"SGML\",
\"SortAs\": \"SGML\",
\"GlossTerm\": \"Standard Generalized Markup Language\",
\"Acronym\": \"SGML\",
\"Abbrev\": \"ISO 8879:1986\",
\"GlossDef\": {
\"para\": \"A meta-markup language, used to create markup languages such as DocBook.\",
\"GlossSeeAlso\": [\"GML\", \"XML\"]
},
\"GlossSee\": \"markup\"
}
}
}
}
}"))
(test '((menu
(id . "file")
(value . "File")
(popup
(menuitem
. #(((value . "New") (onclick . "CreateNewDoc()"))
((value . "Open") (onclick . "OpenDoc()"))
((value . "Close") (onclick . "CloseDoc()")))))))
(string->json "{\"menu\": {
\"id\": \"file\",
\"value\": \"File\",
\"popup\": {
\"menuitem\": [
{\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"},
{\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},
{\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}
]
}
}}"))
(test-end)
(test-begin "make-json-reader")
(let ()
(define-record-type Employee
(make-employee name id title department)
employee?
(name employee-name)
(id employee-id)
(title employee-title)
(department employee-department))
(define-record-type Team
(make-team name lead devs)
team?
(name team-name)
(lead team-lead)
(devs team-devs))
(define read-employee (make-json-reader Employee))
(define read-team
(make-json-reader
`(,Team
(lead . ,Employee)
(name . ,string?)
(devs . #(,Employee)))))
(define (string->employee str)
(read-employee (open-input-string str)))
(define (string->team str)
(read-team (open-input-string str)))
(let ((emp1 (string->employee
"{\"name\": \"Bob\", \"id\": 3, \"title\": \"CEO\"}")))
(test-assert (employee? emp1))
(test "Bob" (employee-name emp1))
(test 3 (employee-id emp1))
(test "CEO" (employee-title emp1)))
(test-assert (employee? (string->employee "{\"unknown\": \"foo\"}")))
(test-error ((make-json-reader Employee #t)
(open-input-string "{\"unknown\": \"foo\"}")))
(test-error (string->team "{\"name\": 3}"))
(let ((team1 (string->team
"{\"name\": \"Tiger Cats\", \"lead\": {\"name\": \"House\", \"id\": 321}, \"devs\": [{\"name\": \"Cameron\", \"id\": 7}, {\"name\": \"Thirteen\", \"id\": 13}]}")))
(test-assert (team? team1))
(test-assert (employee? (team-lead team1)))
(test "House" (employee-name (team-lead team1)))
(test-assert (vector? (team-devs team1)))
(test 2 (vector-length (team-devs team1)))
(test "Cameron" (employee-name (vector-ref (team-devs team1) 0)))
(test "Thirteen" (employee-name (vector-ref (team-devs team1) 1)))))
(test-end)
(test-begin "json->string")
(test "1" (json->string 1))
(test "1.5" (json->string 1.5))
(test "1000" (json->string 1E3))
(test "null" (json->string 'null))
(test "{\"null\":3}" (json->string '((null . 3))))
(test "\"\\u00E1\"" (json->string "á"))
(test "\"\\uD801\\uDC37\"" (json->string "𐐷"))
(test "\"\\uD83D\\uDE10\"" (json->string "😐"))
(test "{\"menu\":{\"id\":\"file\",\"value\":\"File\",\"popup\":{\"menuitem\":[{\"value\":\"New\",\"onclick\":\"CreateNewDoc()\"},{\"value\":\"Open\",\"onclick\":\"OpenDoc()\"},{\"value\":\"Close\",\"onclick\":\"CloseDoc()\"}]}}}"
(json->string '((menu
(id . "file")
(value . "File")
(popup
(menuitem
. #(((value . "New") (onclick . "CreateNewDoc()"))
((value . "Open") (onclick . "OpenDoc()"))
((value . "Close") (onclick . "CloseDoc()")))))))))
(test "{\"glossary\":{\"title\":\"example glossary\",\"GlossDiv\":{\"title\":\"S\",\"GlossList\":{\"GlossEntry\":{\"ID\":\"SGML\",\"SortAs\":\"SGML\",\"GlossTerm\":\"Standard Generalized Markup Language\",\"Acronym\":\"SGML\",\"Abbrev\":\"ISO 8879:1986\",\"GlossDef\":{\"para\":\"A meta-markup language, used to create markup languages such as DocBook.\",\"GlossSeeAlso\":[\"GML\",\"XML\"]},\"GlossSee\":\"markup\"}}}}}"
(json->string '((glossary
(title . "example glossary")
(GlossDiv
(title . "S")
(GlossList
(GlossEntry
(ID . "SGML")
(SortAs . "SGML")
(GlossTerm . "Standard Generalized Markup Language")
(Acronym . "SGML")
(Abbrev . "ISO 8879:1986")
(GlossDef
(para . "A meta-markup language, used to create markup languages such as DocBook.")
(GlossSeeAlso . #("GML" "XML")))
(GlossSee . "markup"))))))))
(test-end)
(test-end)
)))

497
lib/chibi/json.c Normal file
View file

@ -0,0 +1,497 @@
/* json.c -- fast json I/O */
/* Copyright (c) 2020 Alex Shinn. All rights reserved. */
/* Copyright (c) 2020 Ekaitz Zarraga. All rights reserved. */
/* BSD-style license: http://synthcode.com/license.txt */
#include <chibi/eval.h>
static int digit_value (int c) {
return (((c)<='9') ? ((c) - '0') : ((sexp_tolower(c) - 'a') + 10));
}
sexp json_read (sexp ctx, sexp self, sexp in);
sexp sexp_json_read_exception (sexp ctx, sexp self, const char* msg, sexp in, sexp ir) {
sexp res;
sexp_gc_var4(sym, name, str, irr);
sexp_gc_preserve4(ctx, sym, name, str, irr);
name = (sexp_port_name(in) ? sexp_port_name(in) : SEXP_FALSE);
name = sexp_cons(ctx, name, sexp_make_fixnum(sexp_port_line(in)));
str = sexp_c_string(ctx, msg, -1);
irr = ((sexp_pairp(ir) || sexp_nullp(ir)) ? ir : sexp_list1(ctx, ir));
res = sexp_make_exception(ctx, sym = sexp_intern(ctx, "json-read", -1),
str, irr, SEXP_FALSE, name);
sexp_gc_release4(ctx);
return res;
}
sexp sexp_json_write_exception (sexp ctx, sexp self, const char* msg, sexp obj) {
sexp_gc_var2(res, tmp);
sexp_gc_preserve2(ctx, res, tmp);
tmp = sexp_list1(ctx, obj);
res = sexp_user_exception(ctx, self, msg, tmp);
sexp_gc_release2(ctx);
return res;
}
sexp json_read_number (sexp ctx, sexp self, sexp in) {
double res = 0, scale = 1;
int sign = 1, inexactp = 0, scale_sign = 1, ch;
ch = sexp_read_char(ctx, in);
if (ch == '+') {
ch = sexp_read_char(ctx, in);
} else if (ch == '-') {
ch = sexp_read_char(ctx, in);
sign = -1;
}
for ( ; ch != EOF && isdigit(ch); ch = sexp_read_char(ctx, in))
res = res * 10 + ch - '0';
if (ch == '.') {
inexactp = 1;
for (ch = sexp_read_char(ctx, in); isdigit(ch); scale *= 10, ch = sexp_read_char(ctx, in))
res = res * 10 + ch - '0';
res /= scale;
} else if (ch == 'e') {
inexactp = 1;
ch = sexp_read_char(ctx, in);
if (ch == '+') {
ch = sexp_read_char(ctx, in);
} else if (ch == '-') {
ch = sexp_read_char(ctx, in);
scale_sign = -1;
}
for (scale=0; isdigit(ch); ch = sexp_read_char(ctx, in))
scale = scale * 10 + ch - '0';
res *= pow(10.0, scale_sign * scale);
}
if (ch != EOF) sexp_push_char(ctx, ch, in);
return (inexactp || fabs(res) > (double)SEXP_MAX_FIXNUM) ?
sexp_make_flonum(ctx, sign * res) :
sexp_make_fixnum(sign * res); /* always return inexact? */
}
sexp json_read_literal (sexp ctx, sexp self, sexp in, char* name, sexp value) {
int ch;
for (++name; *name; )
if (*(name++) != (ch = sexp_read_char(ctx, in)))
sexp_json_read_exception(ctx, self, "unexpected character in json", in, sexp_make_character(ch));
return value;
}
#define USEQ_LEN 4
long decode_useq(sexp ctx, sexp in) {
long result = 0, i, ch;
for (i=0; i < USEQ_LEN; i++) {
ch = sexp_read_char(ctx, in);
if (!isxdigit(ch)) {
sexp_push_char(ctx, ch, in);
return -1;
}
result = (result << 4) + digit_value(ch);
}
return result;
}
#define INIT_STRING_BUFFER_SIZE 128
sexp json_read_string (sexp ctx, sexp self, sexp in) {
sexp_sint_t size=INIT_STRING_BUFFER_SIZE;
char initbuf[INIT_STRING_BUFFER_SIZE];
char *buf=initbuf, *tmp;
int i=0, ch, len;
long utfchar, utfchar2;
sexp res = SEXP_VOID;
for (ch = sexp_read_char(ctx, in); ch != '"'; ch = sexp_read_char(ctx, in)) {
if (ch == EOF) {
res = sexp_json_read_exception(ctx, self, "unterminated string in json", in, SEXP_NULL);
break;
}
if (i+4 >= size) { /* expand buffer w/ malloc(), later free() it */
tmp = (char*) sexp_malloc(size*2);
if (!tmp) {res = sexp_global(ctx, SEXP_G_OOM_ERROR); break;}
memcpy(tmp, buf, i);
if (size != INIT_STRING_BUFFER_SIZE) free(buf);
buf = tmp;
size *= 2;
}
if (ch == '\\') {
ch = sexp_read_char(ctx, in);
switch (ch) {
case 'n':
buf[i++] = '\n';
break;
case 't':
buf[i++] = '\t';
break;
case 'u':
utfchar = decode_useq(ctx, in);
if (0xd800 <= utfchar && utfchar <= 0xdbff) {
ch = sexp_read_char(ctx, in);
if (ch == '\\') {
ch = sexp_read_char(ctx, in);
if (ch == 'u') {
/* high surrogate followed by another unicode escape */
utfchar2 = decode_useq(ctx, in);
if (0xdc00 <= utfchar2 && utfchar2 <= 0xdfff) {
/* merge low surrogate (otherwise high is left unpaired) */
utfchar = 0x10000 + (((utfchar - 0xd800) << 10) | (utfchar2 - 0xdc00));
} else {
return sexp_json_read_exception(ctx, self, "invalid \\u sequence", in, SEXP_NULL);
}
} else {
sexp_push_char(ctx, ch, in);
sexp_push_char(ctx, '\\', in);
}
} else {
sexp_push_char(ctx, ch, in);
}
}
if (utfchar < 0) {
return sexp_json_read_exception(ctx, self, "invalid \\u sequence", in, SEXP_NULL);
} else {
len = sexp_utf8_char_byte_count(utfchar);
sexp_utf8_encode_char((unsigned char*)buf + i, len, utfchar);
i += len;
}
break;
default:
buf[i++] = ch;
break;
}
} else {
buf[i++] = ch;
}
}
if (!sexp_exceptionp(res)) {
buf[i] = '\0';
res = sexp_c_string(ctx, buf, i);
if (sexp_stringp(res)) sexp_immutablep(res) = 1;
}
if (size != INIT_STRING_BUFFER_SIZE) free(buf);
return res;
}
sexp json_read_array (sexp ctx, sexp self, sexp in) {
sexp_gc_var2(res, tmp);
sexp_gc_preserve2(ctx, res, tmp);
int comma = 1, ch;
res = SEXP_NULL;
while (1) {
ch = sexp_read_char(ctx, in);
if (ch == EOF) {
res = sexp_json_read_exception(ctx, self, "unterminated array in json", in, SEXP_NULL);
break;
} else if (ch == ']') {
if (comma && res != SEXP_NULL) {
res = sexp_json_read_exception(ctx, self, "missing value after comma in json", in, SEXP_NULL);
} else {
res = sexp_nreverse(ctx, res);
res = sexp_list_to_vector(ctx, res);
}
break;
} else if (ch == ',' && comma) {
res = sexp_json_read_exception(ctx, self, "unexpected comma in json array", in, SEXP_NULL);
break;
} else if (ch == ',') {
comma = 1;
} else if (!isspace(ch)) {
if (comma) {
sexp_push_char(ctx, ch, in);
tmp = json_read(ctx, self, in);
if (sexp_exceptionp(tmp)) {
res = tmp;
break;
}
res = sexp_cons(ctx, tmp, res);
comma = 0;
} else {
res = sexp_json_read_exception(ctx, self, "unexpected value in json array", in, SEXP_NULL);
break;
}
}
}
sexp_gc_release2(ctx);
return res;
}
sexp json_read_object (sexp ctx, sexp self, sexp in) {
sexp_gc_var2(res, tmp);
sexp_gc_preserve2(ctx, res, tmp);
int comma = 1, ch;
res = SEXP_NULL;
while (1) {
ch = sexp_read_char(ctx, in);
if (ch == EOF) {
res = sexp_json_read_exception(ctx, self, "unterminated object in json", in, SEXP_NULL);
break;
} else if (ch == '}') {
if (comma && res != SEXP_NULL) {
res = sexp_json_read_exception(ctx, self, "missing value after comma in json object", in, SEXP_NULL);
} else {
res = sexp_nreverse(ctx, res);
}
break;
} else if (ch == ',' && comma) {
res = sexp_json_read_exception(ctx, self, "unexpected comma in json object", in, SEXP_NULL);
break;
} else if (ch == ',') {
comma = 1;
} else if (!isspace(ch)) {
if (comma) {
sexp_push_char(ctx, ch, in);
tmp = json_read(ctx, self, in);
if (sexp_exceptionp(tmp)) {
res = tmp;
break;
} else if (sexp_stringp(tmp)) {
tmp = sexp_string_to_symbol(ctx, tmp);
}
tmp = sexp_cons(ctx, tmp, SEXP_VOID);
for (ch = sexp_read_char(ctx, in); isspace(ch); ch = sexp_read_char(ctx, in))
;
if (ch != ':') {
res = sexp_json_read_exception(ctx, self, "missing colon in json object", in, sexp_make_character(ch));
break;
}
sexp_cdr(tmp) = json_read(ctx, self, in);
if (sexp_exceptionp(sexp_cdr(tmp))) {
res = sexp_cdr(tmp);
break;
}
res = sexp_cons(ctx, tmp, res);
comma = 0;
} else {
res = sexp_json_read_exception(ctx, self, "unexpected value in json object", in, SEXP_NULL);
break;
}
}
}
sexp_gc_release2(ctx);
return res;
}
sexp json_read (sexp ctx, sexp self, sexp in) {
sexp res;
int ch = ' ';
while (isspace(ch))
ch = sexp_read_char(ctx, in);
switch (ch) {
case '{':
res = json_read_object(ctx, self, in);
break;
case '[':
res = json_read_array(ctx, self, in);
break;
case '"':
res = json_read_string(ctx, self, in);
break;
case '-': case '+':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
sexp_push_char(ctx, ch, in);
res = json_read_number(ctx, self, in);
break;
case 'n': case 'N':
res = json_read_literal(ctx, self, in, "null", sexp_intern(ctx, "null", -1));
break;
case 't': case 'T':
res = json_read_literal(ctx, self, in, "true", SEXP_TRUE);
break;
case 'f': case 'F':
res = json_read_literal(ctx, self, in, "false", SEXP_FALSE);
break;
case '}':
res = sexp_json_read_exception(ctx, self, "unexpected closing brace in json", in, SEXP_NULL);
break;
case ']':
res = sexp_json_read_exception(ctx, self, "unexpected closing bracket in json", in, SEXP_NULL);
break;
default:
res = sexp_json_read_exception(ctx, self, "unexpected character in json", in, sexp_make_character(ch));
break;
}
return res;
}
sexp sexp_json_read (sexp ctx, sexp self, sexp_sint_t n, sexp in) {
sexp_assert_type(ctx, sexp_iportp, SEXP_IPORT, in);
return json_read(ctx, self, in);
}
sexp json_write (sexp ctx, sexp self, sexp obj, sexp out);
#define FLONUM_SIGNIFICANT_DIGITS 10
#define FLONUM_EXP_MAX_DIGITS 3
sexp json_write_flonum(sexp ctx, sexp self, const sexp obj, sexp out) {
if (sexp_infp(obj) || sexp_nanp(obj)) {
return sexp_json_write_exception(ctx, self, "unable to encode number", obj);
}
/* Extra space for signs (x2), dot, E and \0 */
char cout[FLONUM_SIGNIFICANT_DIGITS + FLONUM_EXP_MAX_DIGITS + 5];
snprintf(cout, sizeof(cout), "%.*G", FLONUM_SIGNIFICANT_DIGITS, sexp_flonum_value(obj));
sexp_write_string(ctx, cout, out);
return SEXP_VOID;
}
sexp json_write_string(sexp ctx, sexp self, const sexp obj, sexp out) {
char cout[32]; /* oversized to avoid snprintf warnings */
unsigned long ch, chh, chl;
sexp i, end = sexp_make_string_cursor(sexp_string_size(obj));
sexp_write_char(ctx, '"', out);
for (i = sexp_make_string_cursor(0); i < end;
i = sexp_string_cursor_next(obj, i)) {
ch = sexp_unbox_character(sexp_string_cursor_ref(ctx, obj, i));
if (ch < 0x7F) {
switch (ch) {
case '\\':
sexp_write_string(ctx, "\\\\", out);
break;
case '\b':
sexp_write_string(ctx, "\\b", out);
break;
case '\f':
sexp_write_string(ctx, "\\f", out);
break;
case '\n':
sexp_write_string(ctx, "\\n", out);
break;
case '\r':
sexp_write_string(ctx, "\\r", out);
break;
case '\t':
sexp_write_string(ctx, "\\t", out);
break;
default:
sexp_write_char(ctx, ch, out);
break;
}
} else if (ch <= 0xFFFF) {
snprintf(cout, sizeof(cout), "\\u%04lX", ch);
sexp_write_string(ctx, cout, out);
} else {
// Surrogate pair
chh = (0xD800 - (0x10000 >> 10) + ((ch) >> 10));
chl = (0xDC00 + ((ch) & 0x3FF));
if (chh > 0xFFFF || chl > 0xFFFF) {
return sexp_json_write_exception(ctx, self, "unable to encode string", obj);
}
snprintf(cout, sizeof(cout), "\\u%04lX\\u%04lX", chh, chl);
sexp_write_string(ctx, cout, out);
}
}
sexp_write_char(ctx, '"', out);
return SEXP_VOID;
}
sexp json_write_array(sexp ctx, sexp self, const sexp obj, sexp out) {
sexp tmp;
int len = sexp_vector_length(obj), i;
sexp_write_string(ctx, "[", out);
for (i = 0; i < len; ++i) {
tmp = json_write(ctx, self, sexp_vector_ref(obj, sexp_make_fixnum(i)), out);
if (sexp_exceptionp(tmp)) {
return tmp;
}
if (i < len - 1) {
sexp_write_char(ctx, ',', out);
}
}
sexp_write_string(ctx, "]", out);
return SEXP_VOID;
}
sexp json_write_object(sexp ctx, sexp self, const sexp obj, sexp out) {
sexp ls, cur, key, val;
sexp_gc_var2(tmp, res);
if (sexp_length(ctx, obj) == SEXP_FALSE)
sexp_json_write_exception(ctx, self, "unable to encode circular list", obj);
sexp_gc_preserve2(ctx, tmp, res);
res = SEXP_VOID;
sexp_write_char(ctx, '{', out);
for (ls = obj; sexp_pairp(ls); ls = sexp_cdr(ls)) {
if (ls != obj)
sexp_write_char(ctx, ',', out);
cur = sexp_car(ls);
if (!sexp_pairp(cur)) {
res = sexp_json_write_exception(ctx, self, "unable to encode key-value pair: not a pair", obj);
break;
}
key = sexp_car(cur);
if (!sexp_symbolp(key)) {
res = sexp_json_write_exception(ctx, self, "unable to encode key: not a symbol", key);
break;
}
tmp = sexp_symbol_to_string(ctx, key);
tmp = json_write(ctx, self, tmp, out);
if (sexp_exceptionp(tmp)) {
res = tmp;
break;
}
sexp_write_char(ctx, ':', out);
val = sexp_cdr(cur);
tmp = json_write(ctx, self, val, out);
if (sexp_exceptionp(tmp)) {
res = tmp;
break;
}
}
sexp_write_char(ctx, '}', out);
sexp_gc_release2(ctx);
return res;
}
sexp json_write (sexp ctx, sexp self, const sexp obj, sexp out) {
sexp_gc_var1(res);
sexp_gc_preserve1(ctx, res);
res = SEXP_VOID;
if (sexp_symbolp(obj)) {
res = sexp_write(ctx, obj, out);
} else if (sexp_stringp(obj)) {
res = json_write_string(ctx, self, obj, out);
} else if (sexp_listp(ctx, obj) == SEXP_TRUE) {
res = json_write_object(ctx, self, obj, out);
} else if (sexp_vectorp(obj)) {
res = json_write_array(ctx, self, obj, out);
} else if (sexp_fixnump(obj)) {
res = sexp_write(ctx, obj, out);
} else if (sexp_flonump(obj)) {
res = json_write_flonum(ctx, self, obj, out);
#if SEXP_USE_BIGNUMS
} else if (sexp_bignump(obj)) {
res = sexp_make_flonum(ctx, sexp_bignum_to_double(obj));
res = json_write_flonum(ctx, self, res, out);
#endif
} else if (obj == SEXP_FALSE) {
sexp_write_string(ctx, "false", out);
} else if (obj == SEXP_TRUE) {
sexp_write_string(ctx, "true", out);
} else if (obj == SEXP_NULL) {
sexp_write_string(ctx, "null", out);
} else if (sexp_pairp(obj)) {
res = sexp_json_write_exception(ctx, self, "unable to encode elemente: key-value pair out of object", obj);
} else {
res = sexp_json_write_exception(ctx, self, "unable to encode element", obj);
}
sexp_gc_release1(ctx);
return res;
}
sexp sexp_json_write (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp out) {
sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
return json_write(ctx, self, obj, out);
}
sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, const sexp_abi_identifier_t abi) {
if (!(sexp_version_compatible(ctx, version, sexp_version)
&& sexp_abi_compatible(ctx, abi, SEXP_ABI_IDENTIFIER)))
return SEXP_ABI_ERROR;
sexp_define_foreign(ctx, env, "json-read", 1, sexp_json_read);
sexp_define_foreign(ctx, env, "json-write", 2, sexp_json_write);
return SEXP_VOID;
}

149
lib/chibi/json.scm Normal file
View file

@ -0,0 +1,149 @@
;;> A library for reading and writing data in JSON format (RFC 8259).
;;> \procedure{(json-read [in])}
;;> Reads a JSON expression from port \var{in}. Objects are
;;> represented as alists with symbol keys, arrays as Scheme vectors,
;;> null as the symbol \scheme{'null}, and strings, numbers and
;;> booleans as the corresponding Scheme types.
;;> \procedure{(string->json str)}
;;> Returns the JSON representation of \var{str} as from \scheme{json-read}.
;;>
;;> \example{
;;> (string->json "{\\"mean\\": 2.2, \\"quartiles\\": [1, 2, 3, 4]}")
;;> }
(define (string->json str)
(let* ((in (open-input-string str))
(res (json-read in)))
(close-input-port in)
res))
;;> \procedure{(json-write json [out])}
;;> Writes a JSON representation of \var{obj} to port \var{out}, where
;;> \var{obj} should follow the same mappings as in \var{json-read}.
;;> \procedure{(json->string json)}
;;> Returns the string representation of \var{json} as from \scheme{json-write}.
(define (json->string json)
(let ((out (open-output-string)))
(json-write json out)
(get-output-string out)))
(define (json-field-mapper rtd name spec strict?)
(if (symbol? spec)
(rtd-mutator rtd spec)
(let ((setter (rtd-mutator rtd name))
(mapper (make-json-mapper spec strict?)))
(lambda (rec val)
(setter rec (mapper val))))))
(define (make-json-mapper spec . o)
(let ((strict? (and (pair? o) (car o))))
(cond
((vector? spec)
(if (= 1 (vector-length spec))
(let ((elt-spec (make-json-mapper (vector-ref spec 0) strict?)))
(lambda (x)
(if (vector? x)
(vector-map elt-spec x)
(error "expected json array" x))))
(lambda (x)
(if (vector? x) x (error "expected json array" x)))))
((procedure? spec)
(lambda (x)
(if (spec x) x (error "json check failed" spec x))))
((rtd? spec)
(make-json-mapper
(cons spec (map (lambda (f) (cons f f))
(vector->list (rtd-all-field-names spec))))
strict?))
((pair? spec)
(if (rtd? (car spec))
(let* ((rtd (car spec))
(make (make-constructor (type-name rtd) rtd))
(fields
(map (lambda (f)
(cons (car f)
(json-field-mapper rtd (car f) (cdr f) strict?)))
(cdr spec))))
(lambda (x)
(if (not (or (pair? x) (null? x)))
(error "expected json object" x)
(let ((res (make)))
(for-each
(lambda (y)
(cond
((and (pair? y) (assq (car y) fields))
=> (lambda (f) ((cdr f) res (cdr y))))
(strict?
(error "unknown field" (if (pair? y) (car y) y)))
(else
)))
x)
res))))
(error "expected rtd in object spec" spec)))
(else
(error "unknown json reader spec" spec)))))
;;> Returns a procedure of one argument, an input port, which reads a
;;> JSON object according to the specification \var{spec}, which can
;;> be one of:
;;>
;;> \itemlist[
;;> \item{a record type: reads a json object with field names
;;> corresponding to the record names}
;;> \item{a predicate: reads an arbitrary json object, and returns
;;> that object if the predicate succeeds, or an error otherwise}
;;> \item{a vector of one element: reads a json array of objects as
;;> described by the vector element}
;;> \item{a list: the car should be a record type, and the cdr
;;> an alist of (field-name . spec). The spec can be a symbol,
;;> in which case it is the record field name (allowing aliasing),
;;> otherwise it is a normal spec to read and set the corresponding
;;> field}
;;> ]
;;>
;;> If \var{strict?} is specified and true, raises an error if any
;;> unknown field names are specified in an object.
;;>
;;> Examples:
;;>
;;> \example{
;;> (begin
;;> (define-record-type Employee
;;> (make-employee name id title department)
;;> employee?
;;> (name employee-name)
;;> (id employee-id)
;;> (title employee-title)
;;> (department employee-department))
;;> (define-record-type Team
;;> (make-team name lead devs)
;;> team?
;;> (name team-name)
;;> (lead team-lead)
;;> (devs team-devs))
;;> (define read-team
;;> (make-json-reader
;;> `(,Team
;;> (lead . ,Employee)
;;> (name . ,string?)
;;> (devs . #(,Employee)))))
;;> (define team
;;> (read-team
;;> (open-input-string
;;> "{\\"name\\": \\"A-Team\\",
;;> \\"lead\\": {\\"name\\": \\"Hannibal\\", \\"id\\": 321},
;;> \\"devs\\": [{\\"name\\": \\"B.A.\\", \\"id\\": 7},
;;> {\\"name\\": \\"Murdock\\", \\"id\\": 13}]}")))
;;> (cons (team-name team)
;;> (map employee-name
;;> (cons (team-lead team) (vector->list (team-devs team))))))
;;> }
(define (make-json-reader spec . o)
(let* ((strict? (and (pair? o) (car o)))
(proc (make-json-mapper spec strict?)))
;; TODO: update this to read directly without the intermediate
;; representation
(lambda (in) (proc (json-read in)))))

10
lib/chibi/json.sld Normal file
View file

@ -0,0 +1,10 @@
(define-library (chibi json)
(import (scheme base)
(except (srfi 99 records) define-record-type)
(only (chibi ast) type-name)
(only (chibi) make-constructor))
(export string->json json->string json-read json-write
make-json-reader)
(include-shared "json")
(include "json.scm"))

View file

@ -16,22 +16,23 @@
(syntax-rules () (syntax-rules ()
((log->string/no-dates expr ...) ((log->string/no-dates expr ...)
(string-join (string-join
(map (lambda (line) (substring line 20)) (map (lambda (line)
(if (string-null? line) line (substring line 20)))
(string-split (log->string expr ...) "\n")) (string-split (log->string expr ...) "\n"))
"\n")))) "\n"))))
(define (run-tests) (define (run-tests)
(test-begin "(chibi log)") (test-begin "logging")
(test "D four: 4" (test "D four: 4\n"
(log->string/no-dates (log->string/no-dates
(log-debug "four: " (+ 2 2)))) (log-debug "four: " (+ 2 2))))
(test "I pi: 3.14" (test "I pi: 3.14\n"
(log->string/no-dates (log->string/no-dates
(log-info "pi: " (with ((precision 2)) (acos -1))))) (log-info "pi: " (with ((precision 2)) (acos -1)))))
(test-assert (test-assert
(string-prefix? "E " (string-prefix? "E "
(log->string/no-dates (log->string/no-dates
(with-logged-errors (/ 1 0))))) (with-logged-errors (/ 1 0)))))
(test "W warn\nE error" (test "W warn\nE error\n"
(log->string/no-dates (log->string/no-dates
(with-log-level (with-log-level
'warn 'warn

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