3478 Commits

Author SHA1 Message Date
Skgland
896b90e57d fix pstr_iter_tests test 2026-07-23 23:28:53 +01:00
Mark Thom
e7ac3ae0f7 version bump to 0.10.0
Some checks failed
CI / style (push) Has been cancelled
CI / read-msrv (push) Has been cancelled
CI / build-test (--no-default-features, ubuntu-22.04, true, nightly, wasm32-unknown-unknown, --no-run --no-default-features, true) (push) Has been cancelled
CI / build-test (macos-latest, true, stable, x86_64-apple-darwin) (push) Has been cancelled
CI / build-test (miri, true, ubuntu-22.04, nightly, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, ${{ needs.read-msrv.outputs.msrv }}, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, beta, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, true, stable, i686-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (windows-latest, true, stable, x86_64-pc-windows-msvc) (push) Has been cancelled
CI / logtalk-test (push) Has been cancelled
CI / report (push) Has been cancelled
CI / release (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
2025-09-27 00:05:31 -07:00
Mark Thom
60595f990f Merge pull request #3095 from thierrymarianne/derefering-registers-in-files-module-instructions-functions
Dereferencing registers in `files` module instructions functions
2025-09-22 22:28:10 -07:00
Thierry Marianne
042631cb4c run rustfmt
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-21 22:52:12 +02:00
Thierry Marianne
32b6458deb dereferencing registers to access stack variables
deref register to access stack variable for `directory_exists/1`
deref register to access stack variable for `directory_files/2`
deref register to access stack variable for `delete_directory/1`
deref register to access stack variable for `delete_file/1`
deref registers to access stack variable for `file_copy/2`
deref register to access stack variable for `file_exists/1`
deref register to access stack variable for `file_size/2`
deref register to access stack variable from `file_time` function
deref register to access stack variable for `make_directory/1`
deref register to access stack variable for `make_directory_path/1`
deref register to access stack variable for `path_canonical/2`
deref registers to access stack variables for `rename_file/2`

Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-21 22:52:12 +02:00
Thierry Marianne
12db664bd9 add tests for file module predicates
reproduce failing `directory_exists/1` with working directory passed as first argument
reproduce failing `delete_directory/1` with ./test directory passed as first argument
reproduce failing `file_size/1` with 2 bytes files passed as first argument
reproduce failing `file_exists/1` with existing file passed as first argument
reproduce failing `file_modification_time/1`, `file_access_time/1` and `file_creation_time/1` with existing file passed as first argument
reproduce failing `directory_files/2` with existing directory passed as first argument
reproduce failing `delete_file/1` with existing file passed as first argument
reproduce failing `make_directory/1` with non-existing directory passed as first argument
reproduce failing `make_directory_path/1` with non-existing path passed as first argument
reproduce failing `path_canonical/2` with non-canonical path passed as first argument
reproduce failing `rename_file/2` with existing file passed as first argument, target file as second arg
revised `directory_exists/1` test case
renamed test files, test directories
use `path_segments/2`, remove path separators
do not write file size to current output
revised `directory_files/2` test
revised `path_canonical/2` test
revised `file_exists/1` test
removed hardcoded expected size
extracted hardcoded directory argument
remove path prefix containing path separator
revised expected ls cmd exit code so that it is platform-agnostic

Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-21 22:52:02 +02:00
Mark Thom
e9ff1348b1 Merge pull request #3084 from thierrymarianne/set_stream
Prevent top-level from panicking when calling  `set_input/1` with `Stream` variants.
2025-09-17 22:20:10 -07:00
Mark Thom
fc6e007ad1 add missing P increment to GetPartialString (#3089) 2025-09-17 20:31:03 -07:00
Mark Thom
7637a0f7d4 push cyclic pstr's tail to iterator stack of printer (#3086) 2025-09-17 20:21:54 -07:00
Mark Thom
ba7b54e8f8 fix attempted bind to bound StackVar (#3089) 2025-09-17 19:43:37 -07:00
Mark Thom
012e3de3a1 do not use self.fail in compare_term_test 2025-09-16 21:23:23 -07:00
Mark Thom
72cdba82f5 implement unify_ginteger to address FIXME in skip_max_list_cycle 2025-09-15 21:58:38 -07:00
Mark Thom
24f431e2ca fix off-by-one lam loop (#3081) 2025-09-15 21:52:43 -07:00
Thierry Marianne
8afcc7742b handle Stream variants qualified as input stream by is_input_stream
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-15 08:33:47 +02:00
Thierry Marianne
e9834ffa3e throw permission_error when non-input stream is read
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-15 08:28:23 +02:00
Thierry Marianne
28ec457159 merge if let, match structures
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-14 20:10:44 +02:00
Thierry Marianne
1ece558a71 match against Stream HttpRead(), InputFile(_) and NamedTcp(_) variants in read_term_from_user_input
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-14 19:19:26 +02:00
Thierry Marianne
be18eda696 do not reset user input Stream of kind different from Readline(_), Byte(_)
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-14 19:19:21 +02:00
Thierry Marianne
fdbaf6ac9d handle named tcp and http read stream on term reading from user input 2025-09-14 17:02:09 +02:00
Thierry Marianne
5c341ce371 handle input file stream on term reading from user input 2025-09-14 17:02:09 +02:00
Thierry Marianne
5f58e1cfd7 reproduce panick originating in set_input/1 call from top-level
Signed-off-by: Thierry Marianne <thierry@marianne.io>
2025-09-14 17:02:02 +02:00
Mark Thom
dc05526c71 add FIXME for (presently inert & never invoked) race condition 2025-09-12 00:19:52 -07:00
Mark Thom
ffea37d899 fix f64 indexing, introduce bespoke F64Table type (#3065) 2025-09-11 23:58:36 -07:00
Mark Thom
368c9fd9dd Merge pull request #3063 from Skgland/ffi++
ffi API extension and fixes
2025-08-28 20:49:41 -07:00
Skgland
c067bfa832 allow 3rd argument of ffi:read_ptr to not be a variable 2025-08-29 00:36:35 +02:00
Mark Thom
aa3d8b8fba Merge pull request #3059 from pmikkelsen/raw-input
Don't use "readline" input functionality for certain builtins
2025-08-26 23:09:18 -07:00
Skgland
14ce052bf2 export array_type/3 2025-08-26 00:33:16 +02:00
Skgland
252361fc20 fix left over todo 2025-08-26 00:15:13 +02:00
Skgland
78c08b87b6 cleanup ffi error handling and use Atom instead of &str in appropriate places 2025-08-26 00:01:35 +02:00
Peter Mikkelsen
eb91b3c1fb Style tweak 2025-08-25 20:47:29 +02:00
Skgland
a140720c6f use representation_error rather than resource_error 2025-08-25 20:14:14 +02:00
Skgland
6f3f66c407 fix builds without ffi feature 2025-08-24 21:08:52 +02:00
Skgland
1f7a60dec9 add meta_predicate declaration for with_locals/2 2025-08-24 20:25:47 +02:00
Skgland
ce9b41815d add documentation 2025-08-24 20:23:17 +02:00
Skgland
80bf276e09 run rustfmt 2025-08-24 19:57:54 +02:00
Skgland
8bc8171ec7 fix define_foreign_struct 2025-08-24 19:56:26 +02:00
Skgland
3b5b768f4a make ffi error structure not found point to the correct culprit 2025-08-24 19:56:26 +02:00
Skgland
176858ad42 fix map_ffi_arg 2025-08-24 19:56:26 +02:00
Skgland
eba681786d make map_ffi_args a method and throw an instantiation error when encountering a variable 2025-08-24 19:56:25 +02:00
Skgland
f4297e365f don't crash on empty list and differentiate list head not being string like 2025-08-24 19:56:25 +02:00
Skgland
cd777294b9 use setup_call_cleanup/3 for with_locals
as suggested by triska
2025-08-24 19:56:25 +02:00
Skgland
3e929511bb add a test for with_locals 2025-08-24 19:56:24 +02:00
Skgland
d1356db7e3 include a culprit in ffi_error 2025-08-24 19:56:24 +02:00
Skgland
7b2bf73ba1 fix with_locals 2025-08-24 19:56:24 +02:00
Skgland
edd6d44bd6 require array_length to be > 0
C does not have 0-sized types
2025-08-24 19:56:24 +02:00
Skgland
4b5e4a2745 fix some things in ffi.pl
thanks triska for pointing out most of these
2025-08-24 19:56:23 +02:00
Skgland
3a4dfc46da add ffi helpers 2025-08-24 19:56:23 +02:00
Skgland
d8346b1651 don't place allocate, read_ptr and deallocate between use_foreign_module and its helper predicates 2025-08-24 19:56:23 +02:00
Skgland
20d52c093a add ffi:{allocate,read_ptr,deallocate} 2025-08-24 19:56:23 +02:00
Skgland
35d34231f2 don't fail the build script if we couldn't parse a file
this way we get to the actual compilation in which rustc shouldl fail with a more helpfull error message
2025-08-24 19:56:17 +02:00
Peter Mikkelsen
90e6e84312 Update src/read.rs
Co-authored-by: Bennet Bleßmann <3877590+Skgland@users.noreply.github.com>
2025-08-24 14:27:33 +02:00
Mark Thom
cd501beb0b very small cargo fmt 2025-08-23 14:57:56 -07:00
Mark Thom
39d02a0caf clear rustc warnings (#3051) 2025-08-23 14:34:49 -07:00
Mark Thom
e168b31963 make max_depth checking in heap_print.rs consistent across atomics 2025-08-23 14:24:14 -07:00
Mark Thom
eed0a5babb some max_depth improvements (#1876, #2666, #3008, #3027) 2025-08-23 14:01:10 -07:00
Mark Thom
ad29f0f180 further improvements to cyclic partial list printing (#2635) 2025-08-23 13:23:39 -07:00
Mark Thom
b14bda310f improve printer's handling of cyclic lists (#2111, #2635) 2025-08-23 13:23:39 -07:00
Peter Mikkelsen
39cf60bc05 Don't use "readline" input functionality for the following builtins:
* peek_byte
* peek_char
* peek_code
* get_byte
* get_char
* get_code
* get_n_chars
2025-08-22 11:02:59 +02:00
Mark Thom
02b8a6010c Merge pull request #3056 from Skgland/fix-msrv
Fix msrv
2025-08-21 23:24:30 -07:00
Mark Thom
b2cfc8b6f2 fix cyclic detection of partial strings in StackfulPreOrderHeapIter (#3050) 2025-08-21 22:52:25 -07:00
Mark Thom
c5389dbbf2 Use from_str_radix for BigInt in parse_integer_by_radix (#3025, #3033) 2025-08-21 18:25:00 -07:00
Skgland
633b86ddc4 make CI read msrv from Cargo.toml
instead of hardcoding it, so we have a single source of truth
2025-08-18 21:10:27 +02:00
Skgland
348c5029b3 reduce msrv back to 1.85 2025-08-18 20:52:15 +02:00
Mark Thom
7ffd93c0d7 Merge pull request #3055 from Skgland/build-debs
use cargo-deb in CI to build debian deb packages
2025-08-17 15:49:20 -07:00
Skgland
6338a40eed fixup logtalk-test 2025-08-17 22:52:45 +02:00
Skgland
3aa272e44d explicitly pass the target to cargo-deb 2025-08-17 22:31:28 +02:00
Skgland
52f3ddd20d fix paths 2025-08-17 22:12:54 +02:00
Mark Thom
f61c069c2b Merge pull request #3053 from Skgland/add-test-for-issue-3048
add tests for issue 3048
2025-08-17 13:12:28 -07:00
Skgland
f1171e2fb2 build debian packages on linux targets 2025-08-17 21:36:42 +02:00
Skgland
e38ee14580 add tests for issue 3048 2025-08-17 14:50:15 +02:00
Mark Thom
93cc4d4898 clear pdl after comparing partial strings (#3048) 2025-08-16 15:26:10 -07:00
Mark Thom
87f5295bd0 check for stack variables in ground_test before iterating (#3048) 2025-08-14 21:21:32 -07:00
Mark Thom
97607d2bcd small tweak for read_from_term performance (#2668) 2025-08-12 22:29:31 -07:00
Mark Thom
216c251c48 deref terms in read_from_term (#2668) 2025-08-12 22:23:52 -07:00
Mark Thom
8af0a19130 Merge pull request #3042 from dcnorris/numerics
library(numerics), special funs from crate puruspe
2025-08-11 22:26:01 -07:00
David C. Norris
9485ae2ca5 Add README entry for numerics/special_functions 2025-08-10 21:30:36 -04:00
David C. Norris
18c451e11c Drop 2 extra lines flagged by 'cargo fmt' 2025-08-10 18:44:08 -04:00
David C. Norris
a4c071a44b Address CI style complaints 2025-08-10 18:36:54 -04:00
Mark Thom
c0fb3fd429 Merge pull request #2786 from Skgland/ffi-f64-tests
add ffi tests & fix ffi
2025-08-10 13:14:15 -07:00
Mark Thom
9fb7d15f0a Merge pull request #3023 from triska/promote_call_with_error_context
ADDED: variants of errors promoting call_with_error_context/2
2025-08-10 13:04:03 -07:00
David C. Norris
a8fa8993e1 Address several comments by @triska 2025-08-10 11:45:21 -04:00
David C. Norris
af3792f79a library(numerics), special funs from crate puruspe 2025-08-10 10:01:01 -04:00
Mark Thom
d83827b21f Merge pull request #2746 from triska/quads
preliminary support for a subset of quads introduced by @UWN
2025-08-10 01:36:15 -07:00
Markus Triska
ee39be4361 ADDED: resource_error/1 2025-08-09 10:22:28 +02:00
Markus Triska
bc4689ca4a ADDED: representation_error/1 2025-08-09 10:19:49 +02:00
Markus Triska
86dc22a850 ADDED: variants of errors promoting call_with_error_context/2
A good example of call_with_error_context/2 was recently provided by
@Skgland in d907f86c8d. Many thanks!
2025-08-09 10:11:25 +02:00
Mark Thom
9cc170f2ad Merge pull request #3024 from triska/remove_operator_meta_predicate
ISO: remove nonstandard operator meta_predicate.
2025-08-08 21:12:19 -07:00
Mark Thom
61f8bc008c Merge pull request #3026 from triska/DEDUCTION
mention the DEDUCTION Programme
2025-08-08 21:11:46 -07:00
Mark Thom
948cbd8f40 Merge pull request #3029 from triska/process_item
add newly available library(process) to the list of libraries
2025-08-08 21:11:32 -07:00
Skgland
e1a52a4dde allow passing a null through a cstr arg/return 2025-08-08 22:45:24 +02:00
Skgland
7b960a7d63 fix clippy lint warning 2025-08-08 22:08:13 +02:00
Markus Triska
c5fd4c1d8a support newly added representation_error/1 in answer descriptions 2025-08-08 21:34:23 +02:00
Markus Triska
7dc6d6e4e0 preliminary support for a subset of quads introduced by @UWN
This lets us embed toplevel interactions in Prolog programs.
Embedded toplevel interactions are currently ignored.

Example:

   :- use_module(library(lists)).

   ?- member(X, "abc").
      X = a
   ;  X = b
   ;  X = c.
2025-08-08 18:44:25 +02:00
Markus Triska
1d643d8385 add newly available library(process) to the list of libraries
Thank you a lot @Skgland for this extremely valuable contribution!
2025-08-05 17:51:08 +02:00
Markus Triska
badd6304c7 mention the DEDUCTION Programme 2025-08-03 14:32:23 +02:00
Markus Triska
a8da2b6a99 ISO: remove nonstandard operator meta_predicate.
Use functional notation instead for declarations.

This addresses #2822.
2025-08-02 10:22:50 +02:00
Mark Thom
a43bac8fd8 Merge pull request #3021 from mthom/rebis-dev
Merge rebis-dev to master
2025-08-02 00:01:39 -07:00
Mark Thom
72d5574ff0 Merge pull request #3009 from Skgland/process
adds predicates for spawning new processes without a shell
2025-08-01 23:18:36 -07:00
Bennet Bleßmann
a2e19bd483 add process module to all_modules test 2025-08-01 21:31:58 +02:00
Bennet Bleßmann
d907f86c8d use call_with_error_context 2025-08-01 20:49:43 +02:00
Bennet Bleßmann
fadd3a0839 use named vars instead of wildcards
makes updating tests easier as globs are sometimes lost when using TRYCMD=overwrite
2025-08-01 20:49:35 +02:00
Bennet Bleßmann
45041be336 fix culprit 2025-08-01 20:49:24 +02:00
Bennet Bleßmann
b2d639b159 fix arity of prcess_wait builtin errors 2025-08-01 20:49:14 +02:00
Bennet Bleßmann
3a6b92d227 more tests 2025-08-01 20:49:03 +02:00
Bennet Bleßmann
409159d68d adjust/add tests 2025-08-01 20:48:55 +02:00
Bennet Bleßmann
143f32be23 adjust options checking and add more tests 2025-08-01 20:48:44 +02:00
Bennet Bleßmann
d0a6dc9df2 address comment by triska
https://github.com/mthom/scryer-prolog/pull/3009#discussion_r2233221091
2025-08-01 20:48:34 +02:00
Bennet Bleßmann
62e43a3ab0 use functor/3 for must_be_known_options 2025-08-01 20:48:24 +02:00
Bennet Bleßmann
eb82d1b6d4 reformat ; 2025-08-01 20:48:13 +02:00
Bennet Bleßmann
70d65bcea8 add another test and remove unecessary module qualification 2025-08-01 20:48:03 +02:00
Bennet Bleßmann
25edde2eb4 replace filter by tfiltert and fix Pipe{Reader,Writer} streams 2025-08-01 20:47:51 +02:00
Bennet Bleßmann
ab675e071a adjust error kind 2025-08-01 20:47:41 +02:00
Bennet Bleßmann
dc08a4ab11 get process_create working and add tests 2025-08-01 20:47:22 +02:00
Bennet Bleßmann
1120bcde29 add documentation 2025-08-01 20:47:11 +02:00
Bennet Bleßmann
dc495f10f8 change behaviour in supposedly unreachable cases 2025-08-01 20:46:31 +02:00
Bennet Bleßmann
d2ffd4f4bf adjust error for duplicate options 2025-08-01 20:35:12 +02:00
Bennet Bleßmann
87dbad2294 fix rename pid to process 2025-08-01 20:35:01 +02:00
Bennet Bleßmann
ca52c65902 don't remove the child on wait/kill
- important for wait with timout(0) as we may want to try again until the process has realy exited.

- make process_release release the process instead
2025-08-01 20:33:15 +02:00
Bennet Bleßmann
7f233da10c fix timeout default value in process_wait/3 2025-08-01 20:28:17 +02:00
Bennet Bleßmann
ff546a0f9a incorporate suggestion by triska 2025-08-01 20:28:07 +02:00
Bennet Bleßmann
746d4fd106 make atom!() with a new value less annoying 2025-08-01 20:27:53 +02:00
Bennet Bleßmann
97e2e5d7f0 implement process_release/1, process_wait/2, process_wait/3, and process_kill/1 2025-08-01 20:27:27 +02:00
Bennet Bleßmann
1ee4f7a55f store child process in machine state 2025-08-01 20:21:36 +02:00
Bennet Bleßmann
43dd1587fb handle some error cases and replace unwrap with expect 2025-08-01 20:21:23 +02:00
Bennet Bleßmann
8971809c83 adjust errors 2025-08-01 20:21:13 +02:00
Bennet Bleßmann
e321f29b9c rename pid to process 2025-08-01 20:21:02 +02:00
Bennet Bleßmann
129c80bf16 undo changes to error.pl 2025-08-01 20:20:52 +02:00
Bennet Bleßmann
183761eba4 adjust default cwd 2025-08-01 20:20:41 +02:00
Bennet Bleßmann
6c7833b9c7 restructure option parsing 2025-08-01 20:20:31 +02:00
Bennet Bleßmann
82e989f631 add comments and try to fix binding the child process pid 2025-08-01 20:20:20 +02:00
Bennet Bleßmann
2b052bf8dd fix more things 2025-08-01 20:20:09 +02:00
Bennet Bleßmann
003e9d4610 get it working 2025-08-01 20:19:54 +02:00
Bennet Bleßmann
d79ece2497 fix indices 2025-08-01 20:18:44 +02:00
Bennet Bleßmann
ae0baf4893 [WIP] add support to spawn new processes 2025-08-01 20:18:13 +02:00
Bennet Bleßmann
1114700ce6 ignore test making network requests 2025-08-01 20:06:07 +02:00
Bennet Bleßmann
dea43a0244 update docs 2025-08-01 19:42:02 +02:00
Bennet Bleßmann
0c2c6124eb support cstr as an ffi return type and do some more restructuring 2025-08-01 19:41:56 +02:00
Bennet Bleßmann
9cccd509e3 no longer skip f32 and f64 now that they work consistently 2025-08-01 19:11:02 +02:00
Bennet Bleßmann
36bdab84ba further cleanup
- replace macros with functions
- stop abusing allocation error
2025-08-01 19:10:49 +02:00
Bennet Bleßmann
cf51338a77 further ffi cleanup 2025-08-01 19:10:38 +02:00
Bennet Bleßmann
f738b42e49 don't panic on unexpected/invalid value 2025-08-01 19:10:27 +02:00
Bennet Bleßmann
f45426e8ab also accept rust type name 2025-08-01 19:10:15 +02:00
Bennet Bleßmann
3d2439c92b use libffi::middle instead of libffi::low were possible 2025-08-01 19:09:56 +02:00
Bennet Bleßmann
6205f2f1f1 add a simple ffi test using structs 2025-08-01 19:08:32 +02:00
Bennet Bleßmann
760e1d2aac fix UB in ffi tests 2025-08-01 19:08:24 +02:00
Bennet Bleßmann
e1246f0c83 add new test helper 2025-08-01 19:08:02 +02:00
Bennet Bleßmann
bd1f8bb37e make ffi support full {i,u}64 range 2025-08-01 19:07:07 +02:00
Bennet Bleßmann
620459ea1e fix {i,u}64 in ffi 2025-08-01 18:37:48 +02:00
Bennet Bleßmann
d2502b0520 fix all but {i,u}64 2025-08-01 18:37:35 +02:00
Bennet Bleßmann
34eab2e73a fix crash when trying to load and ffi library with an invalid type specification 2025-08-01 18:22:15 +02:00
Bennet Bleßmann
db3f2717bc add more ffi tests 2025-08-01 18:22:14 +02:00
Bennet Bleßmann
7227e1d97c cleanup and fix miri & cross-compile 2025-08-01 18:22:13 +02:00
Bennet Bleßmann
9d8906da30 add ffi tests using f64 2025-08-01 18:22:01 +02:00
Mark Thom
f524062e5b Merge pull request #2961 from rotu/patch-5
Document `when/2` Condition
2025-07-31 22:10:32 -07:00
Mark Thom
eb29390a79 Merge pull request #3017 from triska/adapt_link
adapt link to Scryer Prolog Meetup 2024
2025-07-31 22:09:54 -07:00
Mark Thom
f91aedcc2f Merge pull request #3019 from Skgland/rebis-dev_fix-clippy
fix clippy
2025-07-31 22:09:41 -07:00
Bennet Bleßmann
4f04d2dfca replace .skip(n).next() with .nth(n) 2025-07-31 21:47:12 +02:00
Bennet Bleßmann
de89a78cbb remove unecessary cast 2025-07-31 21:47:11 +02:00
Bennet Bleßmann
e7600884fb remove unecessary into_iter 2025-07-31 21:47:11 +02:00
Bennet Bleßmann
3365cffa96 prefere for loop 2025-07-31 21:47:10 +02:00
Bennet Bleßmann
df3f1236f7 replace always erroring of_else with map_err 2025-07-31 21:47:09 +02:00
Bennet Bleßmann
8766851919 replace single non-wildcard pattern match with if let 2025-07-31 21:47:09 +02:00
Bennet Bleßmann
014d1b0095 remove already implied must_use 2025-07-31 21:47:08 +02:00
Bennet Bleßmann
c885d1a7e7 collaps els-if / if-if 2025-07-31 21:47:08 +02:00
Bennet Bleßmann
7593f88d5a ingore nerver looping loop, but add a todo 2025-07-31 21:47:07 +02:00
Bennet Bleßmann
6885074006 fix clippy::unit_arg 2025-07-31 21:47:07 +02:00
Bennet Bleßmann
73cc872b50 check not empty instead of len > 0 2025-07-31 21:47:06 +02:00
Bennet Bleßmann
fae5e13bd5 impl From rather than Into 2025-07-31 21:47:05 +02:00
Bennet Bleßmann
6d7c217227 fix unecessary mut 2025-07-31 21:47:05 +02:00
Bennet Bleßmann
166ec02973 ignore clippy::unbuffered_bytes in test helper functions 2025-07-31 21:47:04 +02:00
Bennet Bleßmann
1d26f98688 fix legacy int constants 2025-07-31 21:47:04 +02:00
Bennet Bleßmann
58b9a6ad69 ignore wrong self convention 2025-07-31 21:47:03 +02:00
Bennet Bleßmann
a639fec153 fix match/if-let can be simplified to ? 2025-07-31 21:47:03 +02:00
Bennet Bleßmann
495bcd73f2 fix unecessary return 2025-07-31 21:46:52 +02:00
Bennet Bleßmann
ae3019d923 fix unecessary reference/dereference 2025-07-31 21:46:51 +02:00
Bennet Bleßmann
72631b3e0b fix clone on copy values 2025-07-31 21:28:39 +02:00
Bennet Bleßmann
8cc74b2af7 fix clippy::uninlined_format_args 2025-07-31 21:26:08 +02:00
Bennet Bleßmann
7199e9a2db remove outdated comment 2025-07-31 20:07:57 +02:00
Bennet Bleßmann
edf21494d9 also run CI on rebis-dev 2025-07-31 20:07:07 +02:00
Markus Triska
b364c9073a adapt link to Scryer Prolog Meetup 2024
An update of the site has caused a change in the address.
2025-07-28 18:55:59 +02:00
Mark Thom
9b293cf1b6 detect end_of_file before end_of_stream in get_char (#2990) 2025-07-22 20:39:52 -07:00
Mark Thom
65dda019a2 allow abolish_clause to abolish empty dynamic clauses (#3010) 2025-07-20 16:55:07 -07:00
Mark Thom
4aa2a45736 fix variadic_functor 2025-07-16 21:52:40 -07:00
Mark Thom
4efceda8c5 fix parsing partial number tokens in other radixes (#3000) 2025-07-14 23:05:10 -07:00
Mark Thom
5dc8983eec Merge pull request #3003 from rotu/patch-8
CI: run clippy even if fmt fails
2025-07-13 21:22:24 -07:00
Dan Rose
49b30e9f81 Merge branch 'mthom:master' into patch-5 2025-07-08 18:03:16 -05:00
Mark Thom
b78ccf8f28 fmt improvements 2025-07-08 13:47:08 -07:00
Dan Rose
2dc66d33dd CI: run clippy even if fmt fails 2025-07-08 11:51:13 -05:00
Mark Thom
e303e5a805 correct number_chars (#2976) 2025-07-07 22:44:05 -07:00
Mark Thom
762b63e1f4 use granular hierarchical locks in offset_table.rs 2025-07-07 22:44:02 -07:00
Mark Thom
2844b5a958 synchronize offset table growth with the borrowing of offset pointers 2025-07-07 22:39:47 -07:00
Mark Thom
1332611f83 use OffsetTableImpl without synchronization by default 2025-07-07 22:39:47 -07:00
Bennet Bleßmann
725def07cd fix crash when loading html 2025-07-07 22:39:47 -07:00
Bennet Bleßmann
cbdd0fbf15 make Fixnum::build_with harder to accidentally misuse
change trait bound order for better
2025-07-07 22:39:34 -07:00
bakaq
87ca083cfa Align the heap to the size of heap cells 2025-07-07 22:38:12 -07:00
bakaq
d01557f3c1 Add scan_slice_to_str_from_start 2025-07-07 22:38:12 -07:00
Mark Thom
8b009448f4 correct threshold marking in copy_structure (#2920) 2025-07-07 22:38:12 -07:00
Markus Triska
709dc041eb FIXED: correct partial string tail calculation in arg/3
This addresses another aspect of #2924, found by @haijinSk.
Thank you again!

Example:

    ?- "aaaaaaa" = [_,_,_,_,_,_|T], arg(2, T, 2).
       false.
2025-07-07 22:38:12 -07:00
Markus Triska
8763a42c98 FIXED: arg/3 for partial strings
This address #2924, reported by @haijinSk. Thank you a lot!

Example:

    ?- arg(2, "a", A).
       A = [].

The fact that such a mistake in macro usage is even possible could be
a sign that the macro definition should be stricter.
2025-07-07 22:38:12 -07:00
Mark Thom
d6b6eda77d fix cont function crashes (#2920) 2025-07-07 22:38:12 -07:00
Mark Thom
4e0493474e replace deprecated unify_complete_string call with allocate_cstr 2025-07-07 22:38:12 -07:00
bakaq
a9847eef65 Migrate to strict and exposed provenance 2025-07-07 22:38:12 -07:00
Mark Thom
cb9b988905 allow unused_parens around let statement in functor! macro 2025-07-07 22:38:12 -07:00
Markus Triska
073ec4c1d0 FIXED: invoke correct predicate
Noted by Oleg Finkelstein. Many thanks!
2025-07-07 22:38:12 -07:00
Markus Triska
d51cbd67e0 ENHANCED: partial_string/3 no longer creates atoms
As a consequence, resulting strings are now quickly reclaimed on
backtracking.

This addresses #2912.

Test case:

    :- use_module(library(iso_ext)).
    :- use_module(library(lists)).

    ab(a).
    ab(b).

Sample query:

    ?- length(Ls, 1_000_000),
       maplist(ab, Ls),
       partial_string(Ls, Es0, []),
       Es0 == Ls.
       Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..."
    ;  Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..."
    ;  Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..."
    ;  Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..."
    ;  Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..."
    ;  ... .

running in constant memory.
2025-07-07 22:38:12 -07:00
Markus Triska
e9bb41f0d6 ENHANCED: use a fast test for the expected case of chars in atom_chars/2 etc.
Suggested by Oleg Finkelstein, thank you a lot!

Example, before this change:

    ?- t+\(length(As, 1_000_000), maplist(=(a), As), time(atom_chars(A, As))).
       % CPU time: 0.693s, 7_000_041 inferences
       true.

Now:

    ?- t+\(length(As, 1_000_000), maplist(=(a), As), time(atom_chars(A, As))).
       % CPU time: 0.080s, 40 inferences
       true.

This also partially ameliorates #2907.
2025-07-07 22:38:12 -07:00
Mark Thom
b12d1ece17 correct heap-to-cell-index comparison in copy_slice_to_end (#2906) 2025-07-07 22:38:12 -07:00
Mark Thom
706ffe7ad9 fix functor! size calculations around indexing_code_ptr 2025-07-07 22:38:12 -07:00
Mark Thom
258244caf2 restore tab completion to REPL (#2575) 2025-07-07 22:38:12 -07:00
Mark Thom
39ea2d5899 make self.s_offset use bytes in case of HeapPtr::PStr in UnifyVoid (#2897) 2025-07-07 22:38:12 -07:00
Mark Thom
41b90c6e46 correct heap_print.rs for null characters being excluded from pstr regions of heap (#2890) 2025-07-07 22:38:12 -07:00
Mark Thom
6bcbb91e08 correctly increment s_offset for partial strings (#2897) 2025-07-07 22:38:12 -07:00
Mark Thom
e1e52338d6 fix typo in try_from_partial_string 2025-07-07 22:38:12 -07:00
Mark Thom
995a39419a fix read_s logic around HeapPtr::PStrLoc (#2894) 2025-07-07 22:38:12 -07:00
Mark Thom
4644ea2404 repair cyclic PStrLoc handling in heap_print.rs 2025-07-07 22:38:12 -07:00
Mark Thom
f3cd6326a3 remove compare_pstr_to_string and related result type 2025-07-07 22:38:12 -07:00
Markus Triska
bf31d3f9a9 ENHANCED: dedicated faster branches for repositionable streams
rebis-dev makes the speed difference especially apparent due to the
linear scan of strings on the heap in partial_string_tail/2 which is
now avoided for repositionable streams, notably files.

This addresses #2888 reported and analyzed by @haijinSk. Many thanks!
2025-07-07 22:38:12 -07:00
Mark Thom
4c46f0e54d correct GetPartialString (#2887) 2025-07-07 22:38:12 -07:00
Mark Thom
e563fd8e4f generalize compare_pstr_segments 2025-07-07 22:38:12 -07:00
Mark Thom
1297a24469 ensure '\0' atom is static & never inlined (#2880) 2025-07-07 22:38:12 -07:00
Mark Thom
907e64e185 fix root reading of complete strings (#2882) 2025-07-07 22:38:12 -07:00
Mark Thom
46f259bf7d some cosmetic tweaks 2025-07-07 22:38:12 -07:00
Markus Triska
634ccf22aa mark done item 2025-07-07 22:38:12 -07:00
Mark Thom
16b3bea48e correct and simplify compute_pstr_size 2025-07-07 22:38:12 -07:00
Mark Thom
e20363b462 correct create_partial_string (#2593) 2025-07-07 22:38:12 -07:00
Mark Thom
549a26dd03 restore more tabu_list use to compare_term_tests (#2633) 2025-07-07 22:38:12 -07:00
Mark Thom
8981ab72d1 restore tabu_list insertions to PStr-Lis comparisons (#2636) 2025-07-07 22:38:12 -07:00
Mark Thom
98dae9aecc do not allow strings containing null characters to be inlined (#2848) 2025-07-07 22:38:12 -07:00
Mark Thom
22080f3787 move CodeIndex to F64Table-like table 2025-07-07 22:38:12 -07:00
Mark Thom
9e1e99f961 Revert "remove Term"
This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a.
2025-07-07 22:38:10 -07:00
Mark Thom
eef7b06919 make write_with forward return values, use it to correct partial string handling 2025-07-07 22:02:27 -07:00
Mark Thom
2ad870c740 read Str focus properly in build_meta_predicate_clause 2025-07-07 22:02:27 -07:00
Mark Thom
3dee07f648 some fixes in response to miri 2025-07-07 22:02:27 -07:00
bakaq
9daf016d63 Fix parsing of \x0\ in partial strings 2025-07-07 22:02:27 -07:00
Mark Thom
fadcfb966e copy partial string blocks properly in all solutions predicates 2025-07-07 22:02:27 -07:00
Mark Thom
57f76169fd run cargo fmt 2025-07-07 22:02:27 -07:00
Mark Thom
ae4d12a123 remove pstr_vec 2025-07-07 22:02:27 -07:00
Mark Thom
3c85ef2724 globalize ALIGN_CELL/ALIGN, fix compute_pstr_size 2025-07-07 21:59:50 -07:00
Emilie Burgun
15f1320d05 Fix allocate_pstr randomly refusing to properly allocate memory
This one was a toughie: it turns out that using `ptr::align_of()`` was
a bad idea, since the buffer in `Heap` itself is not aligned to
`Heap::heap_cell_alignment()`, so `ptr::align_of()` would sometimes
return lower values than expected.

That made for an heisenbug: if the alignment of the heap happened to be 4,
then the bug wouldn't trigger.
2025-07-07 21:59:50 -07:00
Emilie Burgun
7b357ba84d Fix Heap::drop not accounting for null-initialized HeapInner 2025-07-07 21:59:50 -07:00
Mark Thom
c0cd371056 dereference clause_clause value, reserve more parser space (#2579) 2025-07-07 21:59:50 -07:00
Mark Thom
79be0c0625 unmark_cell_bits! in push_literal (#2645) 2025-07-07 21:59:50 -07:00
Mark Thom
c0f72704ec introduce bespoke Heap type for in-heap partial strings 2025-07-07 21:59:50 -07:00
Mark Thom
f7bbdfe73a variable revision 2025-07-07 21:54:08 -07:00
Mark Thom
1ef681bd21 remove Term 2025-07-07 21:54:08 -07:00
Mark Thom
34ac85bb6d restore ubuntu testing to ci.yml with rust version 1.77 2025-07-07 21:40:36 -07:00
Mark Thom
a69303dc93 throw syntax error after parsing infinite floats (#2998) 2025-07-07 21:30:04 -07:00
Mark Thom
778068129f don't skip '.' char in parse_number_from_string (#2997) 2025-07-07 21:28:07 -07:00
Mark Thom
ce56b5ed6b modify number_token to produce partial lexing results (#2986) 2025-07-05 00:58:28 -07:00
Mark Thom
8e01eea440 be more careful about concatenating '.' in parse_number_from_string (#2986) 2025-07-01 18:40:49 -07:00
Mark Thom
1cf5de8f5c Merge pull request #2970 from notoria/clpz
Make `(mod)/2` stronger in CLP(Z)
2025-06-16 21:02:38 -07:00
Mark Thom
686f20db74 Merge pull request #2980 from triska/hophrase
use nonterminal indicators, correct meta_predicate/1 for higher-order phrase//N
2025-06-16 21:02:20 -07:00
Markus Triska
17377064cf use nonterminal indicators, correct meta_predicate/1 for higher-order phrase//N
Noted by @UWN in https://github.com/mthom/scryer-prolog/discussions/2872.

Many thanks!
2025-06-14 22:47:29 +02:00
Mark Thom
f49a0ae79b Merge pull request #2965 from rotu/zygomorphic-puma
Remove obsolete compatibility for Rust<1.80
2025-05-27 22:18:47 -07:00
notoria
4b480a7eab Strengthened (mod)/2 in CLP(Z)
?- 8 #= -1 mod #Y.
   clpz:(Y in 9..sup), clpz:(-1 mod#Y#=8). % unexpected
Expected: Y = 9
?- 8 #= -12 mod #Y.
   clpz:(Y in 9..sup), clpz:(-12 mod#Y#=8). % unexpected
Expected `Y` with finite domain
2025-05-25 13:39:31 +02:00
notoria
4a6f86591c Strengthened (mod)/2 in CLP(Z)
?- 0 #= 2 mod #Y.
   clpz:(Y in inf.. -1\/1..sup), clpz:(2 mod#Y#=0). % unexpected
Expected: clpz:(Y in-2.. -1\/1..2), clpz:(2 mod Y#=0)
2025-05-25 13:38:56 +02:00
notoria
37ac5bb3c1 Strengthened (mod)/2 in CLP(Z)
?- Z = 8, X = 9, #Z #= #X mod #Y.
   Z = 8, X = 9, clpz:(Y in 9..sup), clpz:(9 mod#Y#=8). % unexpected
Expected: false
2025-05-25 13:37:28 +02:00
Dan Rose
9456517bed Remove obsolete compatibility for Rust<1.80 2025-05-22 14:00:42 -05:00
Mark Thom
8f514ce419 Merge pull request #2955 from rotu/radical-cockroach
Remove xor as a builtin infix operator
2025-05-19 22:47:41 -07:00
Dan Rose
e40125ff3a Document when/2 Condition 2025-05-18 16:46:28 -05:00
Mark Thom
c790bbfce9 Merge pull request #2956 from bakaq/update_arcu_libffi
Update dependencies and fix breaking changes in libffi-sys and arcu
2025-05-13 21:26:29 -07:00
Dan Rose
b767e4de25 xor is not a standard operator 2025-05-13 20:32:59 -05:00
bakaq
ca173873af Update dependencies and fix breaking changes in libffi-sys and arcu 2025-05-13 19:53:13 -03:00
Mark Thom
036c59e5fa Merge pull request #2950 from triska/meetups
link to Scryer Prolog Meetup 2025 page and its announcement
2025-05-08 22:53:04 -07:00
Markus Triska
7809edca19 link to Scryer Prolog Meetup 2025 page and its announcement 2025-05-09 07:42:48 +02:00
Mark Thom
a42a88a2c9 Merge pull request #2802 from adri326/null-stream-safety
Fix UB when interacting with Stream::Null(_)
2025-05-01 17:35:30 -07:00
Mark Thom
9dab070c11 Merge pull request #2930 from triska/meetups
ADDED: Section about Scryer Prolog Meetups.
2025-04-30 18:51:43 -07:00
Markus Triska
ec28872a9a correct grammar 2025-04-30 19:58:45 +02:00
Markus Triska
eb96a0c957 ADDED: Section about Scryer Prolog Meetups. 2025-04-30 19:58:45 +02:00
Mark Thom
90f4716cc3 Merge branch 'null-stream-safety' of https://github.com/adri326/scryer-prolog into adri326-null-stream-safety 2025-04-29 23:32:48 -07:00
Mark Thom
3a6289324e Merge pull request #2901 from matteob8/patch-1
Update http_server.pl
2025-04-29 21:41:07 -07:00
Mark Thom
f496abbbef use loader:strip_subst_module/4 in second module check of retract/1 (#2891, #2893) 2025-04-22 23:28:19 -07:00
Mark Thom
f1793744bc Merge pull request #2905 from bakaq/bump-msrv
Bump MSRV and update flake.lock
2025-04-22 22:28:02 -07:00
bakaq
bd4b305649 Remove Ubuntu 20.04 runner 2025-04-22 18:21:50 -03:00
bakaq
638a765937 Bump MSRV and update flake.lock 2025-04-22 17:20:06 -03:00
Mark Thom
78fec46517 Merge pull request #2895 from hakujin/master
Update `libffi` and `libffi-sys` dependencies to fix aarch64 macOS build
2025-04-21 22:11:43 -07:00
matteob8
00a44921db Update http_server.pl
changed top/0 to the more meaningful run/0 name.
2025-04-21 20:54:43 +02:00
matteob8
d79bc199b3 Update http_server.pl
Avoid overwriting of predicate and made explicit reference to the loading of library(http/http_server).
2025-04-21 19:13:20 +02:00
Colin King
4da0f90097 Update libffi and libffi-sys dependencies to fix aarch64 macOS build
Pulls in latest `libffi` and `libffi-sys` dependencies to fix a
compilation error on aarch64 macOS builds.
2025-04-18 21:40:29 -05:00
Mark Thom
d18ef52e67 Merge pull request #2873 from constraintAutomaton/doc/update-readme-wasm-example
update of the WebAssembly example in README
2025-04-12 21:09:40 -07:00
Mark Thom
925921e9ab Merge pull request #2879 from triska/ad4m
enumerate applications, add AD4M by @coasys
2025-04-12 21:09:20 -07:00
Markus Triska
b98076b39e enumerate applications, add AD4M by @coasys 2025-04-12 09:05:28 +02:00
constraintAutomaton
3090cb0084 Example update to use iterable. 2025-04-12 07:18:00 +02:00
constraintAutomaton
971521791c Merge branch 'master' into doc/update-readme-wasm-example 2025-04-12 07:00:14 +02:00
Mark Thom
2c8041250d Merge pull request #2875 from constraintAutomaton/feature/wasm-result-iterator
Make `WasmQueryState` Iterable in JavaScript
2025-04-11 20:52:45 -07:00
Mark Thom
1b22c89211 mark cyclic lists with ellipses at the head (#2635) 2025-04-10 22:40:13 -07:00
constraintAutomaton
4e207fc34a Made WasmQueryState an iterable. 2025-04-10 19:02:04 +02:00
Mark Thom
8558bd2214 Merge pull request #2874 from triska/read_from_chars_instantiated
generalize read_from_chars/2 and read_term_from_chars/3 to allow instantiated Term
2025-04-10 08:47:21 -07:00
Markus Triska
ba9fed3eae generalize read_from_chars/2 and read_term_from_chars/3 to allow instantiated Term
This addresses part of #2871, raised by @haijinSk. Many thanks!
2025-04-10 08:18:23 +02:00
constraintAutomaton
024c498bee Fix DOM manipulation to avoid deprecated functions in Sudoku solver example. 2025-04-08 20:13:02 +02:00
constraintAutomaton
8c348a7160 better identation of the knowledge base. 2025-04-08 19:29:34 +02:00
constraintAutomaton
1f82dafcb6 Useless console.log in the example deleted. 2025-04-08 19:17:20 +02:00
constraintAutomaton
d2dfb7ccda Update README with working WebAssembly usage example. 2025-04-08 19:12:27 +02:00
Mark Thom
20525e5013 Merge pull request #2869 from triska/format_w
ENHANCED: format specifier ~w more faithfully emulates write/1
2025-04-06 15:31:59 -07:00
Markus Triska
14c8fc3e34 move ~w to least prominent position, point to more suitable specifiers
In particular, "~q" is a safe better choice.
2025-04-05 10:01:22 +02:00
Markus Triska
3d60094330 ENHANCED: format specifier ~w more faithfully emulates write/1
In particular, variables now start with "_".

Example:

    ?- format("~w", [X]).
    %@ _A   true.

Found thanks to a discussion initiated by @haijinSk:

    https://github.com/mthom/scryer-prolog/discussions/2863
2025-04-05 09:58:06 +02:00
Mark Thom
ae27e78d80 Merge pull request #2861 from averms-forks/update-deps
Update and clean up dependencies.
2025-03-31 19:49:54 -07:00
Mark Thom
3826ef38cd Merge pull request #2860 from averms-forks/push-spzqsznlnlnm
Use backticks when referencing predicate in docs.
2025-03-31 19:49:46 -07:00
Aman Verma
7b6f4439bb Install correct locked version of iai-callgrind-runner in CI. 2025-03-31 04:11:16 -05:00
Aman Verma
464cfd9213 Update lexical.
The previous versions of lexical and lexical-core we were using were
subject to the following security advisories:

- https://rustsec.org/advisories/RUSTSEC-2023-0086
- https://rustsec.org/advisories/RUSTSEC-2023-0055
2025-03-31 04:11:16 -05:00
Aman Verma
9dbf592a58 Remove unused deps: regex, assert_cmd, predicates-core.
regex was introduced in commit 9e85be11fe
but isn't used anymore.

assert_cmd and predicates-core were introduced in
e1c681fffe for tests but aren't used
anymore.

Dependency count in Cargo.lock drops from 428 to 421.
2025-03-31 04:11:15 -05:00
Aman Verma
e273b007a2 Update ordered-float to 5.0.0. 2025-03-31 04:11:15 -05:00
Aman Verma
6df4eaf809 Update scraper and ego-tree.
This gets rid of 4 dependencies, as verified by the output of

    yj -tj < Cargo.lock | jq -c '.package | length'

Previously it was 432, now it is 428.
2025-03-31 04:11:15 -05:00
Aman Verma
165d47c7b5 Bump dependencies except for arcu v0.1.1 and half 2.4.1.
arcu is not updated for reasons laid out in issue #2749.
half is not updated because going to 2.5.0 would require an MSRV bump 1.81.

Previous versions of idna, openssl, and ring were subject to the
following security advisories:

- https://rustsec.org/advisories/RUSTSEC-2025-0009
- https://rustsec.org/advisories/RUSTSEC-2025-0004
- https://rustsec.org/advisories/RUSTSEC-2024-0421
2025-03-31 04:10:34 -05:00
Aman Verma
a45a1f6197 Use backticks when referencing predicate in docs.
Trivial change but this prevents the HTML output from being erroneously italicized.
2025-03-27 18:56:38 -05:00
Mark Thom
16187390cd Merge pull request #2847 from triska/call_with_error_context
ADDED: type pair
2025-03-09 13:21:25 -07:00
Markus Triska
57bf1ec39b ADDED: type pair 2025-03-08 14:42:48 +01:00
Mark Thom
7ac84d3565 Merge pull request #2846 from triska/call_with_error_context
ADDED: call_with_error_context/2
2025-03-08 00:39:03 -08:00
Markus Triska
32d91449b5 ADDED: call_with_error_context/2
See https://github.com/mthom/scryer-prolog/discussions/2839 for more information.
2025-03-08 09:12:17 +01:00
Mark Thom
3799974b82 Merge pull request #2837 from notoria/next
Fix conversion from float to rational
2025-03-01 13:40:09 -08:00
Mark Thom
9da0a06afa Merge pull request #2836 from triska/format_floats
Correct handling of floats in format/2 and portray_clause/1
2025-03-01 01:45:55 -08:00
Markus Triska
b8526e0510 FIXED: portray_clause/1 for numbers 2025-02-28 08:41:19 +01:00
Markus Triska
2d4fcf9714 correct handling of floats with N digits (~f and ~Nf)
This addresses #2771. Many thanks to @tmerr for reporting the issue!

The code was posted by @UWN in:

    https://github.com/mthom/scryer-prolog/discussions/2805

Many thanks! With additional inputs by @adri326 and @notoria, who also
posted interesting approaches which could help to increase precision
in cases that are currently not ideally handled. Thank you all!

Please see the issue and discussion for more information.
2025-02-28 08:40:53 +01:00
notoria
4f3843742c Fix conversion from float to rational 2025-02-28 08:00:00 +01:00
Mark Thom
a0e3283d64 Merge pull request #2835 from thierrymarianne/fix-http_open-hanging-on-top-of-main-branch
Prevent http_open/3 from hanging
2025-02-27 21:38:58 -08:00
Mark Thom
c9a0f3332e Merge pull request #2792 from triska/must_be_chars
FIXED: instantiation and type check for string arguments
2025-02-27 21:26:40 -08:00
Mark Thom
aeacccbe4c Merge pull request #2825 from bakaq/wasm_rework
Wasm rework
2025-02-27 21:26:20 -08:00
revue_2_presse
5d468d3e19 Replace futures::executor::block_on with tokio::block_in_place 2025-02-25 20:31:19 +01:00
bakaq
080a4fed03 Documentation 2025-02-20 01:04:38 -03:00
bakaq
3b89c1124d Consult modules 2025-02-20 01:04:38 -03:00
bakaq
236ed93c6c Send pure objects instead of classes 2025-02-20 01:04:38 -03:00
bakaq
cea8e6b1c9 MachineBuilder constructor 2025-02-20 01:04:38 -03:00
bakaq
93e804eeaa Rework Wasm interface 2025-02-20 01:04:38 -03:00
bakaq
b32273fc79 Make Wasm compilable 2025-02-20 01:04:38 -03:00
Mark Thom
4fc4152eac Merge pull request #2817 from adri326/fix-2815-run_module_predicate-backtrack
Fix backtracking on the topmost predicate triggering UB in run_module_predicate
2025-02-16 22:47:49 -08:00
Mark Thom
914318b14e Merge pull request #2799 from bakaq/callback_streams
Callback streams for use as library
2025-02-16 22:47:34 -08:00
bakaq
3fc5709c50 Add builder style configuration of user input, output and error 2025-02-16 04:04:48 -03:00
bakaq
28926486e0 More stream tests 2025-02-16 04:04:48 -03:00
bakaq
ad211d5e05 Disallow null streams in output 2025-02-16 04:04:48 -03:00
bakaq
5386c183d2 Make input and output stream configuration public 2025-02-16 04:04:48 -03:00
bakaq
0a2457943e Configure streams separately 2025-02-16 04:04:48 -03:00
bakaq
baae1dca15 Refactor UserInput to use channels 2025-02-16 04:04:48 -03:00
bakaq
4e032c8a28 Test for callback streams 2025-02-16 04:04:48 -03:00
bakaq
7a6620b52d Add input stream channel 2025-02-16 04:04:48 -03:00
bakaq
dd6533e76c Add callback streams 2025-02-16 03:52:52 -03:00
Mark Thom
d262159399 Merge pull request #2791 from Skgland/patch-1
Expand the build/install section of the readme
2025-02-12 23:25:21 -08:00
Mark Thom
c77ea48fbd Merge pull request #2804 from dnmfarrell/line-count-off-by-one
Line numbers start at 1
2025-02-12 23:23:44 -08:00
Mark Thom
35c1880937 Merge pull request #2818 from adri326/stream-cleanup
Fix various issues around close/1 and stream realiasing
2025-02-12 23:23:11 -08:00
Mark Thom
e5cca9d10a Merge pull request #2812 from bakaq/attr_vars_arity_fix
Fix bug in finding arity for verify attributes
2025-02-12 23:19:34 -08:00
Emilie Burgun
f45b0bcfe8 Remove redundant alias resolution in at_end_of_stream/1, add corresponding tests for null streams
Also fixed at_end_of_stream/0 leaving a choicepoint.
2025-02-07 15:05:01 +01:00
Emilie Burgun
8966e175f1 [fixup] return that reading from a null stream wrote 0 bytes to the buffer 2025-02-07 14:35:27 +01:00
Emilie Burgun
2a218f34b9 Test corner cases of stream aliasing 2025-02-06 23:47:22 +01:00
Emilie Burgun
d8213e29c5 Fix set_output/1 and set_input/1 not updating the alias
Before this change, the following set of queries would behave incorrectly:

```
?- open("/tmp/out.log", write, S), set_output(S).
   prints(""), write("/tmp/out.log", "S = stream(...)").
?- write(user_output, hello).
   prints("hello"), unexpected.
   prints(""), write("/tmp/out.log", "hello"). % Expected, but not found.
```

Now, `set_output/1` and `set_input/1` properly bind the `user_output` and
`user_input` aliases, making the queries above behave as expected.
2025-02-06 23:01:38 +01:00
Emilie Burgun
7f2ce57ba7 Fix stream realiasing possibly shadowing other streams. 2025-02-06 23:01:33 +01:00
Emilie Burgun
949d316773 Fix realiased streams causing close/1 to leave a dangling stream 2025-02-06 23:00:00 +01:00
Emilie Burgun
0cf46d3ec4 Encapsulate accesses to IndexStore::streams and ::stream_aliases
These two fields are able to hold `Stream` instances, which predicates like `close/1`
expect to be managed properly for their correctness. To ensure that this is the case,
I have removed direct accesses to those two fields, so that they can be properly managed
in one place.
2025-02-06 23:00:00 +01:00
Emilie Burgun
e68ac8347f Document run_module_predicate and handle critical failure in toplevel.pl 2025-02-06 13:36:23 +01:00
Emilie Burgun
d4bf52e82c Disable test_run_module_predicate_throw under miri and support rustc < 1.83 2025-02-06 10:37:54 +01:00
Emilie Burgun
22538a05be Fix backtracking on the topmost predicate triggering UB in run_module_predicate
Fixes #2815, see that issue for my investigation.

This is a one-line fix that I'm quite proud of :)

If the topmost query for `run_module_predicate` needs to backtrack,
then before this commit, one of the following two things may happen:
- A dangling OrFrame is read at stack offset 0
- An AndFrame was at stack offset 0 would be read as an OrFrame

This can be seen by either calling `run_module_predicate` with a
throwing predicate (encountering the second scenario) or a failing
predicate (encountering the first scenario), or by running the following
in the REPL, which triggers a `throw/1` within the error handler, propagating
it all the way up (and encountering the second scenario):

```prolog
?- current_output(S), open(stream(S), write, S0, [type(binary)]).
```

Currently, `Stack` is not equipped with tools to detect this incorrect
behavior, so it would instead try to read an OrFrame at offset 0, which
triggers UB, since transmuting between AndFramePrelude and OrFramePrelude
isn't legal.

In practice, since `AndFramePrelude` is smaller, the later fields of
`OrFramePrelude` would read from the cells following the `AndFramePrelude`,
and would contain nonsensical data, triggering the panic that led to
my investigation in #2815 and that is fairly reliable to witness.

Surprisingly, this wouldn't happen with `run_query`, which led me to
look at how they operate differently. It turns out that `run_query`
inserts an OrFrame at offset 0, which covers both problematic scenarios.

The fix is thus to simply add a call to `Machine::allocate_stub_choice_point`
in `run_module_predicate` :)
2025-02-06 00:43:01 +01:00
bakaq
6d80c843e6 Scan entire predicate in InstallVerifyAttr 2025-02-05 11:40:05 -03:00
bakaq
b8ccebbf24 Fix bug in finding arity for verify attributes 2025-02-04 04:11:11 -03:00
Emilie Burgun
7108e87e92 Make Stream::Null behave like /dev/null 2025-02-03 00:12:03 +01:00
Emilie Burgun
fdc35f8b40 Fix UB caused by interactions with null streams 2025-02-03 00:08:37 +01:00
Emilie Burgun
2fe7b55343 Fix close/1 messing up stream_aliases when user_input or user_output aren't set to Stdin and Stdout 2025-02-03 00:07:39 +01:00
David Farrell
f509d3d66f Line numbers start at 1
Bumps the line number for the singleton warning. When the singleton
occurs on the same line at the term starts, the line number is correct:

    foo(X).

However it stills mis-reports this line number as 1 instead of 5:

    foo(1) :-
        true,
        true,
        true,
        Y.

See issue #1356.
2025-02-02 08:16:05 -05:00
Emilie Burgun
079a69396a Add debug asserts to UntypedArenaPtr::build_with, ::get_tag and raw_ptr_as_cell!
These two functions are pretty unsafe, but having these assertions makes
it easier to catch UB in testing.
2025-01-31 15:15:52 +01:00
Mark Thom
c548b14f50 Merge pull request #2798 from bakaq/clippy_warnings
Fix clippy warnings
2025-01-28 23:24:17 -07:00
bakaq
590d0daa24 Fix clippy warnings 2025-01-28 16:49:41 -03:00
Bennet Bleßmann
7a5a5bb795 fix spelling and grammar errors found by mthom
https://github.com/mthom/scryer-prolog/pull/2791#discussion_r1930025598
2025-01-27 20:40:12 +01:00
Mark Thom
5a869e8b48 Merge pull request #2777 from adri326/fix-2772-rnd_i-clipping
Fix invalid casts in is/2
2025-01-26 23:14:57 -07:00
Mark Thom
28678e708b Merge pull request #2738 from adri326/fix-2275-dcgs-call-module
Fix dcgs using call(M:Pred) when M was left unassigned
2025-01-26 23:14:30 -07:00
Mark Thom
f69c58c6b6 Merge pull request #2793 from Skgland/fix-ci
fix ci and update all used actions
2025-01-26 23:02:23 -07:00
Emilie Burgun
0cde8f9a43 Add integration tests for arithmetic operators
This extensively tests the behavior of is/2, both when compiled and in metacalls.
2025-01-27 00:10:56 +01:00
Emilie Burgun
20735ea34c Fix integer overflow in >>/2 and <</2 2025-01-27 00:10:47 +01:00
Emilie Burgun
f3a92c6551 Fix min/2 and max/2 returning the cast version of its arguments
It now behaves the same way as SWI-Prolog.
2025-01-27 00:06:06 +01:00
Emilie Burgun
e2d1a2b6bc Fix X is gcd(1, 2 ^ 64) triggering a panic
The implementation for gcd/2 would cast the second argument to an isize.
2025-01-27 00:06:06 +01:00
Emilie Burgun
d3361c16d8 Fix round() losing precision on bigints
The original issue can be reproduced with `X is round(2 ^ 54 + 1) - 2 ^ 54, X = 1.`
2025-01-27 00:05:30 +01:00
Emilie Burgun
9420c7e41e Fix rnd_i clipping floats that don't fit in Fixnum
Fixes #2772.

The current implementation of `rnd_i` incorrectly casts `f` (an `f64`)
into an `i64`, before casting it into an `Integer`.

This fixes that issue by using `Integer::try_from(f)` instead,
and failing if `f` is infinite or NaN.

A fixme is left for a future PR to properly handle the resulting errors
in floor/1 and friends (right now they can only be triggered through FFI).
2025-01-27 00:02:04 +01:00
Bennet Bleßmann
a7598184bf fix typo 2025-01-24 18:47:42 +01:00
Markus Triska
bc0f614bf9 FIXED: instantiation and type check for string arguments
This addresses #2790.

The issue first appeared in an example reported by @ak-1 in #2788, and
was successfully analyzed by @flexoron. Many thanks!
2025-01-23 20:18:55 +01:00
Bennet Bleßmann
b1e66f686b Update README.md
fix ambiguity regarding the install location for the cargo install method, also include the binary name
2025-01-23 20:04:43 +01:00
Bennet Bleßmann
b74c8139d1 fix ci and update all used actions 2025-01-23 19:53:59 +01:00
Bennet Bleßmann
75d499bf8a update install link 2025-01-23 19:20:19 +01:00
Bennet Bleßmann
f1100271e2 Update README.md 2025-01-23 19:18:15 +01:00
Bennet Bleßmann
143430dd9c Update README.md 2025-01-23 19:11:08 +01:00
Mark Thom
00e6e323f8 Merge pull request #2768 from robstolarz/RSTO-nix-macos-fix
fix: compile under Nix flake on macOS
2025-01-13 22:15:11 -07:00
Emilie Burgun
b76bdd75e4 Fix #2725 by calling load_context/1 in the unspecified branch of strip_module/3
This fixes #2725, by making it so that `strip_module(Pred, M, P), call(M:P)`
doesn't throw an `instanciation_error` when `Pred` isn't in the form `module:predicate`.

Now, `strip_module(hello, M, P)` will call `load_context(M)`, which unifies `M`
with the topmost module (or `user`).

Two new test cases are added: issue2725.pl, which tests the minimal case id(X) --> X.
and the strip_module(P, M, _), call(M:P) scenario, and module_resolution,
which tests the behavior of strip_module in a few scenarios.
2025-01-12 14:08:28 +01:00
Mark Thom
1ed4fe6555 Merge pull request #2756 from adri326/fix-load-context-unreachable
Fix load_context_module triggering unreachable!()
2025-01-11 21:27:32 -07:00
Rob Stolarz
894405149b fix: compile under Nix flake on macOS 2025-01-11 13:00:46 -08:00
Emilie Burgun
eff094cc29 Add tests for PR #2756 2025-01-08 17:57:40 +01:00
Emilie Burgun
6cedbc33c0 Fix load_context_module triggering unreachable code in unify_atom 2025-01-08 17:57:40 +01:00
Mark Thom
2856cc4371 Merge pull request #2742 from triska/clpb
Revert "FIXED: CLP(B): Delay BDD restriction until after the instantiation"
2025-01-04 13:26:08 -07:00
Mark Thom
a683d3e363 Merge pull request #2728 from aarroyoc/lets-play-brisca
Add tutorial: Let's play Brisca
2025-01-04 13:24:35 -07:00
Mark Thom
2257503951 Merge pull request #2743 from triska/crypto
atom --> string
2025-01-04 13:23:59 -07:00
Mark Thom
531d482ba7 Merge pull request #2744 from triska/files
state when the predicates are true
2025-01-04 13:23:44 -07:00
Markus Triska
28c386422b state when the predicates are true
"returns" is not used in this way in logic programming. "return"
suggests that something went away and is now coming back, but this is
never the case in these situations. The arguments may be variables or
also fully known at the time of the call in most cases.
2025-01-02 18:54:27 +01:00
Markus Triska
edaba024b2 atom --> string 2025-01-02 18:30:29 +01:00
Markus Triska
333d6740ae Revert "FIXED: CLP(B): Delay BDD restriction until after the instantiation."
This reverts commit e185b626bd.

This change is now no longer needed, and the underlying issue is
apparently somewhere else entirely. See the description at:

    https://github.com/mthom/scryer-prolog/issues/2732

Current master behaves differently from Scryer as it was at
099d9aaca6 (i.e., preceding
the commit that is now being reverted), even on the same file.

For an example, see:

    dd41176b97

Scryer now works as expected, and compatibly with SICStus. We still
need to find out what fixed the root cause of this issue.
2025-01-02 18:02:38 +01:00
Adrián Arroyo Calle
56cb27f71c Add tutorial: Let's play Brisca 2024-12-30 23:21:05 +01:00
Mark Thom
d57f871a12 Merge pull request #2681 from hurufu/remove-dcgs-that-have-failed-to-expand
Remove DCGs that have thrown an exception during term expansion
2024-12-25 14:29:38 -07:00
Mark Thom
afc7b74bbd qualify module quantification errors better (#2685) 2024-12-25 12:25:01 -08:00
Mark Thom
d287095e61 style corrections 2024-12-25 12:25:01 -08:00
Aleksy Grabowski
a599a11169 Remove DCGs that have thrown an exception during term expansion
Some DCG constructs aren't supported and can't be expanded, here we
remove offending DCG rule and don't compile it at all – in a similar
fashion to what we do when incorrect goal was found – whole predicate
isn't getting compiled.

Fixes #2675
2024-12-22 10:37:32 +01:00
Mark Thom
b7943837a0 Merge pull request #2714 from triska/graphic_token
prevent accidental amalgamation of graphic token chars in output
2024-12-20 18:42:09 -07:00
Mark Thom
e01a4cdc85 Merge pull request #2717 from jasagredo/js/small-doc
Ensure max_assoc/3 is shown as documented
2024-12-20 18:41:51 -07:00
Mark Thom
555dff5bad leave variable modules uninstantiated (#2685) 2024-12-19 20:20:29 -08:00
Javier Sagredo
75ac3fffae Ensure max_assoc/3 is shown as documented 2024-12-18 01:02:45 +01:00
Markus Triska
8dc80b815f use round brackets for goals involving operators
Examples:

    ?- portray_clause(((+) :- a=b,(-))).
    (+) :-
       a=b,
       (-).
       true.

    ?- portray_clause((a :- (b :- c))).
    a :-
       (b:-c).
       true.

This addresses #2715.

Currently, more round brackets than needed are emitted. Ideally, a
better approach to solve the issue here and also in toplevel.pl is
found in the future.
2024-12-17 22:51:47 +01:00
Markus Triska
6175e334a5 prevent accidental amalgamation of graphic token chars in output
This addresses #2713. Many thanks to @notoria for reporting this
excellent case!

Example:

    ?- portray_clause(A = @).
    A= @ .
       true.

At other positions the now inserted space is unnecessary, as in:

    ?- portray_clause((head:- @,b)).
    head :-
       @ ,
       b.
       true.

The toplevel has a similar issue:

    ?- C = # ; false.
       C = # |<-- cursor is here; redundant space after #

There may be a way to solve this issue for all cases like this.
2024-12-17 20:06:52 +01:00
Mark Thom
7e22c12a8d Merge pull request #2582 from bakaq/rework_library_interface
Rework library interface
2024-12-13 21:46:43 -07:00
Mark Thom
b5030be34f Merge pull request #2691 from aarroyoc/remove-meetup-2024
Remove Scryer Prolog Meetup 2024 announcements
2024-12-13 21:39:38 -07:00
Mark Thom
c59f54252c Merge pull request #2683 from ffortier/master
Support hermetic build environment
2024-12-13 21:39:12 -07:00
Mark Thom
a9a77779e3 Merge pull request #2689 from triska/weighted_maybe
introduce and use weighted_maybe/2
2024-12-13 21:38:47 -07:00
Mark Thom
5f035ec6ad Merge pull request #2690 from notoria/next
Add '$random_integer'/3
2024-12-13 21:38:32 -07:00
Mark Thom
9eef380764 Merge pull request #2696 from jasonhemann/patch-3
s/performance characters/performance characteristics/
2024-12-13 21:37:56 -07:00
Mark Thom
ce6a0a1541 Merge pull request #2698 from jasonhemann/patch-5
Documentation for read/2
2024-12-13 20:02:50 -07:00
Mark Thom
b919a39b96 Merge pull request #2703 from jasonhemann/patch-6
s/avaibale/available/
2024-12-13 20:02:21 -07:00
Mark Thom
84fc639f31 Merge pull request #2697 from jasonhemann/patch-4
"bound to an atom"
2024-12-13 19:57:21 -07:00
Jason Hemann
a15b2789e2 s/avaibale/available/
Quick typo fix to docs.
2024-12-13 13:41:05 -05:00
bakaq
2e910de485 cargo fmt 2024-12-12 06:03:43 -03:00
bakaq
74e3d32ca9 Use Cow<'a,B> for toplevel configuration 2024-12-12 05:59:59 -03:00
bakaq
500a6cdaf1 FIXME in Drop for QueryState 2024-12-12 05:49:52 -03:00
bakaq
17293a5753 Leave residual goals for later 2024-12-12 05:47:01 -03:00
bakaq
a75266c3ce Derive Default for StreamConfig 2024-12-12 05:47:01 -03:00
bakaq
a92eac919f Rename lib_machine_tests.rs to tests.rs 2024-12-12 05:46:54 -03:00
Jason Hemann
2ff50f06bc Update builtins.pl
s/compund/compound/
2024-12-11 08:05:03 -05:00
Jason Hemann
e219e1c483 Update builtins.pl
Simplifying docstring.
2024-12-11 05:46:28 -05:00
Jason Hemann
eef9f74a68 Documentation for read/2
Mirrored the wording in the docstrings for `read/1` and `read_term/3`.
2024-12-10 21:18:09 -05:00
Jason Hemann
eae1f53846 "bound to an atom"
Quick typo.
2024-12-10 21:07:48 -05:00
Jason Hemann
48a42ae140 s/performance characters/performance characteristics/
Small typo fix in docs.
2024-12-10 20:56:44 -05:00
Adrián Arroyo Calle
44facf07ab Remove Scryer Prolog Meetup 2024 announcements 2024-12-09 13:52:43 +01:00
bakaq
9265d66f58 Handle errors in QueryState 2024-12-08 20:18:06 -03:00
bakaq
3d3baeed82 Migrate benches 2024-12-08 20:18:06 -03:00
bakaq
e21c772181 Migrate tests to new API 2024-12-08 20:18:06 -03:00
bakaq
2f82c78bc0 Separate lib_machine tests into separate file 2024-12-08 20:18:06 -03:00
bakaq
ec6286ffab Shrink MVP API surface 2024-12-08 20:18:06 -03:00
bakaq
bb5adba4ef Rename PrologTerm to Term 2024-12-08 20:18:06 -03:00
bakaq
33d8abfed8 Remove parsed_results.rs 2024-12-08 20:18:06 -03:00
bakaq
d336cbc86a MachineBuilder 2024-12-08 20:18:06 -03:00
bakaq
79fbd9e90f Fix Machine links 2024-12-08 20:18:06 -03:00
bakaq
cab61738ad #[deny(missing_docs)] 2024-12-08 20:18:06 -03:00
bakaq
e6cc408ff2 Document test methods 2024-12-08 20:18:06 -03:00
bakaq
dc8348b843 Add interfaces for QueryState methods 2024-12-08 20:18:06 -03:00
bakaq
cb040dafc1 Docs for Machine and QueryState 2024-12-08 20:18:06 -03:00
bakaq
c13fc2d1b6 Docs for run_binary() 2024-12-08 20:18:06 -03:00
bakaq
1375f448a0 LeafAnswer docs and success checking methods 2024-12-08 20:18:06 -03:00
bakaq
0433706db6 More PrologTerm documentation 2024-12-08 20:18:06 -03:00
bakaq
e74fd11b0d Conjunctions, disjunction, and LeafAnswer to PrologTerm 2024-12-08 20:18:06 -03:00
bakaq
4480e7c066 Associated functions for creating PrologTerm 2024-12-08 20:18:06 -03:00
bakaq
71dec62ce2 Basic docs and non_exhaustive for PrologTerm 2024-12-08 20:18:05 -03:00
bakaq
658e39aae6 Machine and stream config rework 2024-12-08 20:18:05 -03:00
bakaq
29fc55cb28 Rename LeafAnswer 2024-12-08 20:18:05 -03:00
bakaq
8e7dc9dba8 Rename PrologTerm 2024-12-08 20:18:05 -03:00
Markus Triska
abe1f37167 introduce and use weighted_maybe/2
Many thanks to @hurufu for the very nice definition!

This is until library(random) provides this functionality,
and a good name is found for it. See #2670.
2024-12-08 21:33:03 +01:00
notoria
8cde3f8ce3 Add '$random_integer'/3 2024-12-08 20:00:00 +01:00
Mark Thom
dba9c9a0a7 instantiate module resolutions for meta-predicate lookups when expanding calls (#2255, #2619, #2684) 2024-12-06 23:30:36 -08:00
Mark Thom
ea02b54e7f Merge pull request #2677 from jasagredo/js/get-single-char-windows
Ignore `KeyEventKind::Release` events when reading a char
2024-12-05 20:25:25 -07:00
Mark Thom
0427d9ef11 Merge pull request #2679 from jasonhemann/patch-2
s/red/read/ typo in documentation.
2024-12-05 20:24:56 -07:00
Francis Fortier
c1571bf063 export toplevel repl/0 2024-12-05 09:38:38 -05:00
Francis Fortier
cef45de74a build: resolve include_str path during the compilation of libraries.rs instead of during he build.rs execution to support different build tools (bazel in this case) 2024-12-05 09:10:52 -05:00
Jason Hemann
d7bf7445f1 s/red/read/ typo in documentation.
Small quick fix.
2024-12-05 01:19:51 -05:00
Javier Sagredo
8e5ddebddb Ignore KeyEventKind::Release events when reading a char 2024-12-04 00:05:10 +01:00
Mark Thom
ff03432624 admit YF in current_op/3 (#2639) 2024-11-14 22:41:43 -07:00
Mark Thom
7fd409140c Merge pull request #2652 from gruhn/patch-1
update Docker install instructions
2024-11-15 05:51:03 +01:00
Mark Thom
9f6bbe949c Merge pull request #2653 from srenatus/sr/issue-2650
toplevel.pl: fix arity mismatch in read_input/2
2024-11-15 05:50:51 +01:00
Stephan Renatus
e78914219e toplevel: add more Stop=continue, remove nesting
Signed-off-by: Stephan Renatus <stephan@styra.com>
2024-11-03 13:31:47 +01:00
Stephan Renatus
620077d8c1 toplevel.pl: attempt to fix continue/stop logic
Signed-off-by: Stephan Renatus <stephan@styra.com>
2024-11-02 21:07:02 +01:00
Stephan Renatus
556b7c733f toplevel.pl: fix arity mismatch in read_input/2
I ran into the same problem today and I figured I'd take a stab at it.
Unfortunately, I'm not certain it is the right approach, but it no
longer errors like it did before.

Fixes #2650.

Signed-off-by: Stephan Renatus <stephan@styra.com>
2024-11-01 15:42:50 +01:00
Niklas Gruhn
e577a5430b README: update Docker install instructions 2024-11-01 10:58:44 +01:00
Mark Thom
e8ef9bc33a Merge pull request #2647 from panasenco/master
Updated Dockerfile
2024-10-29 13:15:08 -06:00
Aram Panasenco
7b18b1d47a Updated and tested Dockerfile 2024-10-28 10:31:05 -06:00
Mark Thom
c39ea4818a Merge pull request #2527 from bakaq/leaf_answers_callbacks
Toplevel reimplementation with leaf answer callbacks
2024-10-13 12:13:08 -06:00
bakaq
90d418a181 Fix priority in op/3 2024-10-12 23:37:58 -03:00
Mark Thom
9785a04b3a Merge pull request #2596 from Skgland/issue-2588
fix issue #2588
2024-10-05 22:12:45 -06:00
Bennet Bleßmann
6dd0ec0b98 fix miri 2024-10-04 20:25:02 +02:00
Bennet Bleßmann
e9f03c89a6 fix issue #2588 2024-10-04 19:25:34 +02:00
Bennet Bleßmann
8f41c1aa7e Merge remote-tracking branch 'upstream/master' into issue-2588 2024-10-04 19:11:26 +02:00
Bennet Bleßmann
442636c131 add test for load_html 2024-10-04 19:09:35 +02:00
bakaq
190929e4ac Remove trailing whitespace in toplevel.pl 2024-10-01 21:58:59 -03:00
Mark Thom
2f47343cb5 Merge pull request #2581 from bakaq/fix_hostname_feature
Fix not compiling without hostname feature
2024-09-29 21:09:22 -06:00
bakaq
3bc1885606 Fix not compiling without hostname feature 2024-09-29 16:51:11 -03:00
Mark Thom
0552530b41 Merge pull request #2573 from srenatus/sr/readme-link-to-latest-releases
README: link to latest release
2024-09-26 10:50:51 -06:00
Stephan Renatus
951c88d5f3 README: link to latest release
This will automatically redirect to the release marked "latest" in GitHub.
So the link won't become stale and doesn't need updating.

Signed-off-by: Stephan Renatus <stephan@styra.com>
2024-09-26 09:43:28 +02:00
Mark Thom
383eb5bdd9 Merge pull request #2523 from bakaq/visibility
Be conservative with visibility
2024-09-24 23:16:44 -06:00
Mark Thom
3fa6b69a79 Merge pull request #2533 from hurufu/fix-warnings
Assorted small fixes
2024-09-18 18:39:54 -06:00
Mark Thom
0bc3d67298 Merge pull request #2534 from hurufu/document_non_counted_backtracking
Document non counted backtracking
2024-09-16 17:41:53 -06:00
Mark Thom
a898d7a667 Merge pull request #2558 from bakaq/error_to_doclog
Convert library(error) docs to Doclog format
2024-09-16 17:41:18 -06:00
bakaq
238f1bd639 Convert library(error) docs to Doclog format 2024-09-16 16:47:00 -03:00
Aleksy Grabowski
4b0f9558b3 Change wording for non_counted_backtracking comment 2024-09-07 08:24:46 +02:00
Aleksy Grabowski
c922ed8b0a Explain non_counted_backtracking a little bit more 2024-09-07 08:14:37 +02:00
Aleksy Grabowski
3af24a8067 Revert "Explain non_counted_backtracking a little bit more"
This reverts commit 2b73107631.
2024-09-07 08:13:10 +02:00
bakaq
fdd6579230 Add mechanism to stop query 2024-09-07 02:06:01 -03:00
bakaq
16734ec7e4 Fix Clippy 2024-09-06 21:34:49 -03:00
bakaq
d32f3ee2f3 Fix warnings 2024-09-06 18:42:31 -03:00
bakaq
ada9ba98cc Make macros private 2024-09-06 17:17:04 -03:00
bakaq
a885e87ef7 Add argument with extra info to callback 2024-09-06 14:59:17 -03:00
bakaq
e369c15a27 Documentation for run_query/3 and run_query_goal/4 2024-09-06 14:55:39 -03:00
bakaq
afa7af3de6 Address review comments and remove old toplevel 2024-09-06 14:28:17 -03:00
Aleksy Grabowski
d3071988b2 Revert "Remove unnecessary "unsafe" block to fix compiler warning"
This reverts commit 7af93f1532.
2024-09-06 10:26:17 +02:00
Aleksy Grabowski
08aed04dd2 Revert "Fix rustc warning"
This reverts commit 7b09d447d6.
2024-09-06 10:25:45 +02:00
Aleksy Grabowski
7af93f1532 Remove unnecessary "unsafe" block to fix compiler warning 2024-09-06 08:20:13 +02:00
Aleksy Grabowski
2b73107631 Explain non_counted_backtracking a little bit more 2024-09-06 08:15:45 +02:00
Aleksy Grabowski
61c258f49e Fix mistake in predicate indicator 2024-09-06 08:07:21 +02:00
Aleksy Grabowski
6f0c7f42c6 Remove executable bit for files that don't need it 2024-09-06 08:06:10 +02:00
Aleksy Grabowski
7b09d447d6 Fix rustc warning 2024-09-06 08:06:10 +02:00
bakaq
9f4d31a825 Toplevel reimplementation with leaf answer callbacks 2024-09-03 13:43:31 -03:00
bakaq
806e980cca Be conservative with visibility 2024-09-03 01:02:01 -03:00
Mark Thom
12a61cdff8 Merge pull request #2491 from coasys/reqwest-version-relax
Relax version constraint on reqwest dependency
2024-08-29 12:22:46 -06:00
Nicolas Luck
808ea9fc79 Fix spelling of reqWest
Co-authored-by: Bennet Bleßmann <bennet.blessmann+github@googlemail.com>
2024-08-22 12:55:32 +02:00
Nicolas Luck
e1d830d680 Clean-up comment 2024-08-20 22:09:32 +02:00
Nicolas Luck
6be671d7d9 More precise comment mentioning Deno
Co-authored-by: Bennet Bleßmann <bennet.blessmann+github@googlemail.com>
2024-08-20 22:08:11 +02:00
Mark Thom
5c39e2a5a1 Merge pull request #2475 from bakaq/value_heap_walk
Value heap walk in lib_machine
2024-08-19 16:33:13 -06:00
bakaq
e24396d78a Fix order of variables in bindings 2024-08-19 14:38:53 -03:00
Mark Thom
264e3e9dd6 Merge pull request #2474 from Skgland/fix-looping-memory-allocation
Fix looping memory allocation
2024-08-17 20:58:03 -06:00
Mark Thom
3f25ee3749 Merge pull request #2495 from Skgland/fix2467
fix looping from issue #2467
2024-08-17 20:56:23 -06:00
Bennet Bleßmann
c24a51b633 fix looping from issue 2467 2024-08-17 23:37:12 +02:00
Nicolas Luck
8925133f40 Explanatory comment for the wildcard patch version 2024-08-16 16:16:16 +02:00
Nicolas Luck
2faab30af9 Explanatory comment for the wildcard patch version 2024-08-16 16:15:10 +02:00
bakaq
c1b88cee99 Fix partial strings ending in lists 2024-08-16 08:11:11 -03:00
bakaq
8736526b35 Fix lists of chars as strings 2024-08-16 00:34:46 -03:00
bakaq
7afc08af47 Represent atom [] as empty list 2024-08-16 00:01:25 -03:00
bakaq
12aaae5fc0 Differentiate anonymous variables 2024-08-15 20:08:29 -03:00
Nicolas Luck
e0ec5e75b4 typo 2024-08-15 22:41:48 +02:00
Nicolas Luck
7092e278d7 Relax constraint on version of reqwest dependency (Cargo will pick the latest patch that's possible, but not fail if another dep. has it pinned to something below patch 27) 2024-08-15 22:40:35 +02:00
bakaq
82a7d7efbd Value::from_heapcell() implemented with heap walk 2024-08-14 23:44:52 -03:00
bakaq
37a906cf37 Value::from_heapcell() 2024-08-14 23:44:52 -03:00
Mark Thom
bacfed8983 Merge pull request #2472 from bakaq/query_iterator
Add run_query_iter()
2024-08-14 20:26:03 -06:00
bakaq
ed1b25cb30 Tests for run_query_iter() 2024-08-14 20:02:03 -03:00
bakaq
bc262db6d7 Implement run_query() in terms of run_query_iter() 2024-08-14 19:59:42 -03:00
bakaq
86a2c5e2ed Add run_query_iter() 2024-08-14 19:59:36 -03:00
Mark Thom
e77c97e0d1 Merge pull request #2482 from bakaq/flake
Add flake.nix
2024-08-14 06:36:16 -06:00
Mark Thom
48f3a7b87e Merge pull request #2485 from aarroyoc/learn-pages-docs
Upgrade docs to DocLog 2.0. Includes a test learning page
2024-08-14 06:35:58 -06:00
Adrián Arroyo Calle
e5aaa9d277 Upgrade docs to DocLog 2.0. Includes a test learning page 2024-08-14 11:19:08 +02:00
bakaq
938401dbc6 flake.nix 2024-08-13 23:43:05 -03:00
Bennet Bleßmann
620bf385d1 include the type name for better pin-pointing of the error source
- only done here as all other places are non-generic and the panic already includes file and line info, only here are we in a generic context and might need more differentiation
2024-08-11 21:53:02 +02:00
Bennet Bleßmann
cc51b8150d check whether (re-)allocation succeeded
fixes mthom/scryer-prolog#2449
2024-08-11 19:20:33 +02:00
Bennet Bleßmann
775b14c537 add detail to comment 2024-08-11 19:20:27 +02:00
Mark Thom
7cfe8ee55c Merge pull request #2463 from Skgland/split-up-inconsitent-entry-error
Split up inconsistent entry error
2024-08-05 14:25:33 -06:00
Bennet Bleßmann
058b9c5e51 switch invalid term from type to domain error 2024-08-05 21:25:44 +02:00
Bennet Bleßmann
deed6fb984 fix remaining use of declaration instead of directive 2024-08-05 21:25:43 +02:00
Bennet Bleßmann
2d04c0dcf8 remove obsolete ExistenceError::Declaration 2024-08-05 21:25:43 +02:00
Bennet Bleßmann
5a0abd713e change declaration to directive 2024-08-05 21:25:43 +02:00
Bennet Bleßmann
df33da111e ajust/add devlaration errors to be more standard compliant 2024-08-05 21:25:43 +02:00
Bennet Bleßmann
17a816eff4 impl PartialEq<str> and PartialEq<&str> for Atom 2024-08-05 21:25:42 +02:00
Bennet Bleßmann
880e22d164 adjust errors to be more standard compliant 2024-08-05 21:25:42 +02:00
Bennet Bleßmann
c16d2d4147 fix compilation for 1.77 2024-08-05 21:25:42 +02:00
Bennet Bleßmann
59af900aaf split up CompilationError::InconsistentEntry 2024-08-05 21:25:42 +02:00
Bennet Bleßmann
add03cb4ee add test for declaration errors 2024-08-05 21:25:42 +02:00
Bennet Bleßmann
409f56ea37 use an enum for OpDesc spec 2024-08-05 21:25:36 +02:00
Mark Thom
2814d79b56 Merge pull request #2466 from Skgland/upgrade-deps
Upgrade dependencies
2024-08-05 12:59:42 -06:00
Bennet Bleßmann
4009b40029 replace derive_deref with derive_more
- the latter already used in our transitive dependencies
- derive_more appears better maintained
2024-08-04 02:40:26 +02:00
Bennet Bleßmann
260c52adec replace select by scrape
- the latter appears better maintained and more up to date
- removes some dupplicate/outdated transitive deps
2024-08-04 02:35:36 +02:00
Bennet Bleßmann
b1f057b67d resolve problems from deps upgrade
- downgrade reqwest to 0.11.27
  - fixes problems with missmatched transitive dependencies between it and warp, mainly http
- replace deprecated ripemd160 with ripemd (as specified in the formers readme)
- indexmap: replace deprecated remove with functionally identical swap_remove
2024-08-04 01:57:25 +02:00
Bennet Bleßmann
177bc16255 update/upgrade dependencies 2024-08-04 01:41:03 +02:00
Mark Thom
4ce4cd1bc1 Merge pull request #2462 from Skgland/fix-segfault
fix segfault by dropping loader state payload after resetting machine
2024-08-03 14:05:13 -06:00
Bennet Bleßmann
9e8d8aa19e prevent accidental double free by checking tag before drop 2024-08-03 19:36:05 +02:00
Bennet Bleßmann
4d3ceb387e drop payload after resetting machine
- under some circumstances the payload is accessed durring reset which would cause a segfault if we drop the payload too early
2024-08-03 19:27:32 +02:00
Mark Thom
5038b716eb Merge pull request #2457 from Skgland/library
simplify generated libraries map by using `include_str!`
2024-07-26 11:29:12 -06:00
Adrián Arroyo Calle
e310f9683e Fix build on WASM after #2442
(cherry-pick of 3acf4c637b6f8b17bb0230edeaaae0507d9030d1 from PR
mthom/scryer-prolog#2446)
2024-07-26 01:08:00 +02:00
Bennet Bleßmann
c29b76143c fix copy-past error 2024-07-26 00:13:49 +02:00
Bennet Bleßmann
3ad4b05a97 add a features for gating things we can use once 1.80 is msrv 2024-07-25 23:09:17 +02:00
Bennet Bleßmann
0da313eb84 use a OnceLock static for LIBRARIES instead of thread_local! static 2024-07-25 18:58:29 +02:00
Bennet Bleßmann
6b50ec328c move the creation of the LIBRARIES IndexMap out of the generated file
- only leave the filling of the map in the generated code
2024-07-25 18:53:36 +02:00
Bennet Bleßmann
1eb6a883f6 run rustfmt 2024-07-23 00:01:58 +02:00
Bennet Bleßmann
e7fd408548 use include_str! for the build in libraries
instead of "copy-paste-ing" the prolog source into rust string literals in the generated files
2024-07-23 00:01:29 +02:00
Mark Thom
eaa95293e4 Merge pull request #2439 from Skgland/miri
Some cleanup and miri fixes
2024-07-22 13:40:57 -06:00
Mark Thom
8ac663d703 Merge pull request #2442 from aarroyoc/fix-http-at-end-of-stream
Fix at_end_of_stream/1 for http read stream
2024-07-07 16:02:51 -06:00
Mark Thom
902712695c Merge pull request #2440 from triska/statistics
ADDED: Preliminary support for statistics/2.
2024-07-07 15:59:44 -06:00
Bennet Bleßmann
5d03be4b09 fix leak of slaps with dropped payload 2024-07-07 19:22:46 +02:00
Bennet Bleßmann
689632b51c cleanup the slab types
- get rid of HeaderOrIdxPtr
- add IndexPtrSlab
- add UntypedArenaSlab
- add to_untyped for converting a typed slab into an unsyped slab
- remove TypedArenaPtr::new, as they shouldn't be created outside of this module
2024-07-07 17:12:52 +02:00
Bennet Bleßmann
1b19ae81d5 wrap Payloads that are dropped eraly in ManuallyDrop 2024-07-07 15:58:31 +02:00
Bennet Bleßmann
a0d790445d check that we don't attempt to un-drop while evacuating 2024-07-07 14:37:41 +02:00
Bennet Bleßmann
213ee5ca45 add AllocateInArena as a Pivot for arena_alloc!
so that the value type passed to `arena_alloc!` can differ from the `ArenaAllocated::Payload` type
2024-07-07 14:36:53 +02:00
Bennet Bleßmann
74720d4d2e remove unsafe impl From<UntypedArenaPtr> for CodeIndex 2024-07-07 14:18:50 +02:00
Skgland
39bd520542 ignore pstr_iter_tests test in miri as it takes too long 2024-07-07 13:22:49 +02:00
Bennet Bleßmann
496e4e9f56 fix clippy again 2024-07-07 11:31:36 +02:00
Bennet Bleßmann
89c1ea4232 fix leak of ArenaAllocated IndexPtr 2024-07-07 11:30:56 +02:00
Bennet Bleßmann
a2a50586aa replace static Once and two mut statics with one static OnceLock 2024-07-07 11:30:56 +02:00
Bennet Bleßmann
0284a2092d reduce span of unsafe block 2024-07-07 11:30:37 +02:00
Bennet Bleßmann
c414f75329 switch macos to latest as macos-11 has been removed
See https://github.com/actions/runner-images/issues/9255
2024-07-06 18:47:35 +02:00
Bennet Bleßmann
943dce566b fix clippy 2024-07-06 18:26:34 +02:00
Bennet Bleßmann
b32498b37c adjust ignore reason 2024-07-06 18:24:38 +02:00
Bennet Bleßmann
ea041a40f9 if UB un IndexPtr ArenaAllocated impl 2024-07-06 17:43:13 +02:00
Bennet Bleßmann
1d66f91a41 replace ref_thread_local::ref_thread_local! with std::thread_local!
removes `ref_thread_local` which was still at 0.0.0 released October 2018 while latest 0.1.1 was released mid November 2021

fixes libraries.rs UB
2024-07-06 17:18:26 +02:00
Bennet Bleßmann
fee7ba58b0 fix stack alignement
- adjust align() in RawBlockTraits impl for Stack
- ensure ptr is always aligned in RawBlock::allock
2024-07-06 16:21:59 +02:00
Bennet Bleßmann
8e53d12776 make components a comma seperated string instead of a list 2024-07-06 16:01:52 +02:00
Adrián Arroyo Calle
08a9f7c068 Fix at_end_of_stream/1 for http read stream 2024-07-06 16:00:50 +02:00
Bennet Bleßmann
33793193cc add miri to CI 2024-07-06 15:46:04 +02:00
Bennet Bleßmann
285f11ccdc add associated Payload type to ArenaAllocated 2024-07-06 15:37:08 +02:00
Bennet Bleßmann
d87400afa0 switch Rcu to the arcu crate
The arcu crate is a more general implementation of the Rcu I implemented in here in scryer. It contains some bug-fixes regarding race-conditions in the Rcu update function, which could cause leaks and uses after free.

Source of the problem was the Relaxed load/strore/update of the reference count in side the Arc not being properly ordered with other load/stores.
2024-07-06 14:49:19 +02:00
Bennet Bleßmann
fcb41542c3 fix stream.rs UB 2024-07-06 14:30:03 +02:00
Bennet Bleßmann
87b4c9d736 somehow this was never marked as bad 2024-07-06 14:30:03 +02:00
Bennet Bleßmann
6386e70584 clippy: change ToString impl to Display
- write directly to formatter, eliminating intermediate String allocations
- take Value by reference eliminating clones
- remove trim() called on the result of  QueryResolution::to_string
    - we only  emit "true", "false", or "[<resolutions>]"
      neither of which contains trailing or leading withespace,
      so the calls was effectively a noop
2024-07-06 13:32:58 +02:00
Bennet Bleßmann
722975d77e clippy: use type associated constants 2024-07-06 13:08:59 +02:00
Bennet Bleßmann
8943962704 clippy: ptr dereference in safe function 2024-07-06 13:07:26 +02:00
Bennet Bleßmann
ed57ef3d01 clippy: identity conversion 2024-07-06 13:06:50 +02:00
Bennet Bleßmann
9e7d41025a fix saftey comment 2024-07-06 13:06:24 +02:00
Bennet Bleßmann
d2f236d116 clippy: explicit ptr addrs comparision
relevant for wide pointers i.e. pointers with metadata
2024-07-06 13:06:13 +02:00
Bennet Bleßmann
1ff995fedb clippy: allow new without default 2024-07-06 13:04:55 +02:00
Bennet Bleßmann
1b16c6c73f clippy: use clone_from rather than clone 2024-07-06 13:03:14 +02:00
Bennet Bleßmann
ceac9c9095 clippy: ignore unused fields on PrologBenchmark struct 2024-07-06 13:01:19 +02:00
Markus Triska
0005dcaacb ADDED: Preliminary support for statistics/2.
This is needed for benchmarking library(reif) and its newly provided
goal expansion (#2433).

It partly addresses #321.
2024-07-06 11:33:02 +02:00
Bennet Bleßmann
467a82fe46 run rustfmt 2024-07-06 04:18:02 +02:00
Bennet Bleßmann
ce40f8f10c update ignore reason 2024-07-06 04:15:30 +02:00
Bennet Bleßmann
d2d451b182 adjust the generation of the LIBRARIES map
pre-genrate constants instaed of driectly genrating the literal for the insert
2024-07-06 03:53:22 +02:00
Bennet Bleßmann
52fa51853e don't use env::current_dir() in miri 2024-07-06 03:53:22 +02:00
Bennet Bleßmann
6575b1b573 fix some more miri errors
probably relevant to mthom/scryer-prolog#2438
2024-07-06 03:52:46 +02:00
Bennet Bleßmann
cba81b4dc7 some test pass miri 2024-07-06 02:43:00 +02:00
Bennet Bleßmann
91253917b4 remove rust_beta_channel feature
- the msrv (i.e. rust-version in Cargo.toml) is high enough that all gated code can now be used on stabe
2024-07-06 02:24:26 +02:00
Bennet Bleßmann
821358c062 unify pointer width 2024-07-06 01:49:25 +02:00
Bennet Bleßmann
3de0a4e2ad replace transmut with pointer cast calls 2024-07-06 01:38:13 +02:00
Bennet Bleßmann
b8a3067744 resolve miri error for pstr_iter_tests in atom_table
relevant to mthom/scryer-prolog#2438
2024-07-06 01:21:03 +02:00
Bennet Bleßmann
7509cc1a07 adjust alignment calculation
- I think this used to overallocate when the alignment was already met
2024-07-06 00:13:46 +02:00
Bennet Bleßmann
dd2548453b rework some unsafe parts
- removed some unsafe
- added some safety comments
- add explicit types to transmute calls
- reworked UntypedArenaPtr -> TypedArenaPtr conversion

might help with mthom/scryer-prolog#2438, I noticed fewer complains from miri after changing the default impl for `ArenaAllocated::alloc`
2024-07-05 23:45:02 +02:00
Bennet Bleßmann
a93585080c remove remains of num feature
commit c41aba6b90 removed the num feature but a few cfgs remained
2024-07-05 21:29:38 +02:00
Mark Thom
5f30c9599a Merge pull request #2436 from triska/arxivlink
link to newly available paper about Grants4Companies
2024-07-04 16:30:00 -06:00
Markus Triska
4b3edfd370 link to newly available paper about Grants4Companies 2024-07-03 22:33:56 +02:00
Mark Thom
d6ac03552d Merge pull request #2417 from aarroyoc/fix-2416
Manage Float and Double FFI types in structs
2024-06-06 22:33:46 -06:00
Adrián Arroyo Calle
a72632ae85 Manage Float and Double FFI types in structs 2024-06-06 22:18:17 +02:00
Mark Thom
2d18e0d719 Merge pull request #2413 from Skgland/master
re-add CI job to test Cargo.toml rust-version
2024-05-29 12:28:25 -06:00
Bennet Bleßmann
45a8a7bb31 create swap file for wasm32 build 2024-05-29 19:50:27 +02:00
Bennet Bleßmann
1a9d10d298 fix two clippy lints 2024-05-28 21:28:18 +02:00
Bennet Bleßmann
80a0cab6ab re-add CI job to test Cargo.toml rust-version
was removed in #2393 instead of being updated, see

- https://github.com/mthom/scryer-prolog/pull/2393#discussion_r1585963855 and
- 79bc2d9c68 (commitcomment-141790142)
2024-05-28 21:27:29 +02:00
Mark Thom
96720457d0 Merge pull request #2410 from aarroyoc/fix-warn-dead-code-elimination
Fix warnings of dead code
2024-05-27 12:07:27 -06:00
Adrián Arroyo Calle
f4d2839dc7 Fix warnings of dead code 2024-05-27 19:52:02 +02:00
Mark Thom
070f1e8dfa more generally consider NEGATIVE_SIGN a non-op term (#2401) 2024-05-13 14:37:44 -06:00
Mark Thom
42a0d686a5 Merge pull request #2393 from mthom/unsafe_improvements
Improve use of unsafe Rust in arena.rs (#2391)
2024-04-29 16:17:14 -06:00
Mark Thom
79bc2d9c68 remove 1.70 version CI job 2024-04-29 15:40:05 -06:00
Mark Thom
f3eea6302d delay instantiation errors on lists in phrase/3 until runtime (#1665, #2396) 2024-04-29 15:28:17 -06:00
Mark Thom
bcfa0219e2 detect External indices more generally in internalize_constant (#2395) 2024-04-29 14:23:14 -06:00
Mark Thom
5e1effc69a fix failing clippy checks, remove unnecessary code 2024-04-25 20:05:22 -06:00
Mark Thom
be23c74b17 fix wasm tests in unsafe_improvements branch 2024-04-24 21:21:25 -06:00
Mark Thom
8fe1c206d3 bump required rust version for use of newly introduced macros 2024-04-24 20:33:42 -06:00
Mark Thom
a6157a926d improve use of unsafe Rust in arena.rs (#2391) 2024-04-24 20:28:06 -06:00
Mark Thom
9837187183 add nth_partial_strings_tests for bugs raised in #1827, #2381 2024-04-10 15:50:24 -06:00
Mark Thom
c2657cce37 use common test_framework module for several test suites 2024-04-10 15:47:31 -06:00
Mark Thom
7d6109feca fix char_offset values in add_pstr_offset_chars (#2381) 2024-04-10 15:46:11 -06:00
Mark Thom
cf14b222f2 fix skip_max_list crash on bigint max_steps (#2382) 2024-04-09 18:57:53 -06:00
Mark Thom
238343f389 add max_steps to PStr offset (#2381) 2024-04-09 18:40:08 -06:00
Mark Thom
77e90ca725 correct offsets around max_steps in skip_max_list (#2381) 2024-04-09 15:58:23 -06:00
Mark Thom
f734c273ca Merge pull request #2379 from aarroyoc/scryer-prolog-meetup-2024
website: add Scryer Prolog Meetup 2024 banner
2024-04-07 18:10:54 -06:00
Adrián Arroyo Calle
e23e5203de website: add Scryer Prolog Meetup 2024 banner 2024-04-07 19:44:13 +02:00
Mark Thom
a2dd189241 add Scryer Prolog Meetup 2024 to README 2024-04-05 12:29:02 -06:00
Mark Thom
0ed4e41000 Merge pull request #2376 from mthom/dependabot/cargo/h2-0.3.26
Bump h2 from 0.3.24 to 0.3.26
2024-04-05 11:19:50 -06:00
dependabot[bot]
352919862f Bump h2 from 0.3.24 to 0.3.26
Bumps [h2](https://github.com/hyperium/h2) from 0.3.24 to 0.3.26.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/v0.3.26/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.24...v0.3.26)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-05 16:18:08 +00:00
Mark Thom
aab6567750 treat Utf8Error::valid_up_to as an offset form self.pos, which it is (#2374) 2024-04-03 15:29:29 -06:00
Mark Thom
ea9e24f214 Merge pull request #2367 from triska/dcg_meta_predicates
ADDED: meta_predicate/1 declarations for (',')//2 and (;)//2
2024-03-26 15:21:37 -06:00
Mark
40fc4f9392 correct offset retrieval in add_pstr_chars_and_step (#2370) 2024-03-25 12:47:45 -06:00
Markus Triska
795a7c690d ADDED: meta_predicate/1 declarations for (',')//2 and (;)//2
This addresses #2366.
2024-03-21 22:14:40 +01:00
Mark Thom
2fdbb94c79 Merge pull request #2363 from triska/compile_format
ENHANCED: Partial evaluation of format_//2 and related constructs
2024-03-20 18:52:08 -06:00
Markus Triska
767d90d5e7 ENHANCED: further partial evaluation for the common control sequence ~d 2024-03-20 21:10:14 +01:00
Markus Triska
bc04790fd5 extend partial evaluation to computing lengths when statically possible 2024-03-20 21:10:14 +01:00
Markus Triska
58f7c94e74 goal expansion for format/2 and format/3
In this way, we benefit from partial evaluation of format strings.
2024-03-20 21:10:14 +01:00
Markus Triska
8af29c200d strengthen type check 2024-03-20 21:10:10 +01:00
Markus Triska
1db6bff890 ENHANCED: Partial evaluation of format_//2.
This moves analysis of the format string to compilation time when
possible, so that parsing it at run time is no longer necessary.
2024-03-20 20:59:43 +01:00
Mark
0292cb73d3 expand_call_goals/3 should expand meta-predicate subgoals (#2361) 2024-03-19 17:12:26 -06:00
Mark Thom
7b33eafbb0 Merge pull request #2358 from triska/octet_documentation
Documentation improvements for encoding(octet) option in several predicates
2024-03-16 19:56:49 -06:00
Markus Triska
ee60c463c8 indicate deprecated functionality 2024-03-16 21:23:12 +01:00
Markus Triska
e1a6b5eb03 DOC: Un-document the ability to use bytes with encoding(octet).
This usage is now considered deprecated. Use strings instead for
greater efficiency and type consistency in your applications.

This functionality is a candidate for removal in a future commit.
2024-03-16 20:37:06 +01:00
Markus Triska
4ebdd97ad3 DOC: Improve descriptions to make clear what encoding(octet) means.
In particular, octet does *not* mean that the input is a list of
Prolog bytes in the sense of "integers between 0..255", but that the
character codes are used directly as byte values.
2024-03-16 20:36:22 +01:00
Mark
6f7f979c05 don't skip to end of pstr in CommaSeparatedCharList token variant (#2356) 2024-03-12 18:37:03 -06:00
Mark Thom
ca8e280b4c Merge pull request #2357 from aarroyoc/update-website-0.9.4
Website: link release v0.9.4
2024-03-12 16:46:31 -06:00
Adrián Arroyo Calle
b26e8b0e34 Website: link release v0.9.4 2024-03-12 22:23:12 +01:00
Mark
df41eb1870 recompile original terms from compile_clause for term to term expansions (#2236) 2024-03-01 18:57:01 -07:00
Mark Thom
90c602f867 Merge pull request #2354 from triska/side_channel
explain potential side-channel attacks due to compact string representation
2024-03-01 16:11:22 -07:00
Markus Triska
6b8a679a51 explain potential side-channel attacks due to compact string representation
This legitimate concern was already raised by @infogulch in:

https://github.com/mthom/scryer-prolog/issues/1309#issuecomment-1080028854

Thank you a lot!
2024-03-01 22:03:57 +01:00
Mark Thom
8b16a0e1f6 Merge pull request #2353 from triska/hmac_verification
ENHANCED: Safe HMAC verification, using constant time string comparison.
2024-03-01 12:09:16 -07:00
Markus Triska
ec251b254c ENHANCED: Safe HMAC verification, using constant time string comparison.
Without this provision, the expected HMAC can be gathered from timing
differences depending on the position where the strings first diverge,
and hence an attacker can forge an authenticated message by supplying
the gathered HMAC.

Test case, using exp(E) to succeed exactly 2^E times:

    exp(E) :-
        N is 2^E,
        between(1, N, _).

yielding:

    ?- Options = [algorithm(sha512),hmac([1,2,3])],
       Ds = "test",
       crypto_data_hash(Ds, H, Options),
       phrase((seq(As),seq(Bs)), H),
       same_length(Bs, Cs),
       maplist(=(a), Cs),
       append(As, Cs, H1),
       time((exp(10),crypto_data_hash(Ds, H1, Options),false)).
    %@    % CPU time: 0.710s, 7_942_187 inferences
    %@    % CPU time: 0.713s, 7_942_187 inferences
    %@    % CPU time: 0.712s, 7_942_187 inferences
    %@    % CPU time: 0.711s, 7_942_187 inferences
    %@    % CPU time: 0.710s, 7_942_187 inferences
    %@    % CPU time: 0.711s, 7_942_187 inferences
    %@    % CPU time: 0.710s, 7_942_187 inferences

    ?- length(_, L), time((exp(10),crypto_data_hash("test", "3caebd1a0a2647930319a660b7d3642eb380fbd43202f9f6d08aabaa9ba50c39522a12ead10f0423f0af613cbc6fea74ad682ee11f563cc2e735722004fda2ba", [algorithm(sha512),hmac([0,L])]),false)).
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.734s, 7_878_699 inferences
    %@    % CPU time: 0.732s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.733s, 7_878_699 inferences
    %@    % CPU time: 0.515s, 5_525_404 inferences
    %@    error('$interrupt_thrown',repl/0).
2024-03-01 18:59:48 +01:00
Mark Thom
e0c8163211 Merge pull request #2351 from infogulch/install-current-iai
Install version of iai-callgrind set in Cargo.toml
2024-02-29 17:09:47 -07:00
infogulch
01f757c940 Install version of iai-callgrind set in Cargo.toml 2024-02-29 17:32:44 -06:00
Mark
42f4827854 make indexer downcast Integers to Fixnums when possible, be slightly more judicious about allocating Integers instead of Fixnums (#2340) 2024-02-29 16:15:28 -07:00
Mark
f2d3779fa9 add #2341 test to lib_machine.rs 2024-02-29 15:12:58 -07:00
Mark
b70f121e46 use scryer-modular-bitfield on github, version bump
Some checks failed
CI / build-test (ubuntu-22.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (windows-latest, true, stable, x86_64-pc-windows-msvc) (push) Has been cancelled
CI / logtalk-test (push) Has been cancelled
CI / style (push) Has been cancelled
CI / build-test (--no-default-features, ubuntu-22.04, true, nightly, wasm32-unknown-unknown, --no-run --no-default-features) (push) Has been cancelled
CI / build-test (macos-11, true, stable, x86_64-apple-darwin) (push) Has been cancelled
CI / build-test (ubuntu-20.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, 1.70, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, beta, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, nightly, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, true, stable, i686-unknown-linux-gnu) (push) Has been cancelled
CI / report (push) Has been cancelled
CI / release (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
2024-02-29 10:08:14 -07:00
Mark
641765858f fix misuse of TypeError trait while fixing #2345 2024-02-28 20:47:36 -07:00
Mark
ba362e2fe0 issue callable type error from dynamic_module_resolution if module is not an atom (#2345) 2024-02-28 20:35:38 -07:00
Mark Thom
84d5ce0d1e Merge pull request #2309 from coasys/library-use-case
Iron-out edge cases for library use-case, adding extensive real-world test assertions
2024-02-28 14:34:54 -07:00
Mark Thom
419623d158 Merge pull request #2342 from triska/curve_doc
DOC: Add DocLog comments for reasoning about elliptic curves.
2024-02-24 14:53:18 -07:00
Markus Triska
1dd0c599c6 DOC: Add DocLog comments for reasoning about elliptic curves. 2024-02-24 20:43:57 +01:00
Mark Thom
c7934ca246 Merge pull request #2338 from triska/hmac
ADDED: Hash-based message authentication code (HMAC), using hmac(Key).
2024-02-22 14:48:12 -07:00
Markus Triska
27852eafd7 ADDED: Hash-based message authentication code (HMAC), using hmac(Key). 2024-02-22 20:53:27 +01:00
Mark Thom
d4bde5008d Merge pull request #2337 from triska/master
link to newly available paper on analysis of dose-escalation protocols
2024-02-18 10:05:09 -07:00
Markus Triska
74a525a672 link to newly available paper on analysis of dose-escalation protocols
Many thanks to @dcnorris for this great application and cooperation!
2024-02-18 09:25:29 +01:00
Bennet Bleßmann
e9982dc447 fix build of run_iai bench for wasm32 2024-02-17 00:15:03 +01:00
Bennet Bleßmann
7028baaf8f fix benchmarks being broken for every target except wam32 2024-02-17 00:01:10 +01:00
Bennet Bleßmann
7837c76c74 cfg out benches for wasm32 2024-02-16 23:43:22 +01:00
Bennet Bleßmann
e5ad70c093 fix compilation of wasm32 test and skip to run wasm32 tests 2024-02-16 23:18:21 +01:00
Bennet Bleßmann
7fce688769 undo continue-on-error
- currently  `continue-on-error` is not shown in a usefull way on failiure see <https://github.com/orgs/community/discussions/15452>
2024-02-16 22:23:22 +01:00
Bennet Bleßmann
90c874777c bump ahash lock to 0.8.7
- fix nightly build
- not bumping to latest aka. 0.8.8 as that has a msrv of 1.72.0 and we are only at 1.70.0
2024-02-16 22:15:32 +01:00
Mark Thom
70795134af Merge pull request #2327 from triska/char_type
FIXED: char_type/2 for unbound first argument.
2024-02-11 17:33:07 -07:00
Markus Triska
8f2e9c6b94 FIXED: char_type/2 for unbound first argument.
Surrogate pairs form a gap in valid character codes, see:

    https://github.com/mthom/scryer-prolog/issues/2326#issuecomment-1937864665

Many thanks to @Skgland for the pointer, and to @librarianmage for the
question that spawned this!

This addresses #2326.
2024-02-11 22:19:19 +01:00
Nicolas Luck
ce34ca8f1f continue-on-error if target=wasm32 or rust=nightly 2024-02-09 13:48:45 +01:00
Nicolas Luck
7c632cf165 Reactivate nightly test job with continue-on-error set 2024-02-09 13:44:37 +01:00
Nicolas Luck
b3c5a8db80 Use stable Rust for style/report and deactivate nightly x86_64 target in CI 2024-02-09 13:14:06 +01:00
Nicolas Luck
1d2961e047 Merge branch 'master' into library-use-case 2024-02-09 12:41:01 +01:00
Mark Thom
b43f0979d9 Update src/machine/parsed_results.rs
Co-authored-by: Bennet Bleßmann <bennet.blessmann+github@googlemail.com>
2024-02-08 19:10:29 -07:00
Mark
539a1aee2c fix tests broken by singleton 2024-02-07 21:46:32 -07:00
Mark Thom
8e323b9dfa Merge pull request #2322 from triska/char_code
ENHANCED: Bi-directional char_code/2, addressing #2321.
2024-02-07 18:49:13 -07:00
Markus Triska
53b7d9eec9 ENHANCED: Bidirectional char_type/2, addressing #2321.
Suggested by @librarianmage, many thanks!
2024-02-07 20:57:28 +01:00
Mark Thom
89d3451767 Merge pull request #2319 from triska/clpz_t
ADDED: clpz_t/2, generalizing support for use with library(reif)
2024-02-06 18:11:40 -07:00
Markus Triska
aa98a7e7d6 ADDED: clpz_t/2, generalizing support for use with library(reif)
This was suggested and contributed by @librarianmage in:

    https://github.com/mthom/scryer-prolog/issues/2225#issuecomment-1890801923

Many thanks!

If anyone can find a better predicate name, please let us know any time!
2024-02-06 19:05:29 +01:00
Mark
614850ab1d fmt 2024-02-05 18:34:57 -07:00
Mark Thom
140a15f9cb Merge pull request #2317 from aarroyoc/all-modules-test
Add all_mdoules test and fix library(csv)
2024-02-04 15:09:13 -07:00
Adrián Arroyo Calle
ec4a8745e7 Add all_mdoules test and fix library(csv) 2024-02-04 21:34:01 +01:00
Mark
673329ddb7 fix reverted tests, ensure files are loaded before goals (#2315) 2024-02-03 11:49:26 -07:00
Mark
6a421dd8b0 fix broken tests 2024-02-02 17:04:47 -07:00
Mark
de6c460a51 treat consultation of command line modules as regular goals (#2314) 2024-02-02 15:35:00 -07:00
Mark
75a94fd0b3 fmt 2024-02-02 11:49:02 -07:00
Mark
7573c64087 load .scryerrc before files and goals (#1775, #2313) 2024-02-02 10:54:28 -07:00
Mark
cbb422f69d record stub choice point as block 2024-02-01 09:26:58 -07:00
Nicolas Luck
06f198bc57 Test show problem with nonexistent predicate 2024-02-01 14:14:50 +01:00
Nicolas Luck
6586657658 fmt 2024-02-01 13:53:21 +01:00
Nicolas Luck
a0e598b97e clippy 2024-02-01 13:51:37 +01:00
Nicolas Luck
8a6ea29c45 Fix all orderings in integration assertions 2024-02-01 13:43:51 +01:00
Nicolas Luck
e1b0ba466b Remove test with long program literals, not needed 2024-02-01 13:00:49 +01:00
Nicolas Luck
f35d6287ab More ordering adjustments 2024-02-01 12:59:10 +01:00
Mark
53028a9c2a fix style errors 2024-01-31 17:32:32 -07:00
Mark
33fc2ed10c index stub choice point correctly 2024-01-31 17:30:13 -07:00
Nicolas Luck
bc02fb3754 Extract failing assertion as single test case 2024-01-31 15:03:28 +01:00
Nicolas Luck
48b2379fe5 Adjust some first result orderings in integration assertions 2024-01-30 12:54:12 +01:00
Mark
7de693eb23 check for True or False Query Resolution unconditionally 2024-01-29 15:06:56 -07:00
Nicolas Luck
7bb9c00356 fmt 2024-01-29 18:44:20 +01:00
Nicolas Luck
9aacfff35d Add more test cases to differentiate usage of discontiguous 2024-01-29 16:49:03 +01:00
Nicolas Luck
2e728c7051 Minimal reproduction of faulty behaviour seen in integration tests 2024-01-29 15:26:06 +01:00
Nicolas Luck
7e973a6da6 Merge branch 'master' into library-use-case 2024-01-26 17:21:47 +01:00
Nicolas Luck
cb014095ad Add expected results to integration test
Results are logs of what we get with old toplevel-based version of lib_machine. These are also congruent with what our tests logged out based on SWI.
2024-01-26 17:18:57 +01:00
Mark
6fe8f64835 scan registers of instructions leading to verify_attributes interrupt to find the number of registers to save (#2307) 2024-01-25 23:59:54 -07:00
Mark
6111f72b24 add non chunk traversing cut family instructions to is_head_instr (#2307) 2024-01-25 23:25:06 -07:00
Mark Thom
43041971b7 Merge pull request #2308 from triska/small_format_improvements
Small format improvements
2024-01-25 14:17:18 -07:00
Markus Triska
3505cc3ba0 update answers using latest toplevel output 2024-01-25 21:33:27 +01:00
Markus Triska
05ba5f4358 rely on recently improved argument indexing for determinism
This is possible as of 4fd37335f5.
2024-01-25 21:31:08 +01:00
Mark
bc616ca7d8 move call_residue_vars/2 from atts.pl to iso_ext.pl 2024-01-25 12:40:24 -07:00
Mark
99131131af don't mark temp variables as safe through argument_to_value (#2307) 2024-01-25 12:34:21 -07:00
Mark Thom
44b945a5f3 Merge pull request #2306 from triska/dcg_representation
No longer use (->)//2 in library(clpb)
2024-01-23 15:22:17 -07:00
Mark Thom
3bff923331 Merge pull request #2305 from mthom/dependabot/cargo/h2-0.3.24
Bump h2 from 0.3.22 to 0.3.24
2024-01-23 13:50:17 -07:00
Markus Triska
a6ccf95076 improve error context
Source: https://github.com/mthom/scryer-prolog/issues/2304#issuecomment-1906434756
2024-01-23 21:43:34 +01:00
Markus Triska
665f319a0e no longer use (->)//2, since it is implementation defined
This addresses #2304.
2024-01-23 21:42:36 +01:00
dependabot[bot]
fe31afce6b Bump h2 from 0.3.22 to 0.3.24
Bumps [h2](https://github.com/hyperium/h2) from 0.3.22 to 0.3.24.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/v0.3.24/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.22...v0.3.24)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-23 18:20:39 +00:00
Mark Thom
ac07d2dfc8 Merge pull request #2303 from mthom/dependabot/cargo/shlex-1.3.0
Bump shlex from 1.2.0 to 1.3.0
2024-01-23 11:19:53 -07:00
dependabot[bot]
71165c6984 Bump shlex from 1.2.0 to 1.3.0
Bumps [shlex](https://github.com/comex/rust-shlex) from 1.2.0 to 1.3.0.
- [Changelog](https://github.com/comex/rust-shlex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/comex/rust-shlex/commits)

---
updated-dependencies:
- dependency-name: shlex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 21:53:43 +00:00
Mark Thom
eab3bff78b Merge pull request #2302 from triska/dcg_representation
Throw representation errors for unsupported DCG grammar control constructs
2024-01-22 00:26:23 -07:00
Markus Triska
81dba11ab1 use newly available false//0 2024-01-21 22:53:22 +01:00
Markus Triska
388fa5baa9 no longer use (->)//2, since it is implementation dependent 2024-01-21 22:50:36 +01:00
Markus Triska
fe3241c07c remove checks that are now no longer needed due to representation errors 2024-01-21 10:28:19 +01:00
Markus Triska
0559ddca2a ENHANCED: Throw representation errors for DCG bodies that use unsupported constructs.
This addresses #2285.
2024-01-21 10:28:19 +01:00
Markus Triska
98a046500f MODIFIED: (->)/2 in DCGs is now only supported in the context of if-then-else.
That is, ( If -> Then ; Else ) is still supported, but ( If -> Then ) not.
2024-01-21 10:28:19 +01:00
Mark Thom
58cd0d1669 Merge pull request #2301 from aarroyoc/docs-copy-term-3
Move copy_term/3 to library(iso_ext)
2024-01-19 10:18:59 -07:00
Mark Thom
6421fe10f8 Merge pull request #2300 from aarroyoc/fix-2298
Throw error in call_residue_vars/2
2024-01-19 10:15:35 -07:00
Adrián Arroyo Calle
99c85459a7 Move copy_term/3 to library(iso_ext) 2024-01-19 17:33:45 +01:00
Adrián Arroyo Calle
958bf51648 Throw error in call_residue_vars/2 2024-01-19 16:58:26 +01:00
Mark
e3aa85e2a2 add better no op detection in char_reader.rs (#2297) 2024-01-16 21:50:53 -07:00
Mark
29ced36a79 add #2293 tests, advance continuable HeapPStrIters away from unpacked compounds (#2293) 2024-01-14 15:07:33 -07:00
Mark
f9a5c2d341 fix additional tests, make better use of existing code (#2293) 2024-01-13 12:01:54 -07:00
Mark
dde03718e1 fix additional tests (#2293) 2024-01-12 22:01:01 -07:00
Mark
60d34bea70 add missing CStr branch to unify_partial_string (#2293) 2024-01-12 13:58:46 -07:00
Mark Thom
6fb3b61441 Merge pull request #2276 from triska/hophrase
ADDED: Support for higher-order non-terminals phrase//[2,3]
2024-01-11 11:56:10 -07:00
Mark Thom
11ca168175 Merge pull request #2281 from bakaq/miri
Initial Miri support
2024-01-10 12:13:14 -07:00
bakaq
f02c0eacd8 Make "cargo miri test" actually run 2024-01-09 04:38:53 -03:00
Mark
72a566d2f8 fix cargo fmt --check 2024-01-08 18:12:31 -07:00
Mark Thom
b56ae28c45 Merge pull request #2280 from notoria/clpz
Special case for `(^)/2`
2024-01-08 17:39:18 -07:00
Mark
cd89d71e0c check for PStr in eager stackful preorder iterator before adding tail of PStrOffset (#2272) 2024-01-08 17:36:41 -07:00
notoria
902cd5c3ea Special case for (^)/2
The only solutions for `Z #= X^Z` are `X = Z, X in -1\/1`. Also helps
avoid big numbers.
2024-01-08 21:50:02 +01:00
Mark Thom
f9eadc8e6a Merge pull request #2278 from notoria/clpz
Small fixes for `CLP(ℤ)`
2024-01-07 18:59:38 -07:00
Mark Thom
7b8c8fdda7 Merge pull request #2277 from triska/master
Correct arithmetic disequalities accidentally broken in f5d9a67f36
2024-01-07 18:59:18 -07:00
notoria
1f3de74cbd Fix bound computation in (^)/2
?- A in 0..1, B in-1..0, A^2 #= B.
   false. % unexpected.
?- A^2 #= B, A in 0..1, B in-1..0.
   A = 0, B = 0.
2024-01-07 20:19:40 +01:00
notoria
770ead9c05 Remove min/2 and max/2 when possible
?- A #= min(A,B).
   clpz:(B#>=A), clpz:(A#=min(A,B)). % unexpected.
?- A #= min(A,0).
   clpz:(A in inf..0), clpz:(A#=min(A,0)). % unexpected.
2024-01-07 20:15:28 +01:00
notoria
fe371ff1d1 Fix min/2 and max/2
?- X in 0..1, Y in 2..4, Z #= max(X,Y).
   clpz:(X in 0..1), clpz:(Z#=max(X,Y)), clpz:(Z in 2..4), clpz:(Z#>=Y), clpz:(Y in 2..4). % unexpected.
?- X in 0..1, Y in 2..4, Z #= max(Y,X).
   Y = Z, clpz:(X in 0..1), clpz:(Y in 2..4).
2024-01-07 20:14:32 +01:00
Markus Triska
2f783f0aef Correct arithmetic inequalities accidentally broken in f5d9a67f36.
Example:

    ?- X #>= Y.
    %@    clpz:(X#>=Y).
2024-01-07 09:33:54 +01:00
Mark Thom
92b85d4ba6 Merge pull request #2264 from Skgland/fix-os-argv-1
Fix os:argv/1 in case the raw args contain multiple `--`
2024-01-06 15:52:53 -07:00
Markus Triska
e702fe5c68 ADDED: Support for higher-order non-terminals phrase//[2,3]
These non-terminals take a grammar rule body and additional arguments
as arguments. These arguments are appended to the first argument.

A key motivation for the introduction of these non-terminals is found
in the discussion and sample code provided by @bakaq in:

    https://github.com/mthom/scryer-prolog/discussions/2260

In this way, portable higher-order DCG programming is possible while
keeping the logical grammar rule expansion implementation dependent.

Example:

    ?- phrase(phrase('.', a, []), Cs).
       Cs = "a".
2024-01-06 14:02:13 +01:00
Mark Thom
ed92e1b4f4 Merge pull request #2275 from triska/master
Prevent assertion of clauses for (-->)/2 when DCGs are enabled.
2024-01-05 12:33:05 -07:00
Markus Triska
f2b63d1689 Prevent assertion of clauses for (-->)/2 when DCGs are enabled.
This addresses #1508.
2024-01-05 19:04:53 +01:00
Mark
d51defed06 fix cargo --fmt check error 2024-01-04 13:56:57 -07:00
Mark
851ea2c45b add missing permission error in compile_assert (#2271) 2024-01-04 13:53:46 -07:00
Mark
ec97ee5d41 fix acceptance of invalid syntax, update iso_conformity_tests.pl (#2270) 2024-01-04 13:14:58 -07:00
Skgland
78b83ca1e1 simplify os:argv/1 fix 2024-01-04 19:26:10 +01:00
Skgland
ea0130d114 use once to limit solutions instead of cut 2024-01-04 18:14:32 +01:00
Skgland
e66e7c5034 add another test case for os:argv/1 2024-01-04 18:12:38 +01:00
Mark Thom
ff010678c3 Merge pull request #2269 from aarroyoc/fix-2267
Use reqwest async and use futures::executor
2024-01-03 15:40:48 -07:00
Mark Thom
5abc72cc8b Merge pull request #2268 from aarroyoc/docs-toplevel
Small fixes in documentation and toplevel.pl
2024-01-03 14:52:34 -07:00
Adrián Arroyo Calle
fac8866fb4 Use reqwest async and use futures::executor 2024-01-03 22:43:22 +01:00
Adrián Arroyo Calle
d58e91303b Small fixes in documentation and toplevel.pl 2024-01-03 19:52:50 +01:00
Skgland
8bd0317e9c fix os:argv(V) not completing 2024-01-02 21:43:38 +01:00
Skgland
76b1167842 fix os:argv 2024-01-02 20:54:37 +01:00
Skgland
7537686d8f cover both args ending in -- and args not ending in -- for os:argv/1 test 2024-01-02 20:48:38 +01:00
Skgland
6fc340c4db remove unnecessary true 2024-01-02 20:27:14 +01:00
Skgland
38f25af47d cover trailing -- and os:argv([]) in os_argv test 2024-01-02 20:23:53 +01:00
Skgland
91df533834 fix os:argv/1 2024-01-02 19:55:27 +01:00
Skgland
9a05ca0667 add failing test for os:argv issue
See https://github.com/mthom/scryer-prolog/pull/2263#issuecomment-1874400820
2024-01-02 19:51:09 +01:00
Mark
ccf581d86f expand module names in transitive goals (#2255) 2024-01-02 11:34:38 -07:00
Mark
1dc546ac36 fix cargo fmt --check 2024-01-02 10:08:00 -07:00
Mark
372b4bca46 mark anonymous variables in compile_is_call (#2257) 2024-01-02 10:06:07 -07:00
Mark Thom
5c89029462 Merge pull request #2263 from aarroyoc/docs-toplevel
Move argv/1 to library(os)
2024-01-02 09:19:10 -07:00
Mark Thom
a475a8a899 Merge pull request #2262 from triska/faster_global_cardinality
ENHANCED: Suspend propagation during filtering in global_cardinality/2.
2024-01-02 09:18:42 -07:00
Adrián Arroyo Calle
47b5ae7984 Move argv/1 to library(os) 2024-01-02 13:16:11 +01:00
Markus Triska
f5d9a67f36 ENHANCED: Suspend propagation during filtering in global_cardinality/2.
This allows subsequently invoked constraints to take the entire
filtering results into account, instead of being invoked when the
obtained information is not yet entirely used.

The SICStus-style attributed variables mechanism of Scryer Prolog
automatically prevents very subtle interaction problems that can arise
in systems that do not give all variables that are involved in a
unification an opportunity to schedule their propagators.

An example of such a subtle interaction is:

    ?- tuples_in([[A,C,B]], [[3,1,3],[4,2,4]]),
       global_cardinality([A,B,D], [3-1,4-2]),
       A = 4.

A = 4 causes pgcc_check/1 and pgcc/2 to be queued in the fast and slow
queue, respectively. In the fast queue, there is also rel_tuple/2,
which is worked off after gcc_check/1 and simultaneously instantiates
both C and B (to 2 and 4, respectively). Instantiation of C schedules
do_queue//0 from verify_attributes/3. Note that C does not participate
in the global_cardinality/2 constraint.

Critically, B also gets an opportunity to schedule its propagators in
this case, so another gcc_check/1 is run before gcc_global/2!
2024-01-01 10:50:06 +01:00
Mark Thom
1f90dbec20 Merge pull request #2259 from bakaq/comment_warnings
Emit warnings as Prolog comments
2024-01-01 00:33:58 -07:00
Mark Thom
d713456e29 Merge pull request #2258 from triska/faster_scalar_product
ENHANCED: Suspend propagation during filtering in scalar product constraints.
2024-01-01 00:33:36 -07:00
bakaq
d9d90d1ae8 Emit warnings as Prolog comments 2023-12-30 17:39:20 -03:00
Markus Triska
62b61107e0 ENHANCED: Suspend propagation during filtering in scalar product constraints.
This allows subsequently invoked constraints to take the entire
filtering results into account, instead of being invoked when the
obtained information is not yet entirely used.

It speeds up programs such as the one in:

    https://github.com/triska/clpz/issues/26
2023-12-30 10:30:25 +01:00
Mark Thom
1e0fa56786 Merge pull request #2252 from aarroyoc/bump-versions
Update ring and bump versions in Cargo.lock
2023-12-29 13:10:19 -07:00
Mark Thom
97d5bf7e97 Merge pull request #2254 from bakaq/issue_1404
Parse as much of a list as possible as a partial string
2023-12-29 10:40:19 -07:00
Mark
75302ab716 check that Target is an atom in scoped_clause_to_evacuable (#2248) 2023-12-29 10:12:08 -07:00
Adrián Arroyo Calle
742de9e77c Update ring and bump versions in Cargo.lock 2023-12-28 20:23:01 +01:00
bakaq
921046e886 Parse as much of a list as possible as a partial string #1404 2023-12-28 15:12:32 -03:00
Mark Thom
781f4afe25 Merge pull request #2251 from triska/crrl_ed25519
improve structure, naming and explanation of PKCS#8v2 encoding
2023-12-27 17:37:42 -07:00
Markus Triska
10158f62e0 improve structure, naming and explanation of PKCS#8v2 encoding 2023-12-27 21:12:52 +01:00
Mark
42d6749501 throw errors from char_reader.rs and get_n_chars when reading bad UTF8 data (#2244) 2023-12-26 12:31:04 -07:00
Mark Thom
2fa46e6b6c Merge pull request #2245 from triska/crrl_ed25519
ENHANCED: Use crrl for Ed25519 signing and signature verification.
2023-12-26 10:09:08 -07:00
Markus Triska
47ec5eb6c6 ENHANCED: Use crrl for Ed25519 signing and signature verification.
The main motivation for this change is the introduction of the newly
available predicate ed25519_seed_keypair/2, allowing to generate a key
pair from a given seed. In this way, a key pair can be dynamically
generated from (for example) a password, using crypto_password_hash/3
in combination with crypto_data_hkdf/4 to generate the seed. The
advantage of this method is that the private key need not be stored at
all anywhere.

It is not possible to add a corresponding feature to ring, since it is
closed as "not planned": https://github.com/briansmith/ring/issues/1003

I also used this opportunity to move more of the logic to Prolog. We
now have total control of the key pair representation, and I also
changed the representation to conform to the PKCS#8 v2 standard,
something that only later ring versions do, while still being
backwards compatible with tools that produce a wrong representation
including earlier ring versions.

Another great advantage we get from this change is that the Ed25519
predicates now also run on the 32-bit and WASM versions of Scryer.
2023-12-26 07:33:44 +01:00
Mark Thom
799035c692 Merge pull request #2243 from bakaq/issue_2241
Fix anonymous attributed variables not showing in toplevel
2023-12-22 09:53:40 -07:00
Mark Thom
6c07256dc5 Merge pull request #2242 from triska/starting
explain starting Scryer Prolog
2023-12-22 09:52:56 -07:00
bakaq
20c6a327ea Fix anonymous attributed variables not showing in toplevel #2241 2023-12-22 13:07:09 -03:00
Markus Triska
bcfdc812f9 explain starting Scryer Prolog 2023-12-22 08:36:29 +01:00
Mark
373b08a91e fix off-by-one error caused logtalk test to crash 2023-12-21 12:14:12 -07:00
Mark
a7154968d8 fix cargo fmt --check 2023-12-21 10:24:01 -07:00
Mark
46e432c4d9 restore [o|i]ip zeroing to trust and fix '$get_clause_p'/3 (#2238) 2023-12-20 20:45:15 -07:00
Mark Thom
44a61fa72c Merge pull request #2218 from bakaq/when
Add when/2 and when_si/2
2023-12-20 13:42:46 -07:00
Mark
299df50066 clamp lower_bound_of_target_clause index (#840) 2023-12-18 15:21:30 -07:00
Mark
335330690f don't replace undefined module predicates (#2232) 2023-12-18 14:57:22 -07:00
Mark
f30cee7655 fix retraction of local dynamic predicates (#2215, #2232) 2023-12-18 13:28:45 -07:00
Mark
b943afb7c7 fix '$get_clause_p' whose old implementation was broken by the introduction
of lookahead indexing
2023-12-18 13:28:45 -07:00
Mark
30f3818c66 improve performance of lower_bound_of_target_clause (#1598) 2023-12-18 13:28:45 -07:00
Mark Thom
13624568b5 Merge pull request #2233 from aarroyoc/fix-functor-2214
Throw ValidType::Atom error in functor
2023-12-17 20:20:50 -07:00
Mark Thom
e4f64581ec Merge pull request #2229 from aarroyoc/fix-backslash-docs
Fix backslash docs
2023-12-17 20:20:41 -07:00
Adrián Arroyo Calle
d132227860 Throw ValidType::Atom error in functor 2023-12-17 12:38:46 +01:00
Adrián Arroyo Calle
45abb4703d Fix backslash docs 2023-12-16 19:01:39 +01:00
Mark Thom
a66b93c96f Merge pull request #2226 from mthom/dependabot/cargo/zerocopy-0.7.31
Bump zerocopy from 0.7.25 to 0.7.31
2023-12-15 11:33:03 -07:00
Mark
e5ea95db8d Revert "improve performance of lower_bound_of_target_clause (#1598)"
This reverts commit 8938331915.
2023-12-15 00:42:58 -07:00
Mark
8938331915 improve performance of lower_bound_of_target_clause (#1598) 2023-12-15 00:39:36 -07:00
dependabot[bot]
749767539a Bump zerocopy from 0.7.25 to 0.7.31
Bumps [zerocopy](https://github.com/google/zerocopy) from 0.7.25 to 0.7.31.
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.7.25...v0.7.31)

---
updated-dependencies:
- dependency-name: zerocopy
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 03:52:00 +00:00
Mark
399b50b4d7 fix use of copy_term/3 for attribute goals in toplevel (#888, #2057, #2217) 2023-12-13 12:27:59 -07:00
Mark
82f3731c97 fix cargo style failure 2023-12-11 15:17:02 -07:00
Mark
658258c8c3 dereference port address in socket_server_open (#2222) 2023-12-11 14:38:20 -07:00
Mark
d14cce2374 restore print_tcp_listener in printer (#2221) 2023-12-11 13:29:27 -07:00
bakaq
f411fb1eb3 Tests for when/2 and solved bug 2023-12-11 12:28:59 -03:00
bakaq
6a30ccc907 Add when/2 and when_si/2 2023-12-10 20:55:50 -03:00
Mark Thom
1e1426cab0 Merge pull request #2207 from infogulch/ci-build-before-test
CI: Make test step output easier to read
2023-12-06 13:45:46 -07:00
Mark Thom
2e750671ca Merge pull request #2211 from Skgland/file-based-cli-tests
fix missing .pl file for singleton test case and move .pl files under `<testcase>.in/`
2023-12-06 13:27:14 -07:00
Skgland
147e47c8eb fix missing .pl file for singleton test case and move .pl files under <testcase>.in/
follow up to #2205
2023-12-06 21:21:28 +01:00
infogulch
7208916230 Clean up test step by compiling in build step 2023-12-05 20:51:04 -06:00
Mark Thom
43556f6df0 Merge pull request #2205 from Skgland/file-based-cli-tests
File based cli tests using trycmd
2023-12-05 14:45:00 -07:00
Mark Thom
c0c33392f1 Merge pull request #2203 from coasys/library-use-case
Don’t include unbound variables in results returned from run_query()
2023-12-05 13:14:30 -07:00
Nicolas Luck
77ce5a9586 Result with one empty match should be false 2023-12-05 15:00:07 +01:00
Mark Thom
8665722367 Merge pull request #2204 from mthom/remove_not_as_non_terminal
remove (\+)//1 (#1511)
2023-12-04 15:49:26 -07:00
Skgland
57b52fbe90 fix windows test by not disabling normalization
- this re-enables line ending and file path normalization
  - the latter might be unwanted, but there is only a shared flag
  - this might result in too loose matching of / and \ in stdout and stderr as prolog syntax may be mistaken for a path
2023-12-04 22:59:52 +01:00
Skgland
b052b62b16 fix formatting 2023-12-04 22:41:25 +01:00
Skgland
4df7e94d56 rename to match toml file
- goals.pl is used by both compound_goal.toml and multiple_goals.toml therefor renamed the later to share a common prefix with goals.pl, to keep them together
2023-12-04 22:23:04 +01:00
Skgland
fcf2e2db05 move .pl files from tests-pl next to the .toml of the test that uses them 2023-12-04 22:16:04 +01:00
Skgland
1c52de9ab1 File-oriented testing
inspired by #2191 but for the `run_top_level_test_with_args`s and  `run_top_level_test_no_args instead of the `load_module_test`s
2023-12-04 22:02:46 +01:00
Mark
9cd762d88a remove (\+)//1 (#1511) 2023-12-04 13:51:44 -07:00
Mark
eddcdaabef correct cargo fmt errors 2023-12-04 12:20:54 -07:00
Mark
2c76943d35 emit callable type errors from call/1 and phrase/3 when appropriate (#2202) 2023-12-04 12:20:14 -07:00
Nicolas Luck
24e3e1794e cargo fmt 2023-12-04 20:18:41 +01:00
Nicolas Luck
99055b553a Don’t include unbound variables in results returned from run_query 2023-12-04 20:10:06 +01:00
Nicolas Luck
576f13df60 Merge branch 'master' into library-use-case 2023-12-04 20:06:14 +01:00
Mark
004201abda add module name and missing predicate key to module_does_not_contain_claimed_export error (#2195) 2023-12-04 11:19:44 -07:00
Mark Thom
6899c6b63c Merge pull request #2201 from wkral/revert-2200-percent-graphic-char
Revert "Add '%' to the list of graphic_chars (#2199)"
2023-12-04 10:46:37 -07:00
William Kral
7f5c56a2a8 Revert "Add '%' to the list of graphic_chars (#2199)" 2023-12-03 22:32:49 -08:00
Mark Thom
92e07d2be1 Merge pull request #2200 from wkral/percent-graphic-char
Add '%' to the list of graphic_chars (#2119)
2023-12-03 23:02:05 -07:00
William Kral
aff1fdc6aa Add '%' to the list of graphic_chars (#2199) 2023-12-03 21:30:05 -08:00
Mark Thom
b0b1efcc49 Merge pull request #2194 from triska/clpz_monotonic
support (#=)/3 and (#<)/3 also in the monotonic execution mode
2023-12-02 20:16:59 -07:00
Markus Triska
eb575b9882 support (#=)/3 and (#<)/3 also in the monotonic execution mode 2023-12-02 22:33:56 +01:00
Mark
e667abb143 move propagated_var_nums insertion to proper scope (#2183) 2023-12-01 22:35:36 -07:00
Mark
347ee0211b propagate variable hits to parent branches in push_missing_vars (#2183) 2023-11-30 19:46:32 -07:00
Mark Thom
4f4feba6fc Merge pull request #2187 from triska/term_si
ADDED: term_si/1, true for terms
2023-11-29 13:52:38 -07:00
Markus Triska
8cb4dfef62 ADDED: term_si/1, true for terms
One use case is to ensure that once/1 is safe to use:

    term_si(Goal),
    once(Goal)

In such cases, Goal is ground and can yield at most one solution,
therefore once/1 does not remove any solutions.
2023-11-29 21:25:09 +01:00
Mark
de452bb2c2 fix overeager detection of (->)/2 in if position of (;)/2 (#2183) 2023-11-29 11:05:04 -07:00
Mark Thom
e8d8b09e52 Merge pull request #2186 from aarroyoc/cpu-now-wasm32
Implement $cpu_now in wasm32
2023-11-28 16:17:44 -07:00
Mark
631674db29 open pl files instead of directories (#2014) 2023-11-28 15:32:06 -07:00
Mark Thom
bc3ae52c7a Merge pull request #2184 from mthom/dependabot/cargo/openssl-0.10.60
Bump openssl from 0.10.57 to 0.10.60
2023-11-28 15:31:53 -07:00
Adrián Arroyo Calle
4c795018b4 Implement $cpu_now in wasm32 2023-11-28 23:30:02 +01:00
dependabot[bot]
651b7b2f59 Bump openssl from 0.10.57 to 0.10.60
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.57 to 0.10.60.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.57...openssl-v0.10.60)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-28 21:43:23 +00:00
Mark
5cb207d8b3 allocate cut variables properly (#2183) 2023-11-28 14:38:48 -07:00
Mark
de5de0cfaf allocate cut variables as temporaries when in non-allocating clause (#2183) 2023-11-28 12:58:54 -07:00
Mark
b8ef367824 bind missing module atom in retract/1 (#2182) 2023-11-25 20:59:04 -07:00
Mark Thom
f1458b772e Merge pull request #2169 from infogulch/flame
Benchmark improvements
2023-11-24 18:57:13 +01:00
Mark Thom
4181c9fab2 Merge branch 'master' into flame 2023-11-24 18:00:55 +01:00
Mark
1fbc7f9842 remove redundant running count increment in mark_non_callable (#2176) 2023-11-23 22:05:31 -07:00
Mark Thom
73ed08a412 Merge pull request #2179 from mthom/fix_stress_integration_test
Fix stress integration test
2023-11-23 21:31:12 +01:00
Mark
7cac13aefa set b0 to b for run_query call 2023-11-23 12:55:55 -07:00
Mark Thom
2e114df4c7 Merge pull request #2173 from aarroyoc/js-eval
Add js_eval/2 for wasm32
2023-11-22 21:52:49 +01:00
Adrián Arroyo Calle
36ab590c4e Add js_eval/2 for wasm32 2023-11-22 21:21:19 +01:00
Mark Thom
20da3427c1 Merge pull request #2177 from mthom/remove_assertx
Remove assert(a,z)/2 (#1975)
2023-11-22 17:54:55 +01:00
Mark
2811660fa7 remove assert(a,z)/2 (#1975) 2023-11-22 09:24:07 -07:00
Mark
ef8eb935d4 add CutPoint to select_switch_on_term_index (#2176) 2023-11-22 08:57:23 -07:00
infogulch
11832b524b Expose inference counts on Machine; publish to CI 2023-11-21 21:53:29 -06:00
infogulch
503e45eae1 Upgrade to latest iai for summary output 2023-11-21 21:53:19 -06:00
Mark Thom
041ec06dbc Merge pull request #1999 from triska/time_inferences
ENHANCED: time/1 now shows the number of inferences
2023-11-21 23:04:26 +01:00
Mark
3841b29db8 fix copy_term/2 variable copying bug in lists (#923, #2127) 2023-11-21 14:52:35 -07:00
infogulch
1c94624958 Benchmark improvements
* CI: Clean offline; display cleaned bytes; one artifact upload
* Add missing csv bench to iai benchmarks
* Generate flamegraphs for benchmarks
* Validate benchmark results separately
2023-11-21 13:54:16 -06:00
infogulch
c6f3700de1 Remove accidentally committed files 2023-11-21 13:54:16 -06:00
Markus Triska
186bba9d75 ENHANCED: time/1 now shows the number of inferences
Example:

    ?- time(member(X, "abc")).
       % CPU time: 0.000s, 1 inference
       X = a
    ;  % CPU time: 0.000s, 3 inferences
       X = b
    ;  % CPU time: 0.000s, 3 inferences
       X = c.

This is an initial step towards addressing #1039.
2023-11-21 20:36:44 +01:00
Mark
a3e83d59be fix error detection in int_pow (#2161) 2023-11-21 08:32:26 -07:00
Mark
54166b91eb add global_count inference counter that is always incremented (#2009) 2023-11-20 16:24:31 -07:00
Mark
1e5bb2d3da fix dif:vars_remove_goal/2 (#2175), untabify forms.rs to appease format check 2023-11-20 14:21:18 -07:00
Mark
8d9a759a7d remove unnecessary spaces around (|) (#2164) 2023-11-19 08:46:20 -07:00
Mark Thom
f32b035287 Merge pull request #2168 from aarroyoc/update-web-2023-11-15
Remove Scryer Prolog meetup banner :(
2023-11-16 21:07:25 +01:00
Mark Thom
a8e6930d19 Merge pull request #2159 from mthom/dependabot/cargo/rustix-0.38.21
Bump rustix from 0.38.14 to 0.38.21
2023-11-16 21:07:03 +01:00
dependabot[bot]
7fa4cb7ee8 Bump rustix from 0.38.14 to 0.38.21
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.38.14 to 0.38.21.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.38.14...v0.38.21)

---
updated-dependencies:
- dependency-name: rustix
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-16 19:27:40 +00:00
Mark Thom
df5855dbda Merge pull request #2167 from infogulch/ci-checks-permission
Add checks permission to ci workflow
2023-11-16 09:30:27 +01:00
Adrián Arroyo Calle
e7f5ba6ca1 Remove Scryer Prolog meetup banner :( 2023-11-15 22:42:18 +01:00
Mark Thom
bcb68fcc3d fix sign/1 (#2157) 2023-11-15 20:38:24 +01:00
infogulch
e5ee918063 Add checks permission to ci workflow
This should allow dependabot builds to complete
2023-11-15 13:07:45 -06:00
Mark Thom
4be320abc8 fix shr crash (#2158) 2023-11-14 08:15:19 +01:00
Mark Thom
300f5f817f Merge pull request #2165 from infogulch/bench-csv
Bench csv
2023-11-14 07:32:07 +01:00
Mark Thom
574a4d0758 Merge pull request #2166 from triska/more_tests
mention more passing tests
2023-11-14 07:31:52 +01:00
Markus Triska
a02bd46094 mention more passing tests 2023-11-14 04:09:03 +01:00
infogulch
cab80d3fa2 Fix lint 2023-11-13 15:41:15 -06:00
infogulch
98d8b00d7a Add csv parsing benchmark #1403 2023-11-13 15:41:06 -06:00
infogulch
40608dc8d4 Simplify benchmark setup; support mutating machine 2023-11-13 15:40:27 -06:00
Mark Thom
3b7d4a7b36 Merge pull request #2153 from infogulch/benchmark
Add benchmarks
2023-11-12 07:21:25 +01:00
Joe Taber
f704fcb41d Fix formatting issues 2023-11-11 13:33:19 -06:00
infogulch
8570f119c0 Add benchmarks using library interface 2023-11-11 13:32:34 -06:00
infogulch
1656d9d7ad CI: Setup rust in new action; split style & report actions 2023-11-11 13:32:34 -06:00
Mark Thom
50c64b8512 correct style failures 2023-11-11 18:57:47 +01:00
Mark Thom
83b9c6184c fix permanent variable handling over branches and cells (#2154) 2023-11-11 17:20:22 +01:00
Nicolas Luck
0ad479498c Activate run_query() integration test 2023-11-07 10:28:36 +01:00
Mark
2dd1f6e880 fix compare_pstr_to_string (#2148) 2023-11-04 19:32:23 -06:00
Mark Thom
da0018efdf Merge pull request #2147 from infogulch/lint-format
Resolve all lints and formating; split style checks into separate job
2023-11-04 11:34:11 -06:00
infogulch
16f768197b Split style checks, test reports into separate job 2023-11-04 02:22:24 -05:00
infogulch
d6fe5b5aad Bump Cargo.lock to reflect new scryer version 2023-11-04 02:20:55 -05:00
infogulch
dfe4fbfdc5 Add previous commit to .git-blame-ignore-revs 2023-11-04 02:20:37 -05:00
infogulch
9444e62df9 Resolve lints and format 2023-11-04 02:16:54 -05:00
Mark
dddffb01a6 update release version linked on website 2023-11-02 17:34:49 -06:00
Mark
4520bedf8d update release link 2023-11-02 17:32:33 -06:00
Mark
126d7bba57 bump version number to v0.9.3
Some checks failed
CI / build-test (--no-default-features, ubuntu-22.04, true, nightly, wasm32-unknown-unknown) (push) Has been cancelled
CI / build-test (macos-11, true, stable, x86_64-apple-darwin) (push) Has been cancelled
CI / build-test (true, ubuntu-22.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-20.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, 1.70, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, beta, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, nightly, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, true, stable, i686-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (windows-latest, true, stable, x86_64-pc-windows-msvc) (push) Has been cancelled
CI / logtalk-test (push) Has been cancelled
CI / release (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
2023-11-02 17:01:54 -06:00
Mark Thom
575245c62f Merge pull request #1880 from coasys/library-use-case
Programatic use of Machine / Scryer as library
2023-11-02 16:50:01 -06:00
Nicolas Luck
59264c0aa5 Check for target_arch = “wasm32”
instead of target_os = “wasi”
2023-11-02 19:07:55 +01:00
Nicolas Luck
ee1bd9e006 Merge branch 'master' into library-use-case 2023-11-02 11:12:54 +01:00
Mark
dfd9e43405 correct (\+)/1 (#2141) 2023-10-31 23:58:59 -06:00
Mark
8f06ef965a remove non-conforming hyperbolic and log10 evaluable functors 2023-10-28 18:17:43 -06:00
Mark
ae7cf15c70 fix signed modulus bug (#2134) 2023-10-28 18:13:42 -06:00
Mark Thom
469d2bd104 Merge pull request #2140 from aarroyoc/rename-to-upper
Rename `to_upper` to `upper` and `to_lower` to `lower`
2023-10-28 14:48:10 -06:00
Adrián Arroyo Calle
682b2ada4c Rename to_upper to upper and to_lower to lower 2023-10-28 19:16:07 +02:00
Mark Thom
f4e5426e97 Merge pull request #2137 from infogulch/master
CI: compile wasm separately; default 22.04; matrix
2023-10-26 14:07:18 -06:00
infogulch
6bae789bd6 CI: compile wasm separately; default 22.04; matrix 2023-10-26 14:23:32 -05:00
Mark
ff19db0084 qualify dif/2 call in reinforce_goal (#2135) 2023-10-25 12:26:01 -06:00
Mark
f10d7c05f9 correct char_type/2 (#2132) 2023-10-24 15:35:37 -06:00
Mark
f80dff851b remove unnecessary macros inclusion in mock_wam.rs 2023-10-24 15:15:29 -06:00
Mark
63cbeb9a3c correct modulus bug (#2118, #2119) 2023-10-24 14:20:26 -06:00
Mark
773d3f81fd remove list remnants from stack iteration in printer when cyclic (#2131) 2023-10-24 14:10:11 -06:00
Mark
4ab3e23b1f fix cycle detection in lists by looking backward analogously to the same process for structures (#2130) 2023-10-24 12:23:05 -06:00
Mark
d588b18c39 correct LIS backward bug in cycle_detection.rs 2023-10-23 13:28:44 -06:00
Mark
97b899f4a3 add STOP_AT_CYCLES const parameter for CycleDetectingIter 2023-10-23 12:05:13 -06:00
Mark
6a913bc4cc use Deutsch-Schorr-Waite to implement acyclic_term/1 (#2128) 2023-10-21 21:47:29 -06:00
Mark
bf46c4b5c1 use topo_sort to correct acyclic_term (#2124, #2125) 2023-10-18 12:00:40 -06:00
Nicolas Luck
69a0725c30 Cleanup Cargo.toml 2023-10-17 22:09:34 +02:00
Nicolas Luck
0c9740fe52 Fix wasm warnings 2023-10-17 22:07:38 +02:00
Mark
43f0b6c28d fix cyclicity detection through variables (#2122, #2123) 2023-10-16 15:19:43 -06:00
Nicolas Luck
2776beb842 Use std::sync::RwLock instead of tokio::sync::RwLock (by @aarroyoc) 2023-10-16 14:59:06 +02:00
Nicolas Luck
d7fa6c0ade Fix signalling of success/failure (by @mthom) 2023-10-16 14:56:17 +02:00
Nicolas Luck
025412aac0 Revert "Remove unuse import"
This reverts commit bfa7d3cf41.
2023-10-16 14:55:38 +02:00
Nicolas Luck
bfa7d3cf41 Remove unuse import 2023-10-16 13:44:51 +02:00
Nicolas Luck
9990780b82 Merge branch 'master' into library-use-case 2023-10-16 13:43:26 +02:00
Mark
dff2e73842 more eagerly check for cyclicity of variables in cycle detecting stackless iterator (#2121) 2023-10-15 17:43:29 -06:00
Mark
e2000859b6 add backward looking cyclicity check for variables in cycle detecting stackless iterator (#2111, #2117) 2023-10-15 13:07:41 -06:00
Mark
3a6aee72a3 correct is_cyclic again for non-variable ref cells (#2116) 2023-10-15 01:28:42 -06:00
Mark
3fb2e451a2 improve cycle detection in detect_list_cycles (#2111) 2023-10-15 00:58:19 -06:00
Mark
7875b96956 simplify stackless iterator is_cyclic (#2111) 2023-10-14 23:56:46 -06:00
Mark
d96c9e00b7 correct more acyclic_term/1 issues (#2111, #2114), add acyclic_term tests 2023-10-14 18:38:10 -06:00
Mark
379c252b89 correct cyclic variable check in cycle detecting stackless iterator (#2111, #2113) 2023-10-14 14:03:47 -06:00
Mark
307cb56ef5 fix bugs & incompleteness of cycle-detecting stackless iterator (#2111) 2023-10-14 13:00:58 -06:00
notoria
62e6ca02f9 Reify (^)/2
Like (/)/2, (^)/2 can fail in cases such as 0 #==> X #= 2^(-1), where success is expected.
2023-10-14 12:11:24 -06:00
notoria
c6fcbe20e1 Trigger propagator for popcount/1 2023-10-14 12:11:24 -06:00
notoria
a1b71f0440 Trigger propagator for sign/1 2023-10-14 12:11:24 -06:00
notoria
dc08c26d9f Trigger propagator for (xor)/2 2023-10-14 12:11:24 -06:00
Mark
669023914a add bounds checks for stackless iterator (#2110) 2023-10-14 12:11:22 -06:00
Mark
e4a677ceea detect all cycles in roughly linear time and constant space (#2102) 2023-10-13 18:05:52 -06:00
Mark
8aadc99f1d fix bugs in marker algorithm iterator 2023-10-13 14:38:50 -06:00
Mark
1ea397a807 correct (mod)/2 (#2103, #2107) 2023-10-13 14:33:50 -06:00
Mark Thom
b348f54c33 Merge pull request #2105 from triska/morphing_propagators
ENHANCED: Omit unnecessary residual constraints in disentailed reified (//)/2
2023-10-12 19:10:54 -06:00
Markus Triska
721cf20cf7 shift morphing to the more general p/2 case 2023-10-12 23:32:04 +02:00
Markus Triska
6ed9a99832 ENHANCED: Omit unnecessary residual constraints in disentailed reified (//)/2
Example:

    ?- #\ 0#=(Y// -1)/0.
    %@    clpz:(Y in inf..sup).

This addresses #2104.
2023-10-12 23:32:04 +02:00
Mark
1163d14ea1 fix control construct bugs, iter indentation (#947) 2023-10-11 12:41:45 -06:00
Mark
b83631fb20 Merge branch 'master' of ssh://github.com/mthom/scryer-prolog 2023-10-11 10:11:50 -06:00
Mark
902b08e657 follow marked variables to end in eager_stackful_iter (#2100, #2101) 2023-10-10 20:45:08 -06:00
Mark
b5fdde08aa follow marked variables to end in eager_stackful_iter (#2100, #2101) 2023-10-10 16:03:12 -06:00
Mark Thom
4962c3df11 Merge pull request #2098 from triska/morphing_propagators
Queue morphed propagators to give them a chance for propagation
2023-10-10 14:57:00 -06:00
Markus Triska
8de3498e07 use round brackets around operators to form valid Prolog terms 2023-10-10 21:32:45 +02:00
Markus Triska
26fdf83a48 update comment to reflect the used propagators 2023-10-10 21:32:45 +02:00
Markus Triska
32af047925 remove definition and calls of do_queue/0, which has become a NOP 2023-10-10 21:32:45 +02:00
Markus Triska
282633c877 ENHANCED: Queue morphed propagators to give them a chance for propagation.
This addresses #2096:

    ?- B in -2..0, 0#<==>0#=0/(B*B),labeling([],[B]).
       B = 0.

    ?- A#<==>A#=A/A^2,A=0.
       A = 0.
2023-10-10 21:32:45 +02:00
Mark
77de570aa4 report pre-marked values from eager stackful iterator (#2097) 2023-10-10 12:56:27 -06:00
Mark Thom
c9df19ca30 Merge pull request #2094 from triska/unary_minus
ENHANCED: use (+)/2 to express unary minus
2023-10-09 15:06:09 -06:00
Markus Triska
7c1cd18a06 Z --> Y 2023-10-09 23:13:09 +02:00
Mark Thom
0ca2356be5 Merge pull request #2092 from triska/morphing_pexp
attach the propagator to Y
2023-10-09 15:05:59 -06:00
Markus Triska
8329d222cb ENHANCED: use (+)/2 to express unary minus
This makes answers a bit shorter and more readable.

Example:

    ?- X #= -Y.
       clpz:(X+Y#=0).

This addresses #2058.
2023-10-09 22:59:51 +02:00
Markus Triska
1c3df1cdd7 attach the propagator to Y 2023-10-09 21:55:39 +02:00
Mark Thom
b149805b9e Merge pull request #2091 from triska/morphing_pexp
ENHANCED: Omit projection of morphed (^)/2 in disentailed constraints.
2023-10-09 13:43:25 -06:00
Markus Triska
99348ec309 ENHANCED: Omit projection of morphed (^)/2 in disentailed constraints.
Example:

    ?- B #<==> (0^Y/0) #= Z.
       B = 0, clpz:(Y in 0..sup), clpz:(Z in inf..sup).
2023-10-09 21:33:04 +02:00
Mark Thom
c6976c0f92 Merge pull request #2090 from triska/morphing_propagators
FIXED: Queue triggered propagators to be processed after pexp/3 finishes
2023-10-09 13:20:44 -06:00
Markus Triska
cacc7f3193 FIXED: Queue triggered propagators to be processed after pexp/3 finishes
If reification constraints (such as reified equality) are triggered
here, then they may wish to disable this propagator and remove
attributes from auxiliary variables. If the pexp/3 propagation is
interrupted for that purpose, then the attributes will be
unintentionally reattached by the following fd_put/3 calls in this
propagator. We must ensure that this propagator completely finishes,
so we queue the triggered propagators for later processing.

geq/2 implements propagator activation outside the queue, and thus
should not be used in propagators in the way it was used here.

pexp/3 by itself may not seem particularly important. However, it can
arise by metamorphosis from Var*Var. Example:

    ?- A#<==> -1#=C*C, C in 0..1.
       A = 0, clpz:(C in 0..1).

This addresses #2089.
2023-10-09 20:42:28 +02:00
Mark
4b9cf0952e do not push stack variables to the heap in term_variables (#2087) 2023-10-09 11:38:17 -06:00
Mark Thom
6d37684e9c Merge pull request #2088 from triska/morphing_propagators
ENHANCED: Remove no longer needed morphed propagators.
2023-10-08 12:45:45 -06:00
Markus Triska
743412de33 ENHANCED: Remove no longer needed morphed propagators.
This addresses all remaining cases from #2083, excepting (//)/2:

    ?- #\ 1#=(X*X)/0.
       clpz:(X in inf..sup).

    ?- #\ 1#=(X+X)/0.
       clpz:(X in inf..sup).

Still remaining:

    ?- #\ 0#=(Y// -1)/0.
       clpz:(-1*Y#=_A).
2023-10-08 20:15:56 +02:00
Mark Thom
11c1ee4481 Merge pull request #2085 from triska/reification_same_queue
Use the same queue for variables in reified constraints
2023-10-08 12:01:26 -06:00
Markus Triska
f34703a279 remove no longer needed goal projection for pdiv 2023-10-08 12:07:17 +02:00
Markus Triska
5cce8ddd7d ENHANCED: avoid pending residual constraints in disentailed reified (div)/2
This addresses #2083:

    ?- #\0#=0//0 div 2.
       true.
2023-10-08 11:53:06 +02:00
Markus Triska
ff63eacf2c replace list//1 by seq//1 from library(dcgs) 2023-10-08 11:28:52 +02:00
Markus Triska
8121dce2a4 instead of prdiv, use ptimes directly 2023-10-08 09:46:41 +02:00
Markus Triska
4d910f6bfe FIXED: variables in reified propagators must share the same queue
Otherwise, propagation steps may be inadvertently omitted, if
propagators are scheduled in a different queue.

This addresses #2084.
2023-10-08 09:45:20 +02:00
Markus Triska
51c00fce57 adapt query to Scryer Prolog 2023-10-08 09:26:22 +02:00
Mark
1ab14ea519 mark both components of a PStrLoc (#2082) 2023-10-07 18:48:49 -06:00
Mark Thom
c5c7c1913a Merge pull request #2080 from triska/reified_slash
Corrections to reified (/)/2
2023-10-06 15:31:13 -06:00
Markus Triska
3fc969b38b reorder and realign entries to form a contiguous group starting with d(D) 2023-10-06 22:58:56 +02:00
Markus Triska
7ed38d6c6c FIXED: reification of (/)/2 for undefined subexpressions
This addresses #2078 and #2079.
2023-10-06 22:55:46 +02:00
Mark
fa68fa211c replace eager_stackful_iter's mark stack with a second unmark phase 2023-10-05 20:21:28 -06:00
Nicolas Luck
69cf2c36bc Deactivate tokio runtime respawning on interrupt 2023-10-05 12:11:28 +02:00
Nicolas Luck
640c637ca8 Merge branch 'master' into library-use-case
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/http.rs
#	src/machine/mock_wam.rs
#	src/machine/mod.rs
#	src/machine/system_calls.rs
2023-10-05 12:06:47 +02:00
Mark
0ad4427f83 use eager_stackful_preorder_iter in variable_set, add term_variables/1 tests 2023-10-04 15:12:25 -06:00
Mark
1bfdea7527 rewrite ground_test, add tests for ground/1 (#2075) 2023-10-04 14:17:03 -06:00
Mark
6c36d067d7 Revert "consider Str, PStrLoc in ElideLists of StackfulHeapIterator (#2075)"
This reverts commit 1e60eeef34.
2023-10-04 11:57:09 -06:00
Mark
1e60eeef34 consider Str, PStrLoc in ElideLists of StackfulHeapIterator (#2075) 2023-10-04 00:27:01 -06:00
Mark Thom
005570c90a Merge pull request #2076 from infogulch/master
Pin logtalk to version before scryer support was removed
2023-10-03 21:24:19 -06:00
infogulch
c070fbec62 Pin logtalk to version before scryer support was removed 2023-10-03 21:14:45 -05:00
Mark
f9d44c93fd check for free variables in locations removed from iterator stack in ground_test (#2075) 2023-10-03 15:31:01 -06:00
Nicolas Luck
fab5ca9440 Fix nested List parsing 2023-10-03 20:19:57 +02:00
Nicolas Luck
7b128a9f00 Handle stub_b = b as false 2023-10-03 20:12:11 +02:00
Mark
fd14869ddc correct cycle detection in ground/1 (#2073) 2023-10-03 12:07:36 -06:00
Mark Thom
07d7d3b13b Merge pull request #2074 from triska/expansion_simpler
Revert "FIXED: corrections to expansion_simpler/2"
2023-10-03 11:54:04 -06:00
Markus Triska
7c10683e46 Revert "FIXED: corrections to expansion_simpler/2"
This reverts commit f3b848537a.

The root cause of this problem is a mistake in ground/1. See #2073.
2023-10-03 19:16:04 +02:00
Mark Thom
3ffea2d987 Merge pull request #2072 from aarroyoc/fix-urldecode
Improved version of url_decode
2023-10-02 16:06:35 -06:00
Mark Thom
770665a7b8 Merge pull request #2070 from triska/expansion_simpler
FIXED: corrections to expansion_simpler/2
2023-10-02 16:06:10 -06:00
Adrián Arroyo Calle
93ff049e54 Improved version of url_decode 2023-10-02 23:49:09 +02:00
Markus Triska
f3b848537a FIXED: corrections to expansion_simpler/2
Example:

    ?- X = 0, Y = 0, Z #= X-1 + Y-1.
       X = 0, Y = 0, Z = -2.

This addresses #2064.

See ca5a5b4392 for a previous issue in
this logic.
2023-10-02 23:17:06 +02:00
Mark
27b971cbfa add registers to inlined instruction functors 2023-10-01 23:50:07 -06:00
Mark
a1ceeb697a consider an '$aux' a relation of the unexpanded goal's variables in compile_inline_or_expanded_goal (#2062) 2023-10-01 23:49:55 -06:00
Mark
4a8aa0acbd throw instantiation_error from error/2 if Error_term uninstantiated (#2060) 2023-09-30 22:35:46 -06:00
Mark
6fa00b5b55 get rid of inference_limit_exceeded(B) as an error term (#2023) 2023-09-30 22:35:46 -06:00
Mark Thom
c2218faf47 Merge pull request #2066 from bakaq/dif_tests
Add tests for #2056
2023-09-30 18:41:50 -06:00
bakaq
21c61b6e3a Add tests for #2056 2023-09-30 21:33:42 -03:00
Mark
b065e1cd53 correct depth calculation for lists that are their own car (#1876) 2023-09-30 17:15:20 -06:00
Mark
7d6ce119f5 substitute names for cyclic variables permitted by max_depth > 0 in check_for_seen using a loop (#2057) 2023-09-30 16:47:13 -06:00
Mark
62c23166fa implement ListElisionPolicy to restore previous printer behavior 2023-09-30 16:00:15 -06:00
Mark
25afc11168 correct skipping of not fully visited lists in stackful heap iterator (#2056, #2063, #2065) 2023-09-30 15:24:30 -06:00
Mark
9e713406d3 correct max_depth marking for lists 2023-09-30 11:44:20 -06:00
Mark
f33f641f11 further max_depth improvements 2023-09-29 12:07:12 -06:00
Mark
ca2ddfeed0 improve max_depth write option (#1876, #2053) 2023-09-29 01:00:14 -06:00
Mark
11cd42379b do not deref AttrVar binding in redo_attr_var_binding (#2059) 2023-09-28 15:25:57 -06:00
Mark
40d3345cd5 revert throwing domain errors for unexpected forms of read-options (#2015) 2023-09-27 18:58:45 -06:00
Mark
035e214ef5 check for ChildCloseList in print_struct on [] (#2039) 2023-09-27 18:16:23 -06:00
Mark
f630a8cc1a fix add_predicate_declaration bug not correctly identifying lists of predicate indicators (#2049, #2050, #2051, #2052) 2023-09-27 17:55:15 -06:00
Mark
0bfb08e464 remove debug symbols from release builds (#2054) 2023-09-27 13:53:33 -06:00
Mark Thom
5f6ae3857b Merge pull request #1998 from aarroyoc/warp-http-server
Replace Hyper with Warp for HTTP server
2023-09-27 13:35:46 -06:00
Mark
750544dd2a fix max_depth settings for partial strings on lists (#1876) 2023-09-27 13:34:24 -06:00
Adrián Arroyo Calle
660860bccf Replace Hyper with Warp for HTTP server
- Use Warp
- Optimize clones
- HTTPS server
- Content-Length limit
- HTTP Basic Auth
- Stop server with Ctrl-C
2023-09-27 18:50:19 +02:00
Mark Thom
841aaa78b4 Merge pull request #2048 from infogulch/master
Build windows with msvc #1998; add ubuntu 22.04 target #2047
2023-09-27 10:43:54 -06:00
infogulch
93f46a4142 Tidy ci.yaml 2023-09-27 02:58:48 -05:00
infogulch
a86db1bde8 Build windows with msvc 2023-09-27 02:57:02 -05:00
infogulch
4163437d5a Add ubuntu 22.04 2023-09-27 00:31:08 -05:00
Mark
a6535c28ea remove module_resolution_error (#2035) 2023-09-26 14:06:21 -06:00
Mark
2efe95f2fb filter our builtins from current_predicate/1 (#153) 2023-09-26 13:46:21 -06:00
Mark
56992570d8 check for predicate_indicator list and sequence types in add_predicate_declaration (#1586) 2023-09-26 12:54:16 -06:00
Mark
39934208c3 throw instantiation_error when appropriate from parse_write_options_ (5.5.12 of the standard, #1965) 2023-09-26 12:08:51 -06:00
Mark
193bb313fd correct OutOfFiles resource error (#1375) 2023-09-26 11:22:56 -06:00
Mark
e8334f9b67 add predicate indicator sequences to loader:add_predicate_declaration (#1586) 2023-09-26 11:21:47 -06:00
Mark
280ff8b5d0 throw an error instead of allowing builtin modules to be overwritten (#2042) 2023-09-25 19:21:34 -06:00
Mark
172bb9e96a Merge branch 'master' of ssh://github.com/mthom/scryer-prolog 2023-09-25 16:09:20 -06:00
Mark
c04f1dea48 fix off-by-1 bug in '$skip_max_list'/4 (#2037) 2023-09-25 16:09:04 -06:00
Mark Thom
9114c982e0 Merge pull request #2032 from bakaq/phrase_from_stream
Add phrase_from_stream/2 to library(pio)
2023-09-25 12:04:33 -06:00
bakaq
f644a76281 Remove reposition option from phrase_from_file/2 2023-09-25 02:18:05 -03:00
bakaq
63bb993c02 Inline string_get_n_chars_/3 2023-09-24 19:29:51 -03:00
bakaq
c50291cec8 Better string_get_n_chars_/3 2023-09-24 19:21:03 -03:00
bakaq
2fe79b5fc3 Fixed bug with '$skip_max_list'/4 2023-09-24 15:08:24 -03:00
bakaq
b4fab5a806 Use '$skip_max_list'/4 in string_get_n_chars/4 2023-09-24 14:32:44 -03:00
bakaq
35d0042be1 Add phrase_from_stream/2 to library(pio) 2023-09-24 14:32:44 -03:00
Mark Thom
75dcc3f276 Merge pull request #2040 from rujialiu/allow-cr
Solves CRLF/CR issue by considering'\r' a `layout_char` #553 #2028
2023-09-24 11:11:15 -06:00
Rujia Liu
9c43974747 Solves CRLF/CR issue by considering'\r' a layout_char #553 #2028 2023-09-24 19:10:40 +08:00
Mark Thom
4be5fc6d43 Merge pull request #2038 from infogulch/patch-1
Allow all matrix ci jobs to run to completion even if one fails
2023-09-24 00:44:33 -06:00
Joe Taber
f03336b3a2 Allow all jobs to run to completion even if one fails
See: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategyfail-fast
2023-09-23 21:43:51 -05:00
Mark
a5db117ef6 fix off-by-1 bug in ''/4 (#2037) 2023-09-23 18:32:32 -06:00
Mark
142e0c2c3a don't parse bracketed non-operators as functor terms (#2033) 2023-09-23 14:26:28 -06:00
Mark
1c8cd85f6c record compaction depth after reduce_op if '|' an operator (#1905) 2023-09-23 00:19:54 -06:00
Mark
c547f67c54 add (now failing) test 317 to iso_conformity_tests.pl 2023-09-21 16:49:45 -06:00
Mark
c26e9436b4 generalize multifile/dynamic/discontiguous declarations over lists of predicate indicators (#1586) 2023-09-21 16:22:41 -06:00
Mark
b3239abea1 throw resource error if OpenOptions raises an error of uncategorized kind (#1375) 2023-09-21 14:36:53 -06:00
Mark Thom
81edd4592f Merge pull request #2027 from bakaq/dif
Improvements to dif/2
2023-09-21 11:32:38 -06:00
Mark Thom
7484433e2b Merge pull request #2026 from infogulch/master
Simplify fn maybe
2023-09-21 11:31:35 -06:00
bakaq
cb79e83510 Avoid dif/1 attribute with empty list
Closes #1956
2023-09-21 14:00:37 -03:00
bakaq
cac52c0537 Run dif tests on cargo test 2023-09-21 12:14:27 -03:00
bakaq
f5c23fbb16 Tests for dif/2 2023-09-20 20:56:25 -03:00
bakaq
a64a765f32 Improved dif/2 2023-09-20 20:56:04 -03:00
infogulch
eecfeb2d03 Simplify maybe
Fix whitespace
2023-09-20 18:23:07 -05:00
Mark Thom
54a0313d72 Merge pull request #2025 from aarroyoc/random-seed
Use a SeedableRng to generate random numbers
2023-09-20 15:03:21 -06:00
Adrián Arroyo Calle
7cf6e77f4d Use a SeedableRng to generate random numbers 2023-09-20 22:07:46 +02:00
Nicolas Luck
4968fa0024 Remove debugging println! 2023-09-18 19:31:56 +02:00
Nicolas Luck
5e55625733 Remove some debug println!s 2023-09-18 19:12:50 +02:00
Nicolas Luck
65f64e428e Construct and return exception string 2023-09-18 13:25:27 +02:00
Nicolas Luck
d2f5291412 mthom's changes fixing the panic 2023-09-18 13:01:27 +02:00
Mark
9dc1c339ef remove unnecessary Result return type from read_term_from_heap 2023-09-15 14:10:42 -06:00
Nicolas Luck
c86304b18e Remove lib_toplevel.pl 2023-09-15 11:01:16 +02:00
Nicolas Luck
7c83a1fb8e Cleanup code that's not needed anymore 2023-09-15 10:48:41 +02:00
Nicolas Luck
f02728aab3 Construct QueryResult from printer output 2023-09-15 10:44:59 +02:00
Nicolas Luck
48283c4dbc mthom's changes to run_query with backtracking 2023-09-15 10:04:11 +02:00
Nicolas Luck
6bdd7f3a3f mthom's revised run_query with manually created printer and some cleanup 2023-09-14 22:00:50 +02:00
Mark Thom
6e0dd371a0 Merge pull request #2018 from triska/libffi
use version from crates.io
2023-09-13 15:05:31 -06:00
Markus Triska
5b1df8c4b3 use version from crates.io 2023-09-13 20:45:38 +02:00
Nicolas Luck
5fa68e253c lib_machine tests should not be tokio/async 2023-09-13 19:51:57 +02:00
Mark Thom
3e14ef634f Merge pull request #2017 from cmpute/master
Upgrade dashu and make the related code more idomatic.
2023-09-13 10:41:34 -06:00
Jacob
adb5fcf708 Upgrade dashu and some changes 2023-09-13 12:29:12 -04:00
Nicolas Luck
136463c92e Merge branch 'master' into library-use-case
# Conflicts:
#	Cargo.toml
#	src/atom_table.rs
#	src/bin/scryer-prolog.rs
#	src/http.rs
#	src/machine/mock_wam.rs
#	src/machine/mod.rs
#	src/machine/system_calls.rs
2023-09-13 18:13:14 +02:00
Nicolas Luck
ef56193c44 Use write_term_to_heap as suggest, clean up, and include error in comment 2023-09-13 17:17:02 +02:00
Mark
4077040d03 update syn crates 2023-09-12 14:52:42 -06:00
Mark
de440a8c92 get rid of OssifiedOpDir, DBRef, simplify current_op/3 2023-09-11 15:36:15 -06:00
Mark Thom
c75f74f681 Merge pull request #1993 from coasys/dashu-fixes
Dashu fixes
2023-09-11 11:33:16 -06:00
Mark Thom
46c78ad338 Merge pull request #2013 from gruhn/fix-docker-debian-bullseye
fix Docker image
2023-09-11 11:23:10 -06:00
Niklas Gruhn
2b7a8875c0 fix Docker image
The Docker image is broken with the error message:

    scryer-prolog: error while loading shared libraries:
    libssl.so.1.1: cannot open shared object file: No such
    file or directory

We use the base base image `debian:stable-slim` and in the
background a new Debian version was marked stable (bookworm),
which has libssl3 instead of libssl1.1 installed.

I downgraded the base image to the previous stable version
(bullseye), which seems to fix the issue.
2023-09-11 01:46:59 +02:00
Mark Thom
2ee131c52c Merge pull request #2010 from aarroyoc/update-website-0.9.2
Update INDEX.dj
2023-09-10 17:45:45 -06:00
Adrián Arroyo Calle
f3901cd8b8 Update website to mention 0.9.2 and playground 2023-09-10 23:12:10 +02:00
Fayeed Pawaskar
7f0536b51d Merge branch 'master' into dashu-fixes 2023-09-10 21:51:02 +05:30
Fayeed Pawaskar
af76659830 Removed value method and use deref to get type 2023-09-10 21:40:22 +05:30
Mark Thom
fb658c4918 Merge pull request #2008 from triska/clpb_improvements
Various CLP(B) improvements
2023-09-09 00:40:30 -06:00
Markus Triska
85cc4a80d0 remove code that is not needed in Scryer Prolog 2023-09-09 07:46:01 +02:00
Markus Triska
6fe85c5779 remove more attributes so that they do not appear in residual goals 2023-09-09 07:46:01 +02:00
Markus Triska
b38a56e7d3 move compatibility predicates and meta_predicate/1 declarations so that they are correctly taken into account 2023-09-09 07:46:01 +02:00
Mark Thom
cbf18e5c3a Merge pull request #2006 from infogulch/wasm-ci
Add wasm build steps
2023-09-08 23:34:59 -06:00
Mark Thom
96bd0d267c Merge pull request #2007 from triska/rust_1_70
update required Rust version
2023-09-08 23:34:36 -06:00
Markus Triska
ec67752db4 shorter partition/5, relying on first instantiated argument indexing 2023-09-09 07:32:06 +02:00
Markus Triska
ad4c17fbb6 add meta_predicate/1 declaration for include/3 and exclude/3 2023-09-09 07:32:06 +02:00
Markus Triska
672979c515 shorter include/3 and exclude/3, relying on improved indexing 2023-09-09 07:32:06 +02:00
Markus Triska
efcc2b81cd add licensing information, addressing part of #1798 2023-09-09 07:32:06 +02:00
Markus Triska
640f29fe0f update required Rust version 2023-09-09 07:30:23 +02:00
Joe Taber
13a0085408 Add wasm build steps 2023-09-08 22:47:06 -05:00
Mark Thom
74440d503e Merge pull request #2004 from triska/generalize_description
this holds for all architectures (also 32-bit systems)
2023-09-08 16:11:06 -06:00
Mark Thom
f4769de5c4 Merge pull request #2003 from triska/clpz_comment
update comment
2023-09-08 15:22:49 -06:00
Markus Triska
b843b76b7a this holds for all architectures (also 32-bit systems) 2023-09-08 23:22:36 +02:00
Markus Triska
182afe3b7d update comment 2023-09-08 22:34:24 +02:00
Mark Thom
920e0c6b56 Merge pull request #1986 from rujialiu/wasm32-support
Basic WebAssembly support with minimal Javascript API #615
2023-09-08 11:15:51 -06:00
Rujia Liu
b6ce6b7cdb Basic WebAssembly support with minimal Javascript API #615. Currently 6/12 crypto functions supported. Tested in browser with all default features disabled. 2023-09-08 17:27:22 +08:00
Mark
a0b5a24853 check atom == ',' in ambiguity_check mirroring logic in print_op_addendum (#2000) 2023-09-05 14:56:26 -06:00
Mark
fa11d6bdd4 remove error printing redundancy and inconsistent state resulting from file_load_cleanup (#1995) 2023-09-05 13:53:57 -06:00
Mark Thom
a9aef2bc84 Merge pull request #1980 from Skgland/atomtable
make AtomTable consurrency safe
2023-09-05 12:32:20 -06:00
Mark Thom
bf2b73706a Merge pull request #1997 from triska/countall
Corrections to countall/2
2023-09-05 12:04:52 -06:00
Mark
83ebce86b6 call_with_inference_limit/3 should fail if inference limit is exceeded and R term is not inference_limit_exceeded (#1977) 2023-09-05 11:51:06 -06:00
Markus Triska
1967518fa2 FIXED: documentation of countall/2 (#1976) 2023-09-05 19:42:55 +02:00
Bennet Bleßmann
5928d64d7a make F64Table concurency safe 2023-09-05 19:39:59 +02:00
Bennet Bleßmann
c7ec5a13a5 remove locks from AtomTable
there are technically still two locks
- the Mutex to serialize consurrent updates to the AtomTable
- the RwLock as part of GLOBAL_ATOM_TABLE

the former is the age lock of RESIZE ATOM TABLE in <https://arxiv.org/pdf/1608.00989.pdf>, though we use it for the whole update as we don't match the whole structure and can't reserve an atom slot as is, so we need to also lock concurrent updates without resizing

the later should be uncontendet as we only write AtomTable::new iff the current value is a dangling Weak
2023-09-05 19:39:59 +02:00
Bennet Bleßmann
01aeb7515d [WIP] move towards lockless AtomTable 2023-09-05 19:39:46 +02:00
Markus Triska
d54c3369b3 FIXED: countall/2 for zero solutions (#1996)
Example:

    ?- countall(false, 0).
       true.
2023-09-05 19:39:05 +02:00
Skgland
d24e6100a7 fix rust_beta_channel feature 2023-09-05 19:12:23 +02:00
Skgland
cd0e45b70e fix accidentally left in println!() 2023-09-05 19:12:23 +02:00
Skgland
0f0018abe4 raise msrv for OnceLock support 2023-09-05 19:12:23 +02:00
Skgland
a95c5e26e6 add comment why blocking_write is not used 2023-09-05 19:12:23 +02:00
Skgland
70b6cc8e55 fix deadlock in load_library_as_stream 2023-09-05 19:12:22 +02:00
Bennet Bleßmann
13cbff7eab [WIP] fix deadlock in AtomTable::build_with 2023-09-05 19:12:22 +02:00
Skgland
86166dbf25 [WIP] make AtomTable concurrentcy ready 2023-09-05 19:12:22 +02:00
Skgland
b2130c2a48 run cargo fmt 2023-09-05 19:12:17 +02:00
Mark
5585e83fd6 correct inference counting over index backtracking, built-ins (#1977, #1987) 2023-09-04 17:15:16 -06:00
Fayeed Pawaskar
7b921fc767 Implemented num_order methods on Integer & Rational numbers 2023-09-04 14:12:47 +05:30
Fayeed Pawaskar
cfd67c8337 Added new unify methods 2023-09-04 14:12:11 +05:30
Fayeed Pawaskar
dc498d4de8 Fixed warning 2023-09-04 14:11:54 +05:30
Fayeed Pawaskar
2c67106f26 Added value method to get the generic type from TypedArenaPtr 2023-09-04 14:11:30 +05:30
Fayeed Pawaskar
b105c33b79 Added latest dashu from github 2023-09-04 14:09:45 +05:30
Mark Thom
2ccc238119 Merge pull request #1991 from triska/discoverable_flags
FIXED: make occurs_check and answer_write_options flags discoverable
2023-09-03 18:39:24 -06:00
Mark Thom
e693b7d33b Merge pull request #1990 from triska/clpb_max
remove clpb_max/1 attribute for residual goal projection
2023-09-03 18:39:12 -06:00
Markus Triska
aca0de06cd FIXED: make occurs_check and answer_write_options flags discoverable
Quoting from 7.11 Flags:

   NOTE - A built-in predicate current_prolog_flag(Flag, Value)
   (8.17.2) enables a program to discover all the flags supported
   by a processor and their current values.
2023-09-04 00:56:09 +02:00
Markus Triska
85f4bdbe0b update answer 2023-09-03 22:01:38 +02:00
Markus Triska
1257ba165f untabify 2023-09-03 21:57:51 +02:00
Markus Triska
1c33d2a2ed remove clpb_max/1 attribute for residual goal projection
Example:

    ?- sat(A+B), weighted_maximum([1,1], [A,B], Max).
       A = 1, B = 1, Max = 2.
2023-09-03 21:56:15 +02:00
Mark Thom
99bd3d3b1a Merge pull request #1988 from triska/answer_write_options
ADDED: New Prolog flag, answer_write_options.
2023-09-03 11:36:40 -06:00
Mark Thom
d8aed0ac4f Merge pull request #1989 from triska/mention_binaries
mention precompiled binaries
2023-09-03 11:36:07 -06:00
Markus Triska
5ebd4bb2a4 mention precompiled binaries 2023-09-03 14:12:46 +02:00
Markus Triska
c934e06171 ADDED: New Prolog flag, answer_write_options.
This lets us specify additional write options used by the top level
for writing answers.
2023-09-03 10:49:07 +02:00
Nicolas Luck
8a0685a3e9 Debug print value of register 6 which leads to failing heap dereference 2023-08-30 20:01:56 +02:00
Nicolas Luck
2b018be392 Add back needed dep. hyper-util and upgrade hyper to rc4 2023-08-30 20:00:56 +02:00
Nicolas Luck
4d19c437e0 Merge branch 'master' into library-use-case
# Conflicts:
#	Cargo.toml
#	src/machine/mock_wam.rs
#	src/machine/mod.rs
2023-08-30 18:12:26 +02:00
Nicolas Luck
44c274b9e9 WIP: Pure Rust impl. of run_query 2023-08-30 17:35:36 +02:00
Mark
66f6399b8a refine is/2 compilation so errors are thrown when expected without needlessly allocating (#1974, #1984) 2023-08-29 16:42:23 -06:00
Mark
53a1be78cc don't compile is instruction if bound to anonymous variable (#1974) 2023-08-29 15:50:04 -06:00
Mark
78b35dc57d update Cargo.toml version numbers and bump version number
Some checks failed
CI / build-test (macos-11, stable, bash, x86_64-apple-darwin) (push) Has been cancelled
CI / build-test (true, ubuntu-20.04, stable, bash, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-20.04, 1.65, bash, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-20.04, beta, bash, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-20.04, nightly, bash, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-20.04, stable, bash, i686-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (windows-latest, stable, msys2 {0}, x86_64-pc-windows-gnu) (push) Has been cancelled
CI / logtalk-test (push) Has been cancelled
CI / release (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
2023-08-28 13:23:56 -06:00
Mark Thom
c65d1204af Merge pull request #1978 from aarroyoc/ci-32-bits
32 bit CI for Linux
2023-08-27 12:49:20 -06:00
Mark Thom
3bfed50d81 Merge pull request #1979 from triska/normalize_space
ENHANCED: rudimentary implementation of normalize_space
2023-08-27 12:48:48 -06:00
Adrián Arroyo Calle
4523bb5b81 32 bit CI for Linux 2023-08-27 19:25:54 +02:00
Markus Triska
75aec69de1 replace adjacent whitespace characters with a single SPACE character 2023-08-27 13:01:13 +02:00
Markus Triska
9b96735615 ENHANCED: rudimentary implementation of normalize_space
This removes leading and trailing whitespace from the text. Whitespace
within the string is not yet considered.
2023-08-27 09:56:30 +02:00
Mark Thom
f74d74fe6e Merge pull request #1972 from rujialiu/32-bit-support
32-bit system support #615 #1509 (WIP)
2023-08-25 10:51:15 -06:00
Nicolas Luck
77394ba914 Remove debug println!s 2023-08-24 19:15:41 +02:00
Nicolas Luck
d13173942d Cargo feature "multi_thread" for thread-local ATOM_TABLE_BUF_BASE 2023-08-24 19:13:11 +02:00
Nicolas Luck
afbadd9ea2 Revert "Enable multiple Machines per process by having ATOM_TABLE_BUF_BASE always be thread_local, not only in cfg(test) mode."
This reverts commit bfb3164a0d.
2023-08-24 19:13:11 +02:00
Nicolas Luck
c25888288a Fix parsing of floats 2023-08-24 18:10:47 +02:00
Rujia Liu
4fd059be5f 32-bit system support, addressing all (at most) 4GB addresses of RAM. 2023-08-24 20:05:40 +08:00
Nicolas Luck
bfb3164a0d Enable multiple Machines per process by having ATOM_TABLE_BUF_BASE always be thread_local, not only in cfg(test) mode. 2023-08-23 14:36:07 +02:00
Mark Thom
81712f4c82 Merge pull request #1973 from triska/clpz
CLP(ℤ) improvements, notably related to queue handling
2023-08-22 15:04:33 -06:00
Nicolas Luck
7e97f16f41 Fix list result parsing 2023-08-22 22:46:00 +02:00
Markus Triska
98086de77e attach more propagators before starting propagation
This prevents repeated triggering of already attached propagators
while new propagators are being attached to involved variables.
2023-08-22 21:52:55 +02:00
Markus Triska
24456e9703 remove optional (+)/1 prefix in get_atts/2 and put_atts/2 calls
The (+)/1 prefix in get_atts/2 at line 4219 by itself already causes a
greater than 15% slowdown for the benchmark shown in #1730:

    ?- N #= 2^14,
       time(((between(1, N, _),
              X #\= Y,
              false)
            ; true)).

The performance impact is not a good reason to remove the optional
(+)/1 prefix! Performance issues should be addressed at the root, in
this case get_atts/2 (#1962). We should never manually work around
performance issues in built-in predicates.

In contrast, readability is a good argument, and I find the calls
slightly easier to read without the optional (+)/1 prefix.

The prefix is now consistently omitted when possible.
2023-08-22 21:52:55 +02:00
Markus Triska
7f024f3b8d use pneq/2 2023-08-22 21:52:55 +02:00
Markus Triska
67c1b171c7 enforce same queue in more constraints 2023-08-22 21:52:55 +02:00
Markus Triska
04fbb0c1ce append the entire queues instead of inserting each element individually 2023-08-22 21:52:55 +02:00
Markus Triska
327423ab84 adapt query to Scryer Prolog 2023-08-21 21:19:29 +02:00
Markus Triska
20cfffdff5 update answers 2023-08-21 21:19:29 +02:00
Markus Triska
d8e126044f use can_be/2 2023-08-21 21:19:29 +02:00
Mark Thom
61f975ea18 Merge pull request #1967 from rujialiu/optional-features
Allow users to disable optional features
2023-08-21 11:42:03 -06:00
Rujia Liu
25d4950216 Allow users to disable optional features. Needed for wasm32 support (see #615). 2023-08-21 10:01:24 +08:00
Mark Thom
5aa1521819 Merge pull request #1968 from rujialiu/atom-64bit
Make Atom 64-bit regardless of architecture
2023-08-20 11:50:58 -06:00
Mark Thom
dd030fa18b Merge pull request #1970 from triska/crrl
switch to using crrl for scalar multiplication on Curve25519
2023-08-20 11:24:37 -06:00
Markus Triska
013df58fea ENHANCED: more extensive type checking in curve25519_scalar_mult/3 2023-08-20 14:43:14 +02:00
Markus Triska
745ddc2c87 switch to using crrl for scalar multiplication on Curve25519
This is to facilitate WASM compilation as currently worked on
by @rujialiu in #615. Many thanks, and many thanks to @pornin
for crrl which makes this possible!
2023-08-20 14:43:14 +02:00
Rujia Liu
f6d3b2f896 Make Atom 64-bit regardless of architecture 2023-08-20 19:43:13 +08:00
Mark Thom
7da321ab4f Merge pull request #1964 from triska/master
use newly available double_quotes/1 write option in portray_clause_//1
2023-08-17 15:18:25 -06:00
Markus Triska
92fdc7e380 use newly available double_quotes/1 write option in portray_clause_//1 2023-08-17 23:05:21 +02:00
Mark Thom
2e811de0f5 Merge pull request #1963 from triska/master
ENHANCED: domain error in zcompare/3 (#1723)
2023-08-14 12:18:45 -06:00
Markus Triska
f02cd0ad3c ENHANCED: domain error in zcompare/3 (#1723) 2023-08-14 17:54:18 +02:00
Mark Thom
a36df33a67 Merge pull request #1961 from triska/succ
ADDED: succ/2, part of the Prologue for Prolog
2023-08-12 14:35:21 -06:00
Markus Triska
4a6bf5fd5f reorder tests, per https://github.com/mthom/scryer-prolog/pull/1961#pullrequestreview-1574380588 2023-08-11 23:41:54 +02:00
Markus Triska
26c0b4fc75 ADDED: succ/2, part of the Prologue for Prolog
Specification:

   https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ
2023-08-11 22:46:46 +02:00
Fayeed Pawaskar
ce1c8aac4c Fixed libffi dep 2023-08-08 16:22:08 +05:30
Fayeed Pawaskar
72ceceb7ae Updated hyper to 1.0.0-rc.4 2023-08-08 16:20:49 +05:30
Nicolas Luck
cf63b588bc Ignore stress test because it fails on windows 2023-08-07 18:41:08 +02:00
Nicolas Luck
4e8f7f0a1b Remove unused toplevel predicate 2023-08-07 18:38:34 +02:00
Nicolas Luck
579816a04f Use new double_quotes write-option 2023-08-07 18:29:05 +02:00
Nicolas Luck
cc04872933 Merge branch 'master' into library-use-case 2023-08-07 16:42:48 +02:00
Mark
fad363e64a shed CodeIndex for control predicates in disjuncts.rs (#1791) 2023-08-06 01:26:01 -06:00
Mark
094cf2ac5d retract discontiguous non-multifile predicates between consultations (#1202, #1058, #1585) 2023-08-05 17:42:33 -06:00
Mark Thom
cc82727d20 Merge pull request #1950 from triska/chars_si
ENHANCED: more efficient chars_si/1, using specialized predicates of Scryer
2023-08-04 15:25:42 -06:00
Markus Triska
924750f826 ENHANCED: more efficient chars_si/1, using specialized predicates of Scryer
Source:

    https://github.com/mthom/scryer-prolog/issues/1947#issuecomment-1665113488
2023-08-04 21:18:37 +02:00
Mark Thom
ffbf630b5c Merge pull request #1948 from triska/chars_si
add character_si/1 and use it to correct chars_si/1
2023-08-03 18:34:19 -06:00
Markus Triska
8073a4ba87 add character_si/1 and use it to correct chars_si/1
This addresses #1947.
2023-08-03 22:27:13 +02:00
Nicolas Luck
48a4835819 Merge branch 'master' into library-use-case
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/bin/scryer-prolog.rs
#	src/loader.pl
#	src/machine/mock_wam.rs
#	src/machine/mod.rs
#	src/machine/system_calls.rs
2023-08-03 20:16:32 +02:00
Nicolas Luck
3cf3c0ea99 Integration stress test showing Machine blocking on query 2023-08-03 19:51:12 +02:00
Nicolas Luck
ac61055d43 Remove some unused code from lib_toplevel.pl 2023-08-03 17:41:20 +02:00
Joshua Parkin
65eb93793c dont spawn a runtime in machine; inherit from outside with runtime::handle::Current 2023-08-03 16:22:03 +01:00
Mark
ec450fc567 allocate negator results in arena (#1898) 2023-08-02 19:50:36 -06:00
Mark Thom
2c05ebbded Merge pull request #1943 from triska/dead_skeleton
FIXED: do not attach constraint if the propagator is already entailed and killed
2023-08-02 16:32:27 -06:00
Markus Triska
0ddda0a864 FIXED: do not attach constraint if the propagator is already entailed and killed
Example:

    ?- A#=A//A#==>B,A-B=1-1.
       A = 1, B = 1.

This addresses #1941.
2023-08-03 00:26:40 +02:00
Nicolas Luck
3ff02da314 Deactivate some debugging outputs 2023-08-02 16:25:53 +02:00
Nicolas Luck
df048a4f42 Switch back to run_input_once and use duplicated write_eqs/2 without any input handling 2023-08-02 14:52:49 +02:00
Nicolas Luck
21c36880f1 Fix build 2023-08-02 14:51:41 +02:00
Mark Thom
02328d818c Merge pull request #1938 from triska/remove_auxiliary_constraints
ENHANCED: forget auxiliary constraints set up by the propagator for multiplication
2023-07-31 14:52:34 -06:00
Mark Thom
0f55ba7218 Merge pull request #1939 from triska/oncology_trial_design
better wording, applying the feedback of @dcnorris. Thank you a lot!
2023-07-31 14:52:21 -06:00
Markus Triska
1c089a2bbb better wording, applying the feedback from @dcnorris. Thank you a lot! 2023-07-31 22:07:13 +02:00
Markus Triska
54a887cdc3 ENHANCED: forget auxiliary constraints set up by the propagator for multiplication
This addresses the issue raised in https://github.com/mthom/scryer-prolog/discussions/1937.
2023-07-31 21:57:25 +02:00
Mark Thom
ca28c76e52 Merge pull request #1929 from Skgland/master
detect and prevent concurrent AtomTable use
2023-07-29 10:52:36 -06:00
Bennet Bleßmann
a70157003b fix spelling 2023-07-29 13:11:00 +02:00
Bennet Bleßmann
6aa3c7d5d6 handle atom table resize
* bumping serial_test dev-dependency due to broken should_panic handling in old version
2023-07-29 11:22:25 +02:00
Bennet Bleßmann
4ef8c5c47d detect and prevent² concurrent AtomTable use
²in the case of `#[cfg(not(test))]` there is still a toctou race as I am not sufficently familiar with Atomics
2023-07-27 23:37:03 +02:00
Mark Thom
31d17f135a Merge pull request #1927 from triska/ascii_punctuation
FIXED: correct handling of ascii_punctuation in char_type/2 (#1926)
2023-07-27 14:51:01 -06:00
Markus Triska
03f7b01109 FIXED: correct handling of ascii_punctuation in char_type/2 (#1926) 2023-07-27 20:22:05 +02:00
Nicolas Luck
c2658dc6da Try triska's toplevel and add some debugging println!s. 2023-07-27 14:46:00 +02:00
Nicolas Luck
30dac8ea41 HashSet -> BTreeSet: Make parsing or results and thus tests deterministic. Add comments. 2023-07-27 12:06:03 +02:00
Nicolas Luck
0d28404aad Add special case when parsing 2023-07-27 11:50:38 +02:00
Nicolas Luck
2f99bb025c Add consult that works with streams / strings in library use-case 2023-07-27 11:41:52 +02:00
Mark
bff48e7c7f simplify and correct prefix-bracket spacing in heap_print.rs (#1914, #1918) 2023-07-26 09:32:54 -06:00
Mark
3b67ffa814 overwrite code indices of dynamic_undefined predicates (dynamic, multifile, discontiguous) on export 2023-07-25 13:48:34 -06:00
Mark Thom
49b4e4cbcb Merge pull request #1907 from coasys/dashu
Replace rug with dashu
2023-07-25 11:35:10 -06:00
Mark
287c308bc3 track the parent operator of the current operator in heap_print to emit space if necessary (#1906) 2023-07-24 20:05:28 -06:00
Mark
af44d91568 Merge branch 'dashu' of https://github.com/coasys/scryer-prolog into coasys-dashu 2023-07-24 11:47:57 -06:00
Fayeed Pawaskar
40b6890c54 updated cargo to use git 2023-07-24 19:11:41 +05:30
Fayeed Pawaskar
7248425a76 Fixed warnings 2023-07-24 12:41:56 +05:30
Fayeed Pawaskar
1dcc1ca524 Fixed stackoverflow error 2023-07-24 12:19:41 +05:30
Fayeed Pawaskar
0e17d6acd7 remove rug completely 2023-07-24 10:12:22 +05:30
Fayeed Pawaskar
c89217903a fix all the move errors 2023-07-24 10:12:14 +05:30
Mark
762e6d3ba4 pop both pending redirections in format_bar_separator_op when max depth exceeded (#1903) 2023-07-23 15:02:27 -06:00
Mark
e9ae80e250 fix list abbreviation (#1901) 2023-07-23 14:43:13 -06:00
Mark
fd7f24e265 remove EMIT_NEWLINE (#1900) 2023-07-22 21:42:40 -06:00
Mark
24450a8827 use ExitCode when halting so Drop is called, close terminal stream in rustyline Drop 2023-07-22 19:06:13 -06:00
Mark Thom
57e8ed65b0 Merge pull request #1050 from pmoura/add_float_integer_part_and_float_fractional_part_standard_functions
WIP: Add float_integer_part/1 and float_fractional_part/1 standard arithmetic functions
2023-07-22 13:48:16 -06:00
Mark
3f819e2dfd additional write fixes, use rustyline 12.0.0 (#1876, #1901) 2023-07-22 11:53:09 -06:00
Mark
9a7862c322 correct max_depth option (#1876) 2023-07-22 11:11:23 -06:00
Mark Thom
92c77cdff5 Merge pull request #1899 from triska/master
remove another !/0 which is now no longer necessary due to improved indexing
2023-07-21 23:26:20 -06:00
Markus Triska
554e956ef5 remove another !/0 which is now no longer necessary due to improved indexing 2023-07-22 06:52:29 +02:00
Nicolas Luck
9fd6e18d59 Dedupe machine results 2023-07-22 00:32:24 +02:00
Nicolas Luck
d8a9475460 Add missing list_last_item to lib_toplevel.pl and increase MaxDepth of write_eq to avoid truncation of results 2023-07-22 00:31:49 +02:00
Mark
60d9d01a55 Merge branch 'add_float_integer_part_and_float_fractional_part_standard_functions' of https://github.com/pmoura/scryer-prolog into pmoura-add_float_integer_part_and_float_fractional_part_standard_functions 2023-07-21 15:35:28 -06:00
Mark
cb79552dd0 correct max_depth option (#1876) 2023-07-21 15:05:27 -06:00
Mark
f310ff24a5 remove now unnecessary cut in lists.pl 2023-07-21 11:35:57 -06:00
Nicolas Luck
b1963864d2 Explicitly dereference pointer to avoid calling neg() on reference 2023-07-21 17:07:40 +02:00
Nicolas Luck
9e85be11fe Fix result parsing for complex string results 2023-07-21 14:35:44 +02:00
Fayeed Pawaskar
b4e7000eb2 Fixed missing functionality in dashu with their methods still has some issue with move 2023-07-21 14:21:32 +05:30
Nicolas Luck
0b833bd2f3 Add missing write_goal/3 to lib_toplevel.pl 2023-07-21 00:23:35 +02:00
Nicolas Luck
7c93450aa7 type QueryResult = Result<QueryResolution, String> 2023-07-20 22:31:20 +02:00
Mark
e529e7ba21 improve goal expansion and (',') interpretation error handling 2023-07-20 14:27:10 -06:00
Nicolas Luck
cae32d6a00 Error handling 2023-07-20 22:23:51 +02:00
Nicolas Luck
836f6c1d5b Don't panic when parsing results fails 2023-07-20 21:34:43 +02:00
Mark
1697cd5c7f add log10, hyperbolic tan and inverse hyperbolic tan functions (#1898) 2023-07-20 12:33:51 -06:00
Mark
dcd7360b17 add EMIT_NEWLINE to add newlines to readline input only after query terms begin to be read (#1074, #1897) 2023-07-20 09:39:06 -06:00
Mark
4fd247f881 check for unexpected EOF in get_to_eof (#1897) 2023-07-19 17:13:47 -06:00
Mark
85bc544fb9 dereference TermWriteResult variables sooner in read_term_body (#1894) 2023-07-18 15:39:51 -06:00
Mark
14646074be remove failing append choicepoint in atom_concat/3 special case (#1893) 2023-07-18 14:44:02 -06:00
Mark Thom
1ba040c24d Merge pull request #1885 from mthom/setof_bagof_fixes
Fix group_by_variants/4 and keysort in setof/3
2023-07-18 12:35:10 -06:00
Mark
56f6772422 call write_read_term_options if read_term_from_chars/3 succeeds by unifying Term to end_of_file (#1892) 2023-07-18 12:15:20 -06:00
Mark
db43d461b9 catch errors thrown from tabling Worker (#1526, #1888) 2023-07-18 12:10:27 -06:00
Mark
42a50474da remove read/{1,2} as a builtin, write read options upon EOF, throw better domain errors in parse_read_term_options/2 2023-07-17 16:45:03 -06:00
Mark
cf367024fd add specialized EOF handling for user input (#1892) 2023-07-17 14:38:26 -06:00
Nicolas Luck
644559b7f7 Add back newline at end of toplevel.pl 2023-07-17 21:52:17 +02:00
Nicolas Luck
bb95ed3ad0 Add back all needed predicates to lib_toplevel.pl 2023-07-17 21:48:05 +02:00
Nicolas Luck
3947390877 Use lib constructor in lib tests 2023-07-17 21:47:43 +02:00
Nicolas Luck
e7f1e32ee3 fmt machine/parsed_results.rs 2023-07-17 21:35:00 +02:00
Nicolas Luck
5f8cc3c64b WIP: refactor to generalize Machine::run_top_level() 2023-07-17 21:34:26 +02:00
Mark
67d198ac77 Merge branch 'read_term_eof_changes' 2023-07-17 13:22:51 -06:00
Mark
a154a34f87 omit anonymous variables from read_term variable_names and singletons lists 2023-07-17 13:20:10 -06:00
Mark
86c90d77dd do a better job handling EOF in read_term (#1887) 2023-07-17 13:19:30 -06:00
Mark
4e1a4dae6c print strings in tails of lists (#1890) 2023-07-17 11:38:50 -06:00
Fayeed Pawaskar
cf345d8174 wip dashu move 2023-07-17 20:40:41 +05:30
Mark Thom
a18da368a1 Merge pull request #1891 from triska/initialization_goals
ENHANCED: use newly available read_term_from_chars/3 for better errors
2023-07-16 10:26:13 -06:00
Markus Triska
5d3295c40c ENHANCED: use newly available read_term_from_chars/3 for better errors
Examples, previously:

    $ scryer-prolog -g "member(X,Ls"
    ?-
    $ scryer-prolog -g "member(X,Ls)"
    member(_542,_543) causes: error(existence_error(procedure,member/2),member/2)
    ?-

Now:

    $ scryer-prolog -g "member(X,Ls"
    "member(X,Ls" cannot be read: error(syntax_error(incomplete_reduction),read_term_from_chars/3:0)
    $ scryer-prolog -g "member(X,Ls)"
    member(X,Ls) causes: error(existence_error(procedure,member/2),member/2)
    ?-

This also addresses #1185.
2023-07-16 14:16:07 +02:00
Mark
de10ccfdee re-factor options handling of read_term into read_term_body (#1887) 2023-07-15 21:52:54 -06:00
Mark
65a8ce8e22 generalize simple goal detection to fix call/N test failures in logtalk test suite 2023-07-15 19:29:06 -06:00
Mark
5a7da721cd add read_term_from_chars/3 (#637) 2023-07-15 11:20:20 -06:00
Mark
b234ef7ea3 use double_quotes in write_error (#1886) 2023-07-15 10:58:25 -06:00
Mark
617c961f88 add is_inbuilt check to err_on_builtin_overwrite (#1872) 2023-07-15 10:44:00 -06:00
Mark
e95355e56e eliminate call_with_inference_limit/3 leaks (#1300) 2023-07-15 10:22:23 -06:00
Mark
ff5e9a793b add unknown flag to set_prolog_flag and current_prolog_flag 2023-07-14 19:10:10 -06:00
Mark
101d0548db fix group_by_variants/4 and keysort in setof/3 (#1440, #1856) 2023-07-14 18:52:29 -06:00
Mark
b6a81c51ab add (:-)/1 and (:-)/2 to ClauseType::is_inbuilt (#1872) 2023-07-14 12:44:28 -06:00
Mark
ba2cd43144 fix assert(a|z)/1 errors 2023-07-13 17:12:17 -06:00
Mark Thom
bd720b49f3 Merge pull request #1884 from triska/countall
ADDED: countall/2, for compatibility with GNU Prolog.
2023-07-13 16:09:29 -06:00
Markus Triska
9590d5200c ADDED: countall/2, for compatibility with GNU Prolog.
Example:

    ?- countall(member(X, "abc"), N).
       N = 3.
2023-07-13 23:08:13 +02:00
Mark
12f890e4a2 throw permission_error in compile_assert when attempting to assert a built-in (#1872) 2023-07-13 15:03:26 -06:00
Mark
a9cb826bf3 arith_eval_by_metacall may receive a stack variable 2023-07-13 13:58:51 -06:00
Mark
4163cb038d correct peek_code/2, don't set stream position in peek functions 2023-07-13 13:37:34 -06:00
Mark
b051f39145 correct peek_byte/2 bugs (#1882) 2023-07-13 12:23:20 -06:00
Mark
cfc49243c8 improve ground/1 performance (#1389) 2023-07-12 18:11:56 -06:00
Mark
29430ec88b fix peek_byte/2 crash (#1882) 2023-07-12 16:34:11 -06:00
Mark Thom
d520046a4f Merge pull request #1878 from mthom/lookahead_indexing
use lookahead to skip inapplicable clauses (#1028, #1502)
2023-07-12 16:21:06 -06:00
Markus Triska
814ce2d672 ENHANCED: improved determinism of member/2
Example:

    ?- member(X, "abc").
    %@    X = a
    %@ ;  X = b
    %@ ;  X = c.

This addresses #750.
2023-07-12 14:39:08 -06:00
Mark
4fd37335f5 use lookahead to skip inapplicable clauses (#1028, #1502) 2023-07-12 14:39:02 -06:00
Mark
1791bd8626 remove unsafe unwrap in put_char (#1881) 2023-07-12 14:24:20 -06:00
Mark
3f5dbc1680 emit stream aliases as permission error culprits whenever possible 2023-07-12 12:17:06 -06:00
Mark
44052cb373 Revert "Allow comparisons with stream terms"
This reverts commit 076a75d138.
2023-07-12 11:44:45 -06:00
Mark
8c33da11ce Revert "add stream alias check to atom/1 (#1855)"
This reverts commit b746a8f9ab.
2023-07-12 11:44:44 -06:00
Mark
ab80c84714 Revert "add stream alias processing to atom_chars/2, atom_codes/2"
This reverts commit 811ff65209.
2023-07-12 11:44:41 -06:00
Nicolas Luck
c0dd94c8a3 Add test for programatic queries 2023-07-12 11:57:53 +02:00
Nicolas Luck
f65675836c Fix build warnings 2023-07-12 11:38:53 +02:00
Nicolas Luck
f324c9591d Refactor result parsing to idiomatic Rust and extract into parsed_results.rs 2023-07-12 10:34:07 +02:00
Nicolas Luck
3347f830c7 Remove debug println!s 2023-07-12 01:26:54 +02:00
Nicolas Luck
568abef5b8 Parsed QueryResult 2023-07-12 01:24:39 +02:00
Nicolas Luck
703efdb22d Make run_input_once/0 match and print all results 2023-07-12 00:03:47 +02:00
Mark
bb420e9347 use indexing functions to set num_cells in allocate_and_frame/or_frame (#1877) 2023-07-11 13:43:34 -06:00
Nicolas Luck
2f45f0cfed Add convenience methods Machine::load_module_string() and Machine::run_query() 2023-07-11 14:51:58 +02:00
Nicolas Luck
112d398175 Add Machine::run_input_once() which reads one goal from user input and runs it 2023-07-11 14:24:30 +02:00
Nicolas Luck
95b31146b5 Add Machine::set_user_input(&mut self, input: String) and get_user_output() -> String. Make read_term_from_user_input() handle Stream::Byte. 2023-07-11 14:22:27 +02:00
Mark
55a1f8d3da clean commented code from disjuncts.rs 2023-07-10 10:32:15 -06:00
Mark
fba7790637 remove errant debug_hook from read_and_match 2023-07-09 10:30:30 -06:00
Markus Triska
918dfca409 DOC: new section on applications of Scryer Prolog
This addresses an important aspect of #1777.
2023-07-09 10:29:53 -06:00
Markus Triska
d18f128a3c correct \\ to \, addressing #1865 2023-07-09 10:29:53 -06:00
Mark
c8b9059289 refine EOF handling more (#1873) 2023-07-09 10:29:47 -06:00
Mark
b8a6882a27 refine EOF handling 2023-07-08 22:25:30 -06:00
Mark
fb8e3071f2 follow EOF action after open_parsing_stream in get_char if stream at EOF 2023-07-08 19:27:32 -06:00
Mark
067b5998ee clarify EOF error across stream types and predicates (#1867, #1870) 2023-07-08 13:38:52 -06:00
Mark Thom
2e26f37f5e Merge pull request #1869 from triska/master
print version more readably, addressing #1868
2023-07-08 01:24:04 -06:00
Markus Triska
6525c1f543 print version more readably, addressing #1868 2023-07-08 08:19:05 +02:00
Mark
4db0b385f3 treat unexpected EOF as incomplete reduction in bracketed_comment 2023-07-07 13:04:27 -06:00
Mark
b7f77d1747 interpret '\u{0}' as end_of_file in get_char/1 2023-07-07 11:05:44 -06:00
Mark
811ff65209 add stream alias processing to atom_chars/2, atom_codes/2 2023-07-07 10:38:05 -06:00
Mark Thom
fd70d8975b Merge pull request #1832 from aarroyoc/http-fixes
Multiple fixes for http libraries
2023-07-06 16:30:56 -06:00
Mark
b746a8f9ab add stream alias check to atom/1 (#1855) 2023-07-06 11:38:12 -06:00
Mark
483e4568a2 add scc_block to MachineState to avoid SCC cleanup terms being deallocated too early (#1427) 2023-07-06 11:20:49 -06:00
Mark
9ff1b660f1 correct heap_print.rs tests 2023-07-05 18:11:09 -06:00
Mark
5ffdd2d91a shrink scope of control_entry_point catch, add CutPoint tag to printer 2023-07-05 14:50:49 -06:00
Mark Thom
5b81bee941 Merge pull request #1864 from triska/double_quotes
make double_quotes write option not dependent on double_quotes flag
2023-07-05 13:49:29 -06:00
Markus Triska
3b9b9e75c4 make double_quotes write option not dependent on double_quotes flag
This gives consistent results without depending on another flag.
2023-07-05 21:37:11 +02:00
Mark Thom
faef45fd68 Merge pull request #1862 from mthom/iso_conformity_tests
Revise iso_conformity_tests.pl to remove unnecessary spaces
2023-07-05 10:49:51 -06:00
Mark
b5b45dde9d add missing self.pos to peek_char slices (#1726) 2023-07-04 17:44:27 -06:00
Mark
5ab087bc1e revise iso_conformity_tests.pl in response to new ambiguity check of #1860 2023-07-04 16:12:03 -06:00
Mark
7683367c0e throw lexer errors from devour_whitespace (#1778) 2023-07-04 16:09:54 -06:00
Mark Thom
d2db66b9f7 Merge pull request #1861 from aarroyoc/fix-1855
Allow comparisons with stream terms
2023-07-04 15:11:59 -06:00
Mark
c58d8804a1 widen CharReader buffer (#1859) 2023-07-04 15:08:46 -06:00
Mark
5d09449c95 widen CharReader buffer (#1859) 2023-07-04 11:22:22 -06:00
Adrián Arroyo Calle
076a75d138 Allow comparisons with stream terms 2023-07-04 17:33:48 +02:00
Mark Thom
7f69ac3f4a Merge pull request #1857 from triska/master
advertise newly achieved strong syntactic conformance: all current tests pass
2023-07-03 14:05:16 -06:00
Markus Triska
7f159a7ed2 advertise newly achieved strong syntactic conformance: all current tests pass
This addresses an important aspect of #1777.
2023-07-03 22:04:26 +02:00
Mark Thom
42274ef3ae Merge pull request #1850 from mthom/iso-conformity-tests
Automate ISO syntax conformity tests
2023-07-03 13:53:41 -06:00
Mark
ab893be418 update tests 2023-07-03 13:18:53 -06:00
Mark
f5e7573bd6 correct tests #171 and #300 2023-07-03 12:09:26 -06:00
Mark
9cdad087ef add double_quotes write option for printing to strings, enable it at toplevel 2023-07-03 12:09:05 -06:00
Mark
e36f96fd47 correct ISO conformity test #185 2023-07-03 11:34:41 -06:00
Mark
cb25a90250 add iso-conformity-tests.pl to test suite 2023-07-02 11:10:33 -06:00
Mark
38a9d23174 correct initialization_goals misnomer in iso-conformity-tests.pl 2023-07-02 11:10:33 -06:00
Mark
521118265a make setup of test_166_167 pass 2023-07-02 11:10:33 -06:00
Mark
a09306c585 check ambiguity of "'" against tail if atom token is about to be quoted 2023-07-02 11:10:33 -06:00
Mark
8140ff9154 always print a space between prefix operator and its operand 2023-07-02 11:10:33 -06:00
Mark
3cbe78cb9b correct tests 259 and 304 of tests-pl/iso-conformity-tests.pl 2023-07-02 11:10:33 -06:00
Mark
699afb2c00 introduce tests-pl/iso-conformity-tests.pl 2023-07-02 11:10:33 -06:00
Mark
d079a18459 removing residual debugging comments from format.pl 2023-07-02 11:10:25 -06:00
Mark
b0566e4150 use lexer to detect remaining layout in parse_number_from_string (#1773) 2023-06-30 17:18:10 -06:00
Mark Thom
c38a26e6cd Merge pull request #1854 from triska/needs_bracketing
remove now unneeded check
2023-06-30 15:43:45 -06:00
Markus Triska
31030738a4 remove now unneeded check 2023-06-30 22:14:00 +02:00
Mark
caf84a259e check that F in needs_bracketing/2 is an atom 2023-06-30 13:45:45 -06:00
Mark
1620824d3a do not enclose '(' as atom in brackets (#1487) 2023-06-30 12:06:07 -06:00
Mark Thom
1d2f5053d6 Merge pull request #1852 from triska/needs_bracketing
Improvements to needs_bracketing/2
2023-06-30 11:13:24 -06:00
Markus Triska
42282c6e6e remove unneeded case: only operator definitions should count, not quoting 2023-06-30 18:03:21 +02:00
Markus Triska
a3f8ddd24a remove subsumed case: F == Value means Arity =:= 0, now considered above 2023-06-30 18:02:43 +02:00
Markus Triska
bfe808a779 shorten needs_bracketing/2 2023-06-30 18:01:54 +02:00
Markus Triska
28065b0565 constrain bracketing to operators with pertaining arity
Example:

    ?- X = -->(a,b,c).
       X = -->(a,b,c).
2023-06-30 18:01:17 +02:00
Mark Thom
4953cfd10e Merge pull request #1851 from triska/operator_bracketing
bracket all operators that are direct operands of (=)/2
2023-06-30 00:26:18 -06:00
Markus Triska
db972de40c bracket all operators that are direct operands of (=)/2
This addresses #804.
2023-06-30 08:03:38 +02:00
Adrián Arroyo Calle
330e9ba4ef Multiple fixes for http libraries
* use reqwest for http_open (still uses Hyper underneath)
* use Hyper 1.0.0-rc3 for server
* Modify all internal handling of server
2023-06-29 23:43:37 +02:00
Mark
bb09de1805 fix ReadlineStream peek_char using CharReader 2023-06-29 14:58:15 -06:00
Mark
a6a0cef9fc read the cell written to by mark_var when needed in compile_is (#1846) 2023-06-29 12:58:15 -06:00
Mark
c36bd4dc07 introduce CutPoint heap tag so that they can be offset by call_continuation/1 2023-06-29 12:14:15 -06:00
Mark Thom
83f352b95e Merge pull request #1849 from triska/showterm
remove unneeded single quotes
2023-06-29 12:11:12 -06:00
Markus Triska
c84a5c3282 remove unneeded single quotes 2023-06-29 19:25:23 +02:00
Mark
58af615dd4 correct and generalize current_predicate/1 2023-06-28 17:31:43 -06:00
Mark
c4b13a2176 unify stack variables to streams in unify_constant (#1845) 2023-06-27 17:35:10 -06:00
Mark
039fffb339 better detect syntax errors in lexer.rs (#1771) 2023-06-27 16:39:20 -06:00
Mark Thom
8613513b9c Merge pull request #1844 from triska/copy_term_nat
use copy_term_nat/2
2023-06-27 15:26:33 -06:00
Markus Triska
ceb276b249 use copy_term_nat/2 2023-06-27 22:37:23 +02:00
Mark
16f281e3d1 enable unification of streams to alias atoms (#1823) 2023-06-27 12:23:40 -06:00
Mark
b593fffc7d support module resolution in current_predicate/1 (#1817) 2023-06-27 11:08:29 -06:00
Mark
ce890799bc fix builtin_predicate (#1819) 2023-06-27 10:41:15 -06:00
Mark
aa65287c3b remove tabling attributes in each module's attribute_goals//1 (#1825) 2023-06-27 10:31:10 -06:00
Mark
a6522d6317 properly account for partial string offsets in '$skip_max_list' (#1827) 2023-06-26 16:36:04 -06:00
Mark
0b45d42912 mark chunk boundary at beginning of disjunct in disjuncts.rs (#1843) 2023-06-24 17:18:00 -06:00
Mark
d9829a3606 fix string incompleteness (#1828) 2023-06-24 14:12:08 -06:00
Mark Thom
59766e2db4 Merge pull request #1842 from infogulch/release-on-tag
Fix tags trigger; bump MSRV to 1.65
2023-06-24 13:13:07 -06:00
infogulch
e52a4fbfc0 Bump msrv to 1.65 due to bumping rug to 1.19
https://gitlab.com/tspiteri/rug#version-1190-news-2023-01-06
2023-06-24 13:21:42 -05:00
infogulch
c05afb4705 Fix tags trigger 2023-06-24 13:05:57 -05:00
Mark
9f209dadd9 fix branch subsumption bug (#1840, #1841) 2023-06-24 10:59:29 -06:00
Mark Thom
2ec45b7413 Merge pull request #1838 from triska/get_line_to_chars
MODIFIED: read_line_to_chars/3 is now called get_line_to_chars/3
2023-06-24 09:19:22 -06:00
Mark
bf581879e6 update README 2023-06-24 09:11:30 -06:00
Markus Triska
9bc3757a9e another case of "read" --> "get", for an only internally used predicate 2023-06-24 11:48:28 +02:00
Markus Triska
18d0a74f23 MODIFIED: read_line_to_chars/3 is now called get_line_to_chars/3
This is for consistency with other I/O predicates, where "read" always
indicates Prolog terms. Please adjust your programs accordingly.
2023-06-24 11:47:32 +02:00
Mark
7a188744da correct code_walker.rs in light of compilation improvements 2023-06-23 16:53:18 -06:00
Mark
7f45ac3f7a Merge branch 'compiling_disj' 2023-06-23 15:45:04 -06:00
Mark
612861e010 correct reversions after rebase 2023-06-23 14:32:37 -06:00
Mark
fcae0d9fcf polish perm free list management 2023-06-23 14:11:31 -06:00
infogulch
f446939770 Add steps to publish binaries when releases are tagged 2023-06-23 14:11:31 -06:00
Mark
92853a6a12 free local cut variables after cut 2023-06-23 14:11:31 -06:00
Mark
4ad113a6f8 mark is/2 allocated permanent variables as safe, add CompareNumber terms to ClauseType::is_inlined 2023-06-23 14:11:31 -06:00
dependabot[bot]
89ed1aa8de Bump openssl from 0.10.48 to 0.10.55
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.48 to 0.10.55.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.55)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-23 14:11:31 -06:00
Mark
d7f5675727 improve call/N implementation (#1829) 2023-06-23 14:11:31 -06:00
Mark
4d982d22c1 set_local_value does not make values safe (#1812) 2023-06-23 14:11:31 -06:00
Mark
5ed1802f0f read set_value args from temp regs of put_unsafe_value (#1812) 2023-06-23 14:11:31 -06:00
Markus Triska
2716381e7b FIXED: correct dereferencing in atom_codes/2 and number_codes/2.
This addresses #1818.

Test case:

    run :-
	    length(Ls, L),
	    portray_clause(L),
	    maplist(=(X), Ls),
	    X = Y,
	    Y = 12,
	    atom_codes(_, Ls),
	    false.
2023-06-23 14:11:31 -06:00
Adrián Arroyo Calle
c5c83d724a Rename INDEX.md to INDEX.dj and add banner about Scryer Prolog Meetup 2023-06-23 14:11:31 -06:00
Mark
749dedf477 read from machine stack in stackful pre-order iterator (#1812) 2023-06-23 14:11:31 -06:00
notoria
911c49c43f Compute correctly the domain of the remainder 2023-06-23 14:11:31 -06:00
notoria
770a682d8b Don't add variable
?- Z #= 0, Z #= X mod Y.
   Z = 0, clpz:(_A*Y#=X), clpz:(Y in inf.. -1\/1..sup) % Unexpected.

The expected result:
   Z = 0, clpz:(X mod Y#=0), clpz:(Y in inf.. -1\/1..sup).
2023-06-23 14:11:31 -06:00
notoria
73ca37ecca Remove and move comments 2023-06-23 14:11:31 -06:00
Mark
e0f49e8f43 optionally read from machine stack in stackful pre-order iterator (#1812) 2023-06-23 14:11:31 -06:00
Mark
dae34b6009 affirm integers as rational/1 (#1810) 2023-06-23 14:11:31 -06:00
Adrián Arroyo Calle
5850125d97 Update select crate to 0.6.0 and remove warning 2023-06-23 14:11:31 -06:00
Markus Triska
97bd778745 FIXED: correctly reset counter in reset_gensym/2 (#1807)
Many thanks to @infradig for detecting this issue and suggesting this
correction!
2023-06-23 14:11:31 -06:00
Markus Triska
43df2e2649 shorten gensym/2 2023-06-23 14:11:31 -06:00
Markus Triska
c2f2623471 extend logic to all control and whitespace characters
This addresses #1802.
2023-06-23 14:11:31 -06:00
Mark
8e4465315f use same logic to print Chars and Atoms (#1804) 2023-06-23 14:11:31 -06:00
Markus Triska
86beb222ae rely on first instantiated argument indexing in the definitions of foldl/N
This allows shorter and more natural definitions.
2023-06-23 14:11:31 -06:00
Markus Triska
5e124ccf44 ENHANCED: allow Roman numerals in strings
Example:

    ?- X = "ↁ".
       X = "ↁ".

This addresses #1790.
2023-06-23 14:11:31 -06:00
Markus Triska
47d4e6d2f9 FIXED: consistent read/write of further control characters, and non-breaking space
Example:

    ?- X = '\xa0\'.
       X = '\xa0\'.

This addresses #1768.
2023-06-23 14:11:31 -06:00
Mark
33f65210ee make tests compatible 2023-06-23 14:11:31 -06:00
Mark
9ea6cb4cab backtrack on emission of unsafe register instructions on internal branches 2023-06-23 14:11:31 -06:00
Mark
0e583d620a implement new disjunction compilation 2023-06-23 14:11:31 -06:00
Mark Thom
b205abe949 remove BuildIf, BuildNot, BuildThen TermIterState variants 2023-06-23 14:11:31 -06:00
Mark Thom
cb59c3003a correct chunk type labeling 2023-06-23 14:11:30 -06:00
Mark Thom
942095baa7 remove GetLevelAndUnify and replace it with GetCutPoint 2023-06-23 14:11:30 -06:00
Mark Thom
097849385e add QueryTerm::ChunkTypeBoundary 2023-06-23 14:11:30 -06:00
Mark Thom
c4783062ff delete ChunkedTerm, chunked iteration 2023-06-23 14:11:30 -06:00
Mark Thom
063cf0c608 new TermIterState variants 2023-06-23 14:11:30 -06:00
Mark Thom
a66d666bed variable classification al a carte 2023-06-23 14:11:22 -06:00
Mark Thom
170818759d add more variable probing, chunk type labeling 2023-06-23 14:11:07 -06:00
Mark Thom
e41d1b319b adapt code generation 2023-06-23 14:11:04 -06:00
Mark Thom
b9c9de5222 add classifications and occurrence counting 2023-06-23 13:54:46 -06:00
Mark Thom
d565f5901b milestone marker for surgery 2023-06-23 13:54:04 -06:00
Mark Thom
46317c3a39 begin adapting the techniques of "Compiling Large Disjunctions" 2023-06-23 13:52:24 -06:00
Mark Thom
bcc5bff376 Merge pull request #1834 from infogulch/ci-publish-releases
Add steps to publish binaries when releases are tagged
2023-06-23 12:01:32 -06:00
infogulch
5244d71570 Add steps to publish binaries when releases are tagged 2023-06-22 23:36:04 -05:00
Mark Thom
9fac289d9a Merge pull request #1833 from mthom/dependabot/cargo/openssl-0.10.55
Bump openssl from 0.10.48 to 0.10.55
2023-06-22 11:30:56 -06:00
dependabot[bot]
de665c05d8 Bump openssl from 0.10.48 to 0.10.55
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.48 to 0.10.55.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.55)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-21 22:54:36 +00:00
Mark
98b0ab3409 improve call/N implementation (#1829) 2023-06-10 17:32:18 -06:00
Mark
3c344b176b set_local_value does not make values safe (#1812) 2023-06-06 00:58:44 -06:00
Mark
6093c2858d read set_value args from temp regs of put_unsafe_value (#1812) 2023-05-29 20:49:54 -06:00
Mark Thom
e06ab1ca1c Merge pull request #1822 from triska/master
FIXED: correct dereferencing in atom_codes/2 and number_codes/2.
2023-05-29 10:15:43 -06:00
Markus Triska
5154314786 FIXED: correct dereferencing in atom_codes/2 and number_codes/2.
This addresses #1818.

Test case:

    run :-
	    length(Ls, L),
	    portray_clause(L),
	    maplist(=(X), Ls),
	    X = Y,
	    Y = 12,
	    atom_codes(_, Ls),
	    false.
2023-05-29 11:43:56 +02:00
Mark Thom
fa07306f09 Merge pull request #1820 from aarroyoc/banner-meetup
Rename INDEX.md to INDEX.dj and add banner about Scryer Prolog Meetup
2023-05-28 16:39:05 -06:00
Adrián Arroyo Calle
07115ce4f5 Rename INDEX.md to INDEX.dj and add banner about Scryer Prolog Meetup 2023-05-29 00:29:53 +02:00
Mark
b656700294 read from machine stack in stackful pre-order iterator (#1812) 2023-05-28 12:59:01 -06:00
Mark Thom
7bc7f0ad06 Merge pull request #1816 from notoria/clpz
Small fixes for `CLP(ℤ)`
2023-05-27 11:07:50 -06:00
notoria
495df8846a Compute correctly the domain of the remainder 2023-05-27 13:47:14 +02:00
notoria
05d48cdcc3 Don't add variable
?- Z #= 0, Z #= X mod Y.
   Z = 0, clpz:(_A*Y#=X), clpz:(Y in inf.. -1\/1..sup) % Unexpected.

The expected result:
   Z = 0, clpz:(X mod Y#=0), clpz:(Y in inf.. -1\/1..sup).
2023-05-27 13:41:04 +02:00
notoria
dc02be4944 Remove and move comments 2023-05-27 13:08:25 +02:00
Mark
462097d956 optionally read from machine stack in stackful pre-order iterator (#1812) 2023-05-26 15:19:07 -06:00
Mark
0e374c2e96 affirm integers as rational/1 (#1810) 2023-05-24 13:58:43 -06:00
Mark Thom
94a1313916 Merge pull request #1809 from aarroyoc/update-select
Update select crate to 0.6.0 and remove warning
2023-05-18 12:31:44 -06:00
Adrián Arroyo Calle
b54a4afad6 Update select crate to 0.6.0 and remove warning 2023-05-17 18:19:19 +02:00
Mark Thom
c71b8e05f0 Merge pull request #1808 from triska/gensym
gensym-related improvement and correction
2023-05-16 15:55:39 -06:00
Markus Triska
021c01dfd0 FIXED: correctly reset counter in reset_gensym/2 (#1807)
Many thanks to @infradig for detecting this issue and suggesting this
correction!
2023-05-16 22:42:57 +02:00
Markus Triska
30f222b837 shorten gensym/2 2023-05-16 22:41:20 +02:00
Mark Thom
f7d9237bb9 Merge pull request #1805 from triska/master
extend logic to all control and whitespace characters
2023-05-14 23:27:49 -06:00
Markus Triska
49addc7b04 extend logic to all control and whitespace characters
This addresses #1802.
2023-05-14 09:25:08 +02:00
Mark
2f9996f9ac use same logic to print Chars and Atoms (#1804) 2023-05-10 00:04:35 -06:00
Mark Thom
c1218fc986 Merge pull request #1801 from triska/foldl
rely on first instantiated argument indexing in the definitions of foldl/N
2023-05-04 21:25:16 -06:00
Mark Thom
57ef706eb0 Merge pull request #1799 from triska/roman_numerals
ENHANCED: allow Roman numerals in strings
2023-05-04 21:25:03 -06:00
Mark Thom
e4b19dc1dd Merge pull request #1800 from triska/nbsp
FIXED: consistent read/write of further control characters, and non-breaking space
2023-05-04 21:24:45 -06:00
Markus Triska
4e60cc46a2 rely on first instantiated argument indexing in the definitions of foldl/N
This allows shorter and more natural definitions.
2023-05-04 00:50:27 +02:00
Markus Triska
d8edf7bfff FIXED: consistent read/write of further control characters, and non-breaking space
Example:

    ?- X = '\xa0\'.
       X = '\xa0\'.

This addresses #1768.
2023-05-03 23:29:22 +02:00
Markus Triska
e951db662d ENHANCED: allow Roman numerals in strings
Example:

    ?- X = "ↁ".
       X = "ↁ".

This addresses #1790.
2023-05-03 22:02:47 +02:00
Mark
c5a3ec3ba8 fix current_predicate/1 (#1761) 2023-04-24 23:23:27 -06:00
Mark Thom
f12a90351a Merge pull request #1794 from aarroyoc/uppercase-2
Fix to_upper/to_lower when string is instantiated
2023-04-23 17:08:21 -06:00
Adrián Arroyo Calle
b162c40007 Fix to_upper/to_lower when string is instantiated 2023-04-23 23:01:29 +02:00
Mark Thom
402100fd52 Merge pull request #1797 from triska/clpb_residuals
remove residual goal for ground BDD
2023-04-23 10:31:40 -06:00
Markus Triska
2a1b8f37ec remove residual goal for ground BDD
Example:

    ?- sat(X).
       X = 1.
2023-04-23 09:23:00 +02:00
Mark
7d2e59ab64 discard CodeIndex literals from unfolded control operators in preprocessor (#1791) 2023-04-22 18:38:50 -06:00
Mark
f35298a227 add and document inlined_instructions/2 to/in diag.pl (#1791) 2023-04-22 18:38:49 -06:00
Mark Thom
198e925430 Merge pull request #1796 from triska/dif_si
ADDED: dif_si/2
2023-04-22 17:21:03 -06:00
Markus Triska
8b7281fad0 ADDED: dif_si/2
Source: https://stackoverflow.com/questions/20223390/prolog-a-person-is-a-sibling-of-himself

In Scryer Prolog, this is actually not needed, since Scryer Prolog provides
dif/2 in library(dif). However, it is still useful to provide dif_si/2 for two reasons:

  1) to more easily port code from systems where only dif_si/2 is available
  2) to provide correct disequality in other systems that adopt this library
2023-04-23 00:37:14 +02:00
Mark Thom
502574dfc3 Merge pull request #1795 from infogulch/fix-ci-install
Use --force to install cargo2junit
2023-04-22 16:03:39 -06:00
infogulch
7a0f4e5787 Use --force to install cargo2junit
This probably appeared now because it's the first time this tool was cached
from a previous run.
2023-04-22 15:42:10 -05:00
Mark Thom
f277f660f3 Merge pull request #1793 from infogulch/fix-action-ref
Change ref for `publish-unit-test-result-action`
2023-04-22 11:26:45 -06:00
infogulch
9c037d6028 Change ref for publish-unit-test-result-action 2023-04-22 10:18:10 -05:00
Mark Thom
396528189d Merge pull request #1789 from aarroyoc/uppercase
library(charsio): add to_upper and to_lower
2023-04-20 07:17:09 +02:00
Adrián Arroyo Calle
4b882c465c library(charsio): add to_upper and to_lower 2023-04-18 18:58:09 +02:00
Mark Thom
8937cac47d Merge pull request #1783 from infogulch/test
Refactor CI Workflow
2023-04-18 08:35:45 +02:00
infogulch
5a3e2899dd Refactor CI Workflow
* Rename the workflow from Test to CI, since it does more than tests
* Run logtalk tests in a separate job to improve isolation
* Publish all xunit/junit test files as build artifacts to be consumed
  by a separate publishing workflow.
* Add "job summary" feature to show a formatted summary of the test
  results on the job summary status page
* Run the CI job once every Wed to ensure that there are always some
  recent builds on master that haven't expired.
2023-04-14 14:55:49 -05:00
Mark Thom
3a5ed4723b Merge pull request #1785 from mthom/dependabot/cargo/h2-0.3.17
Bump h2 from 0.3.15 to 0.3.17
2023-04-14 06:22:32 +02:00
Mark Thom
dcf4c44173 Merge pull request #1786 from triska/tuples_in
FIXED: propagation for ground tuples
2023-04-14 06:22:18 +02:00
Markus Triska
5763a4b9df FIXED: propagation for ground tuples
Example:

    ?- tuples_in([[A,A]],[[0,1],[2,0]]).
       false.

See https://github.com/triska/clpz/issues/22.
2023-04-13 23:39:45 +02:00
dependabot[bot]
82200a21eb Bump h2 from 0.3.15 to 0.3.17
Bumps [h2](https://github.com/hyperium/h2) from 0.3.15 to 0.3.17.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.15...v0.3.17)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-13 17:03:50 +00:00
Mark Thom
fc7d98d748 Merge pull request #1780 from triska/tuples_in
Various improvements to tuples_in/2
2023-04-12 19:10:50 +02:00
Markus Triska
5dce7d9075 FIXED: enforce equality also for ground elements in tuples
Example:

    ?- tuples_in([[A,B]], [[1,2],[3,4]]),
       tuples_in([[A,B]], [[3,2]]).
       false.

See https://github.com/SWI-Prolog/swipl-devel/issues/1160.
2023-04-11 22:33:19 +02:00
Markus Triska
f08f539768 do not create attributed variables for ground tuples 2023-04-11 21:26:18 +02:00
Markus Triska
be45672e22 actually disable and reenable the queue 2023-04-11 21:26:18 +02:00
Markus Triska
94efb9ffe3 remove no longer needed clpz_relation attributes 2023-04-11 21:26:18 +02:00
Markus Triska
fd1e902492 do not leave an attribute when (re-)enabling a queue 2023-04-11 21:14:18 +02:00
Mark Thom
8d6e3d7d56 Merge pull request #1776 from infogulch/master
Add iso prolog / logtalk tests to test runner
2023-04-07 06:09:08 +02:00
infogulch
a197bb6815 Allow the test suite to fail without failing the build 2023-04-06 09:40:03 -05:00
infogulch
9de8456c7f Add logtalk test suite 2023-04-02 17:31:20 -05:00
infogulch
ebf8091dba Test workflow cleanup; switch to macos-11 2023-04-02 14:47:52 -05:00
Mark Thom
47ce84b273 Merge pull request #1772 from triska/number_chars
FIXED: number_chars(N, "0' "), addressing #1580.
2023-04-02 19:24:59 +02:00
Mark Thom
449e097f4a Merge pull request #1774 from infogulch/master
Optimize Test GH action
2023-04-02 19:24:36 +02:00
Markus Triska
fe27605497 FIXED: number_chars(N, "0' "), addressing #1580.
There may be a more elegant way to solve this.
2023-04-02 10:04:52 +02:00
infogulch
8792ee438c Add cache step to test workflow 2023-04-02 02:09:41 -05:00
Mark Thom
7279062d3c Merge pull request #1770 from triska/doc
Smaller documentation improvements to explain compilation and target directory
2023-04-01 23:28:19 +02:00
Markus Triska
b87fe1e21f DOC: link to "Indexing dif/2" 2023-04-01 11:04:37 +02:00
Markus Triska
d6ac125425 DOC: explain location of scryer-prolog after compilation
This question was recently raised on the #scryer IRC channel.
2023-04-01 11:04:37 +02:00
Markus Triska
b79d8732ea use the release flag so that the instructions can be used verbatim
Also, the location of the executable depends on this flag.
2023-04-01 11:04:33 +02:00
Markus Triska
3df0806017 change "run" to "build", since "run" leads to a Scryer prompt which can be unexpected 2023-04-01 11:03:31 +02:00
Mark Thom
c7759aa737 Merge pull request #1769 from triska/show_pending_constraints
ENHANCED: use call_residue_vars/2 to show all pending constraints
2023-03-31 04:51:34 +02:00
Markus Triska
8ab1155fc5 ENHANCED: use call_residue_vars/2 to show all pending constraints
Example:

    ?- freeze(_, false).
       freeze:freeze(_A,false).

This was originally added in 04ba9bc11a,
then reverted, and is now restored.
2023-03-30 23:49:33 +02:00
Mark Thom
adc77985d7 broaden the definition of alpha_char! (#1749, #1515, #1591) 2023-03-26 11:10:46 -06:00
Mark Thom
d85fc7c9f8 Merge pull request #1765 from mthom/dependabot/cargo/openssl-0.10.48
Bump openssl from 0.10.42 to 0.10.48
2023-03-25 06:20:00 +01:00
dependabot[bot]
41b083c962 Bump openssl from 0.10.42 to 0.10.48
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.42 to 0.10.48.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.42...openssl-v0.10.48)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-25 01:27:40 +00:00
Mark Thom
4ee6a7bfb8 add '$unattributed_var' builtin (#1758) 2023-03-18 23:08:38 -06:00
Mark Thom
6e53d08d40 Merge pull request #1759 from triska/better_queue
Better queue
2023-03-16 04:34:33 +01:00
Markus Triska
01285f12c3 remove no longer needed queue attributes after propagation 2023-03-15 21:17:06 +01:00
Markus Triska
cd586aab8c show remaining queue/2 attributes as residual goals
This lets us verify that all attributes are correctly removed earlier.
2023-03-15 19:56:02 +01:00
Mark Thom
4da646252b Revert "correct call_residue_vars/3 using new copy_term_3 (#1239)"
This reverts commit 9b35a316c9.
2023-03-14 21:34:49 -06:00
Mark Thom
cc8bb38abc Revert "use new call_residue_vars/2 in toplevel.pl (#847)"
This reverts commit 04ba9bc11a.
2023-03-14 21:34:48 -06:00
Mark Thom
04ba9bc11a use new call_residue_vars/2 in toplevel.pl (#847) 2023-03-12 17:56:54 -06:00
Mark Thom
9b35a316c9 correct call_residue_vars/3 using new copy_term_3 (#1239) 2023-03-12 17:56:54 -06:00
Mark Thom
3a522f3c98 Merge pull request #1757 from aarroyoc/fix-docs-1756
DOCS: Fixes #1756
2023-03-12 18:26:54 +01:00
Adrián Arroyo Calle
4c44859132 Fixes #1756 2023-03-12 16:47:20 +01:00
Mark Thom
ecd77f7512 Merge pull request #1755 from triska/doc
various smaller documentation improvements
2023-03-10 02:40:29 +01:00
Markus Triska
56bd596af3 use actual toplevel answers 2023-03-08 23:35:11 +01:00
Markus Triska
21acb9361a use string notation as discussed on #scryer IRC 2023-03-08 23:32:05 +01:00
Markus Triska
c3477d8476 items --> elements
This addresses #1740.
2023-03-08 23:31:02 +01:00
Mark Thom
cba09d4ea1 Merge pull request #1754 from triska/dif
ENHANCED: more compact definition of dif/2
2023-03-08 21:48:34 +01:00
Markus Triska
884b0ca10e FIXED: Take all variables into account during goal projection.
This addresses #1751.
2023-03-08 21:16:54 +01:00
Markus Triska
c9ecfb11d9 ENHANCED: more compact definition of dif/2
As outlined in #1753.
2023-03-08 20:50:33 +01:00
Mark Thom
9288dcabe9 Merge pull request #1744 from aarroyoc/ffi
Foreign Function Interface - library(ffi)
2023-03-02 21:57:56 +01:00
Adrián Arroyo Calle
73df96244d Fill more cases 2023-03-01 22:13:04 +01:00
Adrián Arroyo Calle
7396630627 Merge branch 'master' into ffi 2023-02-28 22:10:40 +01:00
Adrián Arroyo Calle
0ac93751d0 FFI: Documentation 2023-02-28 22:09:35 +01:00
Mark Thom
400ca21213 invoke '$default_attr_list' in project_attributes.pl (#1748) 2023-02-26 22:42:02 -07:00
Mark Thom
3286e78cd2 third argument of copy_term should be instantiated as a list (#1747) 2023-02-26 22:42:02 -07:00
Mark Thom
24eb9ce483 Merge pull request #1746 from triska/type_over_instantiation_error
ENHANCED: must_be/2: prefer type error over instantiation error
2023-02-26 23:46:23 +01:00
Markus Triska
3dc6ed79d2 ENHANCED: must_be/2: prefer type error over instantiation error
This addresses #1594.
2023-02-26 22:28:18 +01:00
Adrián Arroyo Calle
f94294dbd9 FFI: Nested structs 2023-02-26 20:48:00 +01:00
Mark Thom
04ba58067a add, implement and use the Unifier trait 2023-02-26 12:21:22 -07:00
Adrián Arroyo Calle
92b262d599 Macroization of the code 2023-02-25 22:27:28 +01:00
Mark Thom
7ffb40e0ad Merge pull request #1743 from triska/rely_on_indexing
rely on first instantiated argument indexing
2023-02-25 19:23:59 +01:00
Markus Triska
997161c740 rely on first instantiated argument indexing
This great improvement to indexing allows much more natural
definitions of virtually all meta-predicates. Many thanks to @notoria!
2023-02-25 10:17:55 +01:00
Mark Thom
84c95c59e9 Merge pull request #1741 from triska/clpz_residuals
in projection of residual goals, mark considered propagators as processed
2023-02-23 01:51:22 +01:00
Markus Triska
669242a8ce DOC: update residual goals 2023-02-23 00:10:36 +01:00
Markus Triska
2a04d5e799 in projection of residual goals, mark considered propagators as processed
This is to avoid duplicated goals with the new projection mechanism.
2023-02-23 00:05:27 +01:00
Adrián Arroyo Calle
9d52d2a653 MVP of Foreign Function Interface 2023-02-22 23:10:03 +01:00
Mark Thom
95f6ebc000 assign responsibility for emitting dif goal to the first variable of the left-hand term (#1739) 2023-02-22 10:28:29 -07:00
Mark Thom
6e9cd072c5 catch attribute_goals errors in copy_term/3, don't discard variable module qualifiers in dcg_body/3 (#1738) 2023-02-21 00:50:46 -07:00
Mark Thom
729f2b1cb9 Merge pull request #1737 from triska/link_to_homepage
add link to newly available homepage
2023-02-20 21:10:01 +01:00
Markus Triska
1a01438064 add link to newly available homepage
Many thanks to @aarroyoc for the documentation system, and for hosting the page!
2023-02-20 20:09:47 +01:00
Robert Jacobson
34ec6d3167 Changed the links for the delimited continuations papers and the precise garbage collection paper. 2023-02-20 01:11:52 -07:00
Robert Jacobson
c9295323f6 Added links to referenced research papers in the Phase 2 and Nice to Have Features sections. 2023-02-20 01:11:52 -07:00
Mark Thom
92d543b8a8 change '$delete_all_attributes' to '$delete_all_attributes_from_var' 2023-02-20 01:11:52 -07:00
Mark Thom
3f445c76be add '$delete_all_attributes', use copy_term/3 as defined in #1272 2023-02-20 01:11:51 -07:00
Mark Thom
a6e416f13d compile '$atts' and '$project_atts' modules using loader.pl 2023-02-20 01:11:35 -07:00
Mark Thom
601ff567e3 keep phrase goal qualified even if qualifier is a variable 2023-02-17 00:20:15 -07:00
Mark Thom
56783b8e4b correct incremental compilation bugs 2023-02-12 23:41:25 -07:00
Mark Thom
326f18ea75 copy attributed variable attribute lists specially via copy_attr_var_list 2023-02-12 17:30:04 -07:00
Mark Thom
491472a8c5 retire TrailedAttrVarHeapLink TrailEntry tag 2023-02-10 22:52:27 -07:00
Mark Thom
359619e035 simplify and optimize attributed variables (#1590, #1634, #1730) 2023-02-10 21:56:42 -07:00
Mark Thom
9454d670c7 port '$get_from_list' to '$get_from_attr_list' in Rust 2023-02-06 01:23:29 -07:00
Mark Thom
2fcec4fff9 include wambook errata 2023-02-04 18:14:16 -07:00
Mark Thom
2c2a9fe01e correct shl stub_gen 2023-02-03 22:27:15 -07:00
Mark Thom
165a55dac6 Merge pull request #1734 from triska/clpz_corrections
DOC: teletype font for reification
2023-02-04 05:49:11 +01:00
Markus Triska
196e9c1e47 DOC: teletype font for reification 2023-02-03 20:47:08 +01:00
Mark Thom
17450520ba shift by usize instead of u32 in shl and shr (#1718, #1719) 2023-02-02 20:49:39 -07:00
Mark Thom
97702f3071 Merge pull request #1732 from aarroyoc/docs-minor-fixes
Minor fixes to docs
2023-02-03 01:58:52 +01:00
Adrián Arroyo Calle
e8408ca93f Minor fixes to docs 2023-02-02 21:35:35 +01:00
Mark Thom
e0dcf88b68 Merge pull request #1731 from triska/clpz_corrections
correct DocLog ~/.scryerrc rendering
2023-02-02 06:26:08 +01:00
Mark Thom
cc38cf15a4 Merge pull request #1729 from aarroyoc/negative-shifts
Negative shifts (fixes #1719 and #1718)
2023-02-02 06:25:52 +01:00
Markus Triska
da4c0a359b correct DocLog ~/.scryerrc rendering 2023-02-01 23:26:52 +01:00
Mark Thom
ce56a7303e avoid arena allocation of stream in read_term_from_chars (#1266) 2023-01-31 00:15:57 -07:00
Mark Thom
5667ec8699 update tokio version 2023-01-30 23:27:07 -07:00
Adrián Arroyo Calle
36b3150225 Negative shifts (fixes #1719 and #1718) 2023-01-30 18:56:37 +01:00
Mark Thom
28c338416f Merge pull request #1728 from aarroyoc/docs-csv
Compatible Doclog docs for library(csv)
2023-01-30 04:24:04 +01:00
Mark Thom
26a8fc1a37 Merge pull request #1727 from triska/clpz_corrections
DOC: use valid Prolog terms as predicate indicators
2023-01-30 04:23:52 +01:00
Adrián Arroyo Calle
f347baafa3 Compatible Doclog docs for library(csv) 2023-01-29 22:36:16 +01:00
Markus Triska
95278c221b DOC: use valid Prolog terms as predicate indicators 2023-01-29 21:48:22 +01:00
Mark Thom
5a28366158 Merge pull request #1725 from aarroyoc/fix-docs-http-server
Fix library(http/http_server) docs. Other minor fixes
2023-01-28 20:12:09 +01:00
Mark Thom
ac0cea8a73 Merge pull request #1724 from triska/clpz_corrections
CLP(ℤ) corrections
2023-01-28 20:11:48 +01:00
Markus Triska
814b631543 use DocLog syntax for section anchors and links within the document 2023-01-28 17:37:43 +01:00
Markus Triska
0d8c7f8785 small documentation adjustments 2023-01-28 17:37:43 +01:00
Markus Triska
5bae8fcaf8 FIXED: use lsb/2 and msb/2 from library(arithmetic)
This addresses #1720.
2023-01-28 17:37:43 +01:00
Adrián Arroyo Calle
4110cfcfcb Fix library(http/http_server) docs. Other minor fixes 2023-01-28 16:00:27 +01:00
Mark Thom
2bdba261ea Merge pull request #1717 from triska/format_doc
correct table layout for entries that themselves contain |
2023-01-27 07:47:53 +01:00
Markus Triska
58fb851717 correct table layout for entries that themselves contain | 2023-01-27 00:22:48 +01:00
Mark Thom
1118b37c92 Merge pull request #1674 from aarroyoc/docs-builtins
Compatible Doclog docs for builtins
2023-01-26 05:10:20 +01:00
Mark Thom
39606a2277 Merge pull request #1705 from triska/format_doc
DOC: convert library(format) documentation to DocLog format
2023-01-26 02:05:23 +01:00
Mark Thom
275d306b69 Merge pull request #1706 from triska/si_doc
DOC: convert library(si) documentation to DocLog format
2023-01-26 02:03:24 +01:00
Mark Thom
e948413c09 Merge pull request #1707 from triska/reif_doc
DOC: add link to "Indexing dif/2" in DocLog format
2023-01-26 02:03:14 +01:00
Mark Thom
f8bb3148d0 Merge pull request #1708 from triska/freeze_doc
DOC: add documentation for library(freeze) in DocLog format
2023-01-26 02:02:58 +01:00
Mark Thom
e7cf70936a Merge pull request #1709 from triska/pio_doc
DOC: convert library(pio) documentation to DocLog format
2023-01-26 02:02:47 +01:00
Mark Thom
409287e8f8 Merge pull request #1710 from triska/tabling_doc
DOC: initial documentation for library(tabling) in DocLog format
2023-01-26 02:02:35 +01:00
Mark Thom
87d6ef16f7 Merge pull request #1711 from triska/pairs_doc
DOC: initial documentation for library(pairs) in DocLog format
2023-01-26 02:02:22 +01:00
Mark Thom
3c08eba559 Merge pull request #1712 from triska/lambda_doc
DOC: convert code samples in library(lambda) to DocLog format
2023-01-26 02:02:12 +01:00
Mark Thom
d399b68d01 Merge pull request #1713 from triska/simplex_doc
DOC: convert library(simplex) documentation to DocLog format
2023-01-26 02:02:01 +01:00
Markus Triska
2e9ec653a8 DOC: convert library(simplex) documentation to DocLog format 2023-01-26 00:46:06 +01:00
Markus Triska
7ca782b92d DOC: convert code samples in library(lambda) to DocLog format 2023-01-26 00:40:08 +01:00
Markus Triska
996496c3f5 DOC: initial documentation for library(pairs) in DocLog format 2023-01-26 00:36:05 +01:00
Markus Triska
90cf713186 add link to Desouter et al., "Tabling as a Library with Delimited Control" 2023-01-26 00:25:26 +01:00
Markus Triska
ca4aaf44de DOC: initial documentation for library(tabling) in DocLog format 2023-01-26 00:20:53 +01:00
Markus Triska
b04d845ec0 DOC: convert library(pio) documentation to DocLog format 2023-01-26 00:09:41 +01:00
Markus Triska
a8ea2b0f97 DOC: add documentation for library(freeze) in DocLog format 2023-01-25 23:54:30 +01:00
Markus Triska
a29227d0d4 DOC: add link to "Indexing dif/2" in DocLog format 2023-01-25 23:40:55 +01:00
Markus Triska
7f8f137aa0 DOC: convert library(si) documentation to DocLog format 2023-01-25 23:27:45 +01:00
Markus Triska
cc7e721611 DOC: convert library(format) documentation to DocLog format 2023-01-25 23:18:39 +01:00
Mark Thom
058cbcf19a Merge pull request #1704 from triska/time_doc
DOC: correctly format the table using DocLog syntax
2023-01-25 22:51:05 +01:00
Markus Triska
22b815dc5c DOC: correctly format the table using DocLog syntax 2023-01-25 22:29:14 +01:00
Mark Thom
c709853aa7 Merge pull request #1703 from aarroyoc/docs-arithmetic
Compatible Doclog docs for library(arithmetic) and small fixes on INDEX.md
2023-01-25 21:40:15 +01:00
Adrián Arroyo Calle
d755bb7e12 Apply feedback on builtins 2023-01-25 21:04:10 +01:00
Adrián Arroyo Calle
6d99912b7b Compatible Doclog docs for library(arithmetic) and small fixes on INDEX.md 2023-01-25 19:48:01 +01:00
Mark Thom
82dd9e0596 Merge pull request #1701 from triska/diag_doc
DOC: add DocLog documentation for library(diag)
2023-01-25 00:16:53 +01:00
Mark Thom
6ba3d49034 Merge pull request #1702 from triska/debug_doc
DOC: add DocLog documentation for library(debug)
2023-01-25 00:16:34 +01:00
Markus Triska
64be8e0fba DOC: add DocLog documentation for library(debug) 2023-01-25 00:19:14 +01:00
Markus Triska
43a297b691 DOC: add DocLog documentation for library(diag) 2023-01-25 00:09:44 +01:00
Mark Thom
df266378c4 Merge pull request #1689 from triska/clpb_doc
DOC: preliminary CLP(B) documentation in DocLog format
2023-01-24 22:51:35 +01:00
Mark Thom
ec55765cb2 Merge pull request #1697 from triska/crypto_doc
DOC: convert library(crypto) documentation to DocLog format
2023-01-24 22:46:14 +01:00
Mark Thom
de2ff8118f Merge pull request #1696 from triska/clpz_doc
DOC: improve CLP(ℤ) DocLog documentation
2023-01-24 22:45:51 +01:00
Mark Thom
c30c9dc98f Merge pull request #1698 from triska/time_doc
DOC: convert library(time) documentation to DocLog format
2023-01-24 22:43:53 +01:00
Mark Thom
1f872c3f0c Merge pull request #1694 from aarroyoc/docs-dcgs
Compatible Doclog docs for library(dcgs)
2023-01-24 22:43:43 +01:00
Mark Thom
b6204eb6f1 Merge pull request #1699 from triska/sgml_doc
DOC: convert library(sgml) documentation to DocLog format
2023-01-24 22:43:22 +01:00
Markus Triska
af9f0f81d8 DOC: convert library(sgml) documentation to DocLog format 2023-01-24 22:42:58 +01:00
Markus Triska
1c08b56e05 strengthen reified division for divisor == 1 2023-01-24 22:15:05 +01:00
Markus Triska
6cb8020f62 DOC: add CLP(B) documentation in DocLog format 2023-01-24 22:15:05 +01:00
Markus Triska
d742d4cde9 DOC: convert library(time) documentation to DocLog format 2023-01-24 22:14:15 +01:00
Markus Triska
b7d06540e6 DOC: convert library(crypto) documentation to DocLog format 2023-01-24 22:13:38 +01:00
Markus Triska
909f2e1058 DOC: improve CLP(ℤ) DocLog documentation 2023-01-24 20:39:47 +01:00
Mark Thom
26d39c3617 Merge pull request #1695 from aarroyoc/website
Add website frontpage
2023-01-24 20:29:48 +01:00
Mark Thom
371bc3b231 Merge pull request #1676 from aarroyoc/docs-http-server
Compatible Doclog docs for library(http/http_server)
2023-01-24 04:09:39 +01:00
Adrián Arroyo Calle
bdeabcdd89 Website page 2023-01-23 23:51:27 +01:00
Adrián Arroyo Calle
7f177c3d03 Compatible Doclog docs for library(dcgs) 2023-01-23 21:03:11 +01:00
Mark Thom
4ed36a12e9 Merge branch 'retract_improvements' 2023-01-22 21:04:55 -07:00
Mark Thom
a7e93db363 improve retract/1 and related predicates (#1598) 2023-01-22 21:04:41 -07:00
Mark Thom
789715f31a Merge pull request #1693 from aarroyoc/docs-xpath
Compatible Doclog docs for library(xpath).
2023-01-23 04:04:00 +01:00
Mark Thom
7cc900d437 Merge pull request #1691 from aarroyoc/docs-os-3
Compatible Doclog docs for library(os)
2023-01-23 04:02:57 +01:00
Mark Thom
ff0f6f4fc2 Merge pull request #1690 from aarroyoc/docs-charsio
Compatible Doclog docs for library(charsio)
2023-01-23 04:02:02 +01:00
Mark Thom
5698e8f21a Merge pull request #1692 from aarroyoc/docs-between
Compatible Doclog docs for library(between).
2023-01-23 04:00:11 +01:00
Adrián Arroyo Calle
ddcae2c906 Compatible Doclog docs for library(xpath). 2023-01-22 21:22:54 +01:00
Adrián Arroyo Calle
468d096ccb Compatible Doclog docs for library(between). 2023-01-22 20:26:30 +01:00
Adrián Arroyo Calle
bca79d12c0 Compatible Doclog docs for library(os) 2023-01-22 17:45:50 +01:00
Adrián Arroyo Calle
03eba9594b Compatible Doclog docs for library(charsio) 2023-01-21 21:05:13 +01:00
Mark Thom
5e0e3e2754 Merge pull request #1687 from gruhn/master
Fix failing Docker build
2023-01-21 05:02:33 +01:00
Mark Thom
04fd835267 Merge pull request #1688 from aarroyoc/djot-migration
Migrate from Markdown to Djot
2023-01-21 04:48:26 +01:00
Adrián Arroyo Calle
f072761150 Fix assoc.pl file 2023-01-19 21:18:40 +01:00
Adrián Arroyo Calle
46d1e3bee3 Migrate from Markdown to Djot 2023-01-19 21:15:25 +01:00
Niklas Gruhn
f8e6e0252d Use lastest 1.xx Rust version in Docker build
With the previous Rust version 1.61, the build fails with

> error[E0658]: use of unstable library feature 'scoped_threads'

This has been "stabilized" in Rust 1.63. To avoid the hassle
of manually updating the version, we can just default to the
latest minor release.
2023-01-18 19:08:19 +01:00
Mark Thom
f9e3bdb6b0 restore free list usage on structures in facts without crashing lgtunit loader 2023-01-13 18:35:13 -07:00
Mark Thom
a80aab48cd Merge pull request #1677 from aarroyoc/docs-dif
Compatible Doclog docs for library(dif)
2023-01-13 07:50:17 +01:00
Mark Thom
3a4aa2a541 tighten deallocate truncation of stack (#1686) 2023-01-12 23:47:07 -07:00
Mark Thom
84583da5b8 Merge pull request #1685 from triska/reify_sign
ADDED: sign/1 is now reifiable.
2023-01-11 17:41:14 +01:00
Markus Triska
f213956ceb use (#)/1 2023-01-11 17:23:53 +01:00
Markus Triska
c5caa9d311 ADDED: sign/1 is now reifiable.
This addresses #1500.
2023-01-11 17:22:38 +01:00
Mark Thom
0c4d93f01f remove add_term_to_free_list from AddToList (#1684) 2023-01-10 18:24:48 -07:00
Mark Thom
a4e8bfc1ba Merge pull request #1682 from triska/reify_slash
FIXED: correctly reify (/)/2.
2023-01-10 23:44:48 +01:00
Markus Triska
542b9e1976 rely on newly available operator notation for (#)/1 2023-01-10 22:59:11 +01:00
Markus Triska
73a1ee59fa replace several more instances of ?/1 by (#)/1 2023-01-10 22:57:14 +01:00
Markus Triska
2771109427 use (#)/1 already internally for describing constraint projections 2023-01-10 22:50:38 +01:00
Markus Triska
cc420bd31a FIXED: reification of (xor)/2.
Example:

    ?- A #= 1 xor 0 #<==> R.
    %@    clpz:(A#=1#<==>R), clpz:(R in 0..1).
2023-01-10 22:09:41 +01:00
Markus Triska
2fe1d2ef53 FIXED: correctly reify (/)/2.
Example:

    ?- 0 #==> X #= 1/2.
    %@    clpz:(X in inf..sup)
    %@ ;  false.

This addresses #1501.
2023-01-10 17:35:43 +01:00
Mark Thom
bb624cc971 use free lists to allow register re-use (#1612) 2023-01-08 12:11:04 -07:00
Mark Thom
aa7b8e52f3 use '$enqueue_attr_var' when adding attributes only 2022-12-24 00:31:47 -07:00
Adrián Arroyo Calle
07f358c91b Compatible Doclog docs for library(dif) 2022-12-22 23:23:07 +01:00
Adrián Arroyo Calle
8ae0a1a4af Compatible Doclog docs for library(http/http_server) 2022-12-22 22:36:33 +01:00
Adrián Arroyo Calle
7647ad14b8 More feedback applied 2022-12-21 23:19:38 +01:00
Adrián Arroyo Calle
21e4347b3e Apply some feedback 2022-12-21 22:32:36 +01:00
Adrián Arroyo Calle
f2d041ea23 Merge branch 'master' into docs-builtins 2022-12-21 21:29:22 +01:00
Adrián Arroyo Calle
56c1c4e43c Compatible Doclog docs for builtins 2022-12-21 21:28:16 +01:00
Mark Thom
820011412b Merge pull request #1658 from aarroyoc/copy_file
Add predicate file_copy/2 in library(files)
2022-12-18 21:22:25 +01:00
Mark Thom
81afa6942f Merge pull request #1672 from triska/deref_register
dereference more registers, analogous to d660e4244f
2022-12-18 21:21:58 +01:00
Markus Triska
6cb8d7596a dereference more registers, analogous to d660e4244f
See also #1654 for a nice test case by @notoria which this corrects.
2022-12-18 17:43:33 +01:00
Mark Thom
a2d46af5ac Merge pull request #1671 from aarroyoc/docs-iso-ext
Compatible Doclog docs for library(iso_ext)
2022-12-18 00:38:22 +01:00
Mark Thom
6d94b8ab75 Merge pull request #1669 from aarroyoc/docs-http-open
Compatible Doclog docs for library(http/http_open).
2022-12-18 00:38:13 +01:00
Adrián Arroyo Calle
0166c3bf0f Compatible Doclog docs for library(iso_ext) 2022-12-17 22:46:44 +01:00
Adrián Arroyo Calle
6a995fb62b Compatible Doclog docs for library(http/http_open). 2022-12-17 20:43:43 +01:00
Mark Thom
d804d8a92e use proper dynamic arities in JmpByCall and JmpByExecute (#1605, #1606) 2022-12-17 11:54:20 -07:00
Mark Thom
cf63e8375d track attr_var_init lengths on the stack (#1667) 2022-12-16 20:10:17 -07:00
Mark Thom
1eff758751 update README to point to local wambook (#1668) 2022-12-16 00:45:00 -07:00
Mark Thom
0a8fc70ba9 detect cyclic bindings in attr_vars_of_term (#1666) 2022-12-16 00:42:38 -07:00
Mark Thom
b4b72a3166 Merge pull request #1662 from mthom/interpreting_disj
Fix mishandled if-then-else interpretation (#1659)
2022-12-16 04:36:02 +01:00
Mark Thom
a5054c0064 use append/3 rather than set_difference/3 to gather witnesses in bagof/3 and setof/3 (#1663, #1664) 2022-12-12 23:55:55 -07:00
Mark Thom
705f421d53 Merge pull request #1661 from aarroyoc/lcm2
Add predicate lcm/2 to library(arithmetic)
2022-12-12 00:38:40 +01:00
Mark Thom
4dc0114c52 fix mishandled if-then-else interpretation (#1659) 2022-12-11 16:35:32 -07:00
Adrián Arroyo Calle
5f2c77fa74 Add predicate lcm/2 to library(arithmetic) 2022-12-11 21:49:41 +01:00
Adrián Arroyo Calle
5f703afed1 Rename copy_file/2 to file_copy/2 2022-12-11 00:08:41 +01:00
Adrián Arroyo Calle
c6aa2068e2 Add predicate copy_file/2 in library(files) 2022-12-11 00:06:56 +01:00
Mark Thom
209f7a239a Merge pull request #1657 from aarroyoc/docs-files
Compatible Doclog docs for library(files)
2022-12-10 18:09:01 +01:00
Mark Thom
0d404ad374 Merge pull request #1656 from aarroyoc/docs-ordsets
Compatible Doclog docs for library(ordsets)
2022-12-10 18:08:45 +01:00
Mark Thom
d5db0c641c Merge pull request #1655 from triska/deref_register
more uses of newly available deref_register(n)
2022-12-10 18:08:26 +01:00
Adrián Arroyo Calle
21d6220f3f Compatible Doclog docs for library(files) 2022-12-08 23:41:28 +01:00
Adrián Arroyo Calle
e0464d5447 Compatible Doclog docs for library(ordsets) 2022-12-08 22:30:48 +01:00
Markus Triska
309e5b320e more uses of newly available deref_register(n) 2022-12-07 23:19:31 +01:00
Mark Thom
afa9703eb5 Merge pull request #1653 from triska/deref_register
introduce and use deref_register(n)
2022-12-07 05:52:07 +01:00
Markus Triska
56e5da6680 introduce and use deref_register(n) 2022-12-06 21:07:50 +01:00
Mark Thom
a8810d73e4 Merge pull request #1652 from aarroyoc/docs-lists
Compatible Doclog docs for library(lists)
2022-12-06 17:57:46 +01:00
Mark Thom
4b31c30cab Merge pull request #1651 from aarroyoc/docs-sockets
Compatible Doclog docs for library(sockets)
2022-12-06 17:57:36 +01:00
Adrián Arroyo Calle
df4b56148f Compatible Doclog docs for library(lists) 2022-12-06 13:19:10 +01:00
Adrián Arroyo Calle
f22a48f576 Compatible Doclog docs for library(sockets) 2022-12-06 11:58:26 +01:00
Mark Thom
d660e4244f dereference encoding register in crypto_data_decrypt (#1650) 2022-12-05 23:28:47 -07:00
Mark Thom
d383e5eb8b avoid pushing stack variables to the heap in get_continuation_chunk (#1644) 2022-12-05 23:17:15 -07:00
Mark Thom
e1dc114517 Merge pull request #1649 from aarroyoc/docs-ugraphs
Compatible Doclog docs for library(ugraphs)
2022-12-05 06:05:13 +01:00
Mark Thom
73780ebf63 Merge pull request #1648 from aarroyoc/docs-random
Compatible Doclog docs for library(random)
2022-12-05 06:05:02 +01:00
Mark Thom
a19f7a0b9f Merge pull request #1647 from aarroyoc/docs-uuid
Compatible Doclog docs for library(uuid)
2022-12-05 06:04:48 +01:00
Mark Thom
e07473d155 Merge pull request #1646 from aarroyoc/docs-assoc
Compatible Doclog docs for library(assoc)
2022-12-05 06:04:30 +01:00
Adrián Arroyo Calle
d429b263eb Compatible Doclog docs for library(ugraphs) 2022-12-05 00:09:32 +01:00
Adrián Arroyo Calle
b2a0d0c1c7 Compatible Doclog docs for library(random) 2022-12-02 23:43:24 +01:00
Adrián Arroyo Calle
8bafd7adb1 Compatible Doclog docs for library(uuid) 2022-12-02 23:23:16 +01:00
Adrián Arroyo Calle
76d24fe4e3 Compatible Doclog docs for library(assoc) 2022-12-02 23:05:03 +01:00
Mark Thom
3bdcc3aba9 return -1 from get_code to indicate end of file (#1622) 2022-11-18 18:19:55 -07:00
Mark Thom
cb25b27963 Merge pull request #1640 from gruhn/master
Adjust Github Action: Docker Publish
2022-11-16 20:57:35 +01:00
Niklas Gruhn
b3df81c143 Adjust Github Action: Docker Publish
1. Not only publish Docker images when new release tags are created but
   on every push to master, since release frequency is so low.

2. Use newer versions of the various actions (setup-buildx-action,
   login-action, metadata-action, ...) to suppress some deprecation
   warnings see:
   https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-11-15 18:55:15 +01:00
Mark Thom
68b3c480c9 update Dockerfile to use rustc 1.61 2022-11-14 21:18:03 -07:00
Mark Thom
9fd1bf5574 mention #scryer in README 2022-11-14 21:16:46 -07:00
Mark Thom
b491a06c6d README rustc version bump 2022-11-14 21:13:52 -07:00
Mark Thom
d16312a314 use existing bindings in compile_is (#1545) 2022-11-14 20:58:07 -07:00
Mark Thom
d19a8d6b98 begin to mark registers as safe from built-in predicates like is/2 (#1545) 2022-11-14 20:58:07 -07:00
Mark Thom
c90dd80ece revise UnsafeVarMarker (#1545) 2022-11-14 20:57:51 -07:00
Mark Thom
eb9d865635 Merge pull request #1635 from mthom/rebis-dev
Some checks failed
Test / windows (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
Test / build (macos-10.15, beta) (push) Has been cancelled
Test / build (macos-10.15, stable) (push) Has been cancelled
Test / build (ubuntu-20.04, beta) (push) Has been cancelled
Test / build (ubuntu-20.04, stable) (push) Has been cancelled
Test / msrv (macos-10.15) (push) Has been cancelled
Test / msrv (ubuntu-20.04) (push) Has been cancelled
Merge rebis-dev into master
2022-11-10 07:18:10 +01:00
Mark Thom
694c87cb61 bump version to 0.9.1 2022-11-10 06:59:03 +01:00
Mark Thom
c41aba6b90 remove num-rug-adapter 2022-11-10 06:56:57 +01:00
Mark Thom
28ea672e36 move asserta/2, assertz/2 to iso_ext 2022-11-10 06:47:32 +01:00
Mark Thom
9366a48d6d introduce InlineTermStream to avoid arena allocations during call_inline (#1576) 2022-11-09 00:01:01 +01:00
Mark Thom
c7e1f5d568 Merge pull request #1630 from epilys/fix-1625
fix type_error with instantiated EOF -1 byte literal in get_byte/2
2022-10-26 23:37:36 -06:00
Markus Triska
d91ee5b77c FIXED: CLP(ℤ): Correctly remove all attributes during propagation of all_distinct/1 and other global constraints.
The constraints from library(clpz) were already correctly removed, but
others such as pending freeze/2 goals were not, potentially leading to
an accumulation of redundant constraints during propagation.

Test case:

   ?- freeze(A,(X=1;X=2)), all_distinct([A]), A = 1.
      A = 1, X = 1
   ;  A = 1, X = 2.

The combination of freeze/2 and CLP(ℤ) is useful for example when
creating animations of search processes.

This addresses #1624.
2022-10-26 23:36:07 -06:00
Mark Thom
fd97b84916 build partial strings using PStrLoc in write_term_to_heap (#1627) 2022-10-26 23:36:07 -06:00
Mark Thom
23f59970cb export asserta/2 (#1623) 2022-10-26 23:36:07 -06:00
Mark Thom
8781e03863 cache ball terms before unifying in handle_ball/3 (#1608) 2022-10-26 23:36:07 -06:00
Adrián Arroyo Calle
f2940ddfcf Some minor fixes. Thanks to @triska for them! 2022-10-26 23:36:07 -06:00
Mark Thom
140149f051 fix crash in read_term (#1616) 2022-10-26 23:36:07 -06:00
Skgland
9055370326 adjust rust-version declaration 2022-10-26 23:36:07 -06:00
Adrián Arroyo Calle
1af62c8d11 Set default Shell 2022-10-26 23:36:07 -06:00
Adrián Arroyo Calle
ec5430826e Add Windows MSYS2 2022-10-26 23:36:07 -06:00
Markus Triska
b2cccab768 ENHANCED: library(crypto): Faster conversion to bytes when the integer is known.
These entailed constraints only affect performance, and can be removed
without affecting the correctness of the code. They speed up scalar
multiplication of a curve point, used for example in Bitcoinolog.
2022-10-26 23:36:07 -06:00
Markus Triska
579aa8acd4 use newly available u8s_to_string 2022-10-26 23:36:07 -06:00
Markus Triska
9c2cb144b5 remove redundant error handling, since this case is checked in Prolog
This restores f668640e3d, where this
change was already made. It seems it was accidentally overwritten in
0404c3bd94.
2022-10-26 23:36:07 -06:00
Markus Triska
3d04689660 introduce and use u8s_to_string 2022-10-26 23:36:07 -06:00
Markus Triska
a891cc4edf use (slightly) better variable names 2022-10-26 23:36:07 -06:00
Markus Triska
706ab2ae5b use newly available must_be(chars, ...) for better and shorter type test 2022-10-26 23:36:07 -06:00
Markus Triska
9c1de8e00b ENHANCED: Eliminate the OpenSSL dependency of library(crypto).
This is achieved by using the newly available crrl crate by @pornin
to implement crypto_curve_scalar_mult/4 for secp256k1. Many thanks!
2022-10-26 23:36:07 -06:00
Mark Thom
1109e05e06 properly match strings concluding with characters in lists (#1597) 2022-10-26 23:36:07 -06:00
Markus Triska
ce313b8a6b correct nth0/4 and nth1/4
As per 56b430ecaf (commitcomment-82155379).
2022-10-26 23:36:07 -06:00
Markus Triska
7c96b91663 remove nth1/3, which is now provided by library(lists) 2022-10-26 23:36:07 -06:00
Markus Triska
87e966e185 remove nth1/3, which is now provided by library(lists) 2022-10-26 23:36:07 -06:00
Markus Triska
1e018681de ENHANCED: Much improved nth0/3, taken from #1529.
This also adds nth0/4 and bootstraps nth1/[3,4] from it.
2022-10-26 23:36:07 -06:00
Markus Triska
5b324680ba ADDED: must_be/can_be(not_less_than_zero, ...)
See #1309.
2022-10-26 23:36:07 -06:00
Markus Triska
abca5fc405 better implementation of list_si/1
Per discussion in https://github.com/mthom/scryer-prolog/pull/1589.
2022-10-26 23:36:07 -06:00
Markus Triska
6a455d2866 ADDED: chars_si/1, testing for a string
Examples:

    ?- chars_si("hello").
       true.

    ?- chars_si(5).
       false.

    ?- chars_si([a,b,c|Rs]).
       error(instantiation_error,sort/2).
2022-10-26 23:36:07 -06:00
Markus Triska
70da818101 use new domain names from library(error): octet_character, octet_chars 2022-10-26 23:36:07 -06:00
Markus Triska
5ec837acb4 ADDED: octet_character and octet_chars, testing for strings that represent bytes. 2022-10-26 23:36:07 -06:00
Markus Triska
76e33d051c rely on the built-in DCG expansion, per discussion in #1577 2022-10-26 23:36:07 -06:00
Markus Triska
7c5318b784 ENHANCED: Use '$skip_max_list'/4 for greater efficiency of nth0/3.
This is now possible due to 4c7e2eb8614da9c04f2286f6116b468017fb442c.

See #1529 for the suggestion by @UWN.
2022-10-26 23:36:07 -06:00
Markus Triska
47892bf24a ENHANCED: Improve determinism of ... //0 and seq//1.
Example:

    ?- phrase(..., "hello").
       true.

This addresses #1577.
2022-10-26 23:36:07 -06:00
Mark Thom
8a9cd7779c offset into complete strings with '$skip_max_list'/4 (#1529) 2022-10-26 23:36:07 -06:00
Mark Thom
d4c0277065 don't return ops with priority 0 when building set for current_op (#1571) 2022-10-26 23:36:07 -06:00
Mark Thom
069e132c0e treat functors with PI '.'/2 as lists (#1570) 2022-10-26 23:36:07 -06:00
Mark Thom
4e6c138099 introduce expand_call_goal/3 to expand goals in control meta-predicates (#1568) 2022-10-26 23:36:07 -06:00
Markus Triska
0ab355eada use a DCG to describe the path 2022-10-26 23:36:07 -06:00
Markus Triska
44825826df remove entailed must_be/2 goals 2022-10-26 23:36:07 -06:00
Markus Triska
612f09893c use newly available ... //0 from library(dcgs) 2022-10-26 23:36:07 -06:00
Markus Triska
e9f507b868 add meta_predicate/1 declaration for phrase_to_file/3 2022-10-26 23:36:07 -06:00
Mark Thom
78278c804f strip modules from GRBody in phrase/3 (#1565) 2022-10-26 23:36:07 -06:00
Mark Thom
b51460a59a fail on non-list solutions in setof/3 (#1553) 2022-10-26 23:36:07 -06:00
Adrián Arroyo Calle
181be5be3f HTTP Server 2.0 2022-10-26 23:36:07 -06:00
Mark Thom
91d4e91f53 prefix inlined goals with module names in expand_subgoal/5 (#1551) 2022-10-26 23:36:07 -06:00
Mark Thom
ad3ae7991b try to invoke '$call_inline' a second time in call/N (#1543) 2022-10-26 23:36:07 -06:00
Markus Triska
c7caf6b7a9 ENHANCED: CLP(ℤ): Reduce redundant propagator invocations during all_distinct/1 filtering
First, the current propagator is now logged and not re-triggered
during filtering. Second, and more significantly, all neq_num/2
constraints are scheduled and processed before more global constraints
are invoked. In this way, all the distilled information can be taken
into account by subsequently invoked global constraints.

These changes yield a 3-fold improvement in several Sudoku instances,
and a significant runtime reduction in social golfer instance 8-4-9.
2022-10-26 23:36:07 -06:00
Markus Triska
4422ffe39f add meta_predicate/1 declarations 2022-10-26 23:36:07 -06:00
Mark Thom
1ff52f70aa resolve phrase modules internally (#1541) 2022-10-26 23:36:07 -06:00
Mark Thom
fce45167a5 fail when exception caught from subgoal expansion (#1535) 2022-10-26 23:36:07 -06:00
Mark Thom
b8f384045c fix module resolution in dcgs, call/N (#1539) 2022-10-26 23:36:07 -06:00
Mark Thom
ea95a7900c deduplicate index ptr inlining for 0-arity atoms (#1538) 2022-10-26 23:36:07 -06:00
Mark Thom
edea1273c8 trim get_structure and put_structure arities when last arg is an index ptr (#1536) 2022-10-26 23:36:07 -06:00
Mark Thom
ec9c763211 print index_ptr offset (#1534) 2022-10-26 23:36:07 -06:00
Mark Thom
5a08117e75 use separate predicate for findall cleanup 2022-10-26 23:36:07 -06:00
Mark Thom
0aec980aa8 inference count call_inline, fail on undefined index 2022-10-26 23:36:07 -06:00
Mark Thom
6b05ee5130 streamline assertz/1, asserta/1 2022-10-26 23:36:07 -06:00
Mark Thom
1ffbf63d20 inline metacalls 2022-10-26 23:36:07 -06:00
Manos Pitsidianakis
b905d2758d fix type_error with instantiated EOF -1 byte literal in get_byte/2
According to ISO Prolog, get_byte/2 predicate can receive an
instantiated input byte:

http://www.gprolog.org/manual/html_node/gprolog037.html#sec156

    get_byte(+stream_or_alias, ?in_byte)

Since in_byte can be -1 if EOF is reached, instantiating it with -1
should work but does not because the implementation is trying to convert
it to a u8 which is unsigned:

?- open("/dev/null", read, S, [type(binary)]), get_byte(S, -1).
   error(type_error(in_byte,-1),get_byte/2).

This commit adds an extra check for -1 before checking for a valid u8
instantiated value if in_byte is an input:

?- open("/dev/null", read, S, [type(binary)]), get_byte(S, -1).
   S = '$stream'(0x55601e65c998).

Closes #1625
2022-10-26 13:49:38 +03:00
Mark Thom
311d985145 Merge pull request #1628 from epilys/fix-1626
Fix xor/2 type error reporting wrong argument
2022-10-25 20:46:49 -06:00
Manos Pitsidianakis
a9a06b5297 Fix xor/2 type error reporting wrong argument
If first argument n1 in xor/2 is of wrong numerical type, the match
patterns fall through to a catch all case that reports the second
argument in the type error.

Fixes #1626

`xor/2 function reports the wrong argument in type error #1626`

https://github.com/mthom/scryer-prolog/issues/1626
2022-10-24 19:26:43 +03:00
Mark Thom
6b8e620495 Merge pull request #1530 from RossSmyth/FixImports
Fixed imports for num-rug-adapter
2022-07-18 21:36:46 -06:00
Ross Smyth
577f85099d Fixed imports num-rug-adapter 2022-07-17 02:06:37 -04:00
Mark Thom
607c84a79b capture and propagate (=..)/2 errors in phrase/{2,3} (#1460) 2022-06-21 22:47:55 -06:00
Mark Thom
2eec6499ff propagate inference_limit_exceeded errors through the loader (#1298) 2022-06-18 11:26:31 -06:00
Mark Thom
cd1150c11d use setup_cal_n_init_goal_info in dynamic_module_resolution 2022-06-15 22:33:13 -06:00
Mark Thom
987bbdecf5 improve efficiency of call/N, replace '$call_with_default_policy' with
'$call_with_inference_counting'
2022-06-12 22:34:07 -06:00
Mark Thom
a68394b6f2 simplify detecting undefined goal_ and term_expansion 2022-06-12 22:34:07 -06:00
Mark Thom
3d6fbabc86 Merge pull request #1510 from Skgland/add-gitattributes
add a .gitattributes file
2022-06-12 15:44:14 -06:00
Skgland
1479b5d38c add a .gitattributes file
- this should stop problems such as mthom/scryer-prolog#1491
  by specifying the line ending
  as this should take precedence over the global config
2022-06-12 15:39:55 +02:00
Mark Thom
336311ecc8 replace call with $call in more meta-predicates 2022-06-06 09:28:03 -06:00
Mark Thom
e9bb35c895 emit indexing instructions in single clauses of dynamic predicates 2022-06-04 23:43:48 -06:00
Mark Thom
ab4f93dcee do not emit indexing instructions for single clause subsequences (#1503) 2022-06-04 15:29:00 -06:00
Mark Thom
140a199805 Merge pull request #1505 from Skgland/optional_rustfmt
make rustfmt optional
2022-06-04 09:56:51 -06:00
Skgland
232b66cfc3 adjust error message on failed formatting 2022-06-03 23:50:17 +02:00
Skgland
11ba7e47fd make rustfmt optional
- when rustfmt is not detected (by attempting to run ``rustfmt --version)
  no formatting will be attempted
- this should resolve issue mthom/scryer-prolog#1504
2022-06-03 23:35:55 +02:00
Mark Thom
c36d4a9c9a unmark cells in arith_eval_by_metacall (#1497) 2022-06-01 00:02:11 -06:00
Mark Thom
4b5c22864e don't print superfluous round brackets in curly braces (#1416) 2022-05-31 23:34:55 -06:00
Mark Thom
5e1faeb5d2 fix broken quoting in writeq/1 (#1498) 2022-05-31 18:29:42 -06:00
Mark Thom
4b7c2ba6c8 fix off-by-one error reporting in write_term/3 (#1490) 2022-05-30 23:25:44 -06:00
Mark Thom
b9285f8de1 don't quote most characters in strings (#1495, #301) 2022-05-30 23:09:20 -06:00
Mark Thom
084fc84590 use existence_error for dropped streams (#1472) 2022-05-23 11:15:58 -06:00
Mark Thom
7a9b71cc03 Merge pull request #1485 from triska/in_character
Implement and use can_be(in_character, ...)
2022-05-22 19:52:19 -06:00
Markus Triska
6b49653754 use in_character
This addresses one aspect of #1472.
2022-05-22 23:04:27 +02:00
Markus Triska
d5fa8cc211 ADDED: must_be(in_character, ...) and can_be(in_character, ...) 2022-05-22 23:04:27 +02:00
Mark Thom
10a11c293e fix stream position and term comparison bugs (#1472) 2022-05-22 14:16:14 -06:00
Mark Thom
e486862db8 Merge pull request #1484 from aarroyoc/fix-windows-build-2
Fix build on Windows 10
2022-05-22 10:15:16 -06:00
Adrián Arroyo Calle
1c8aae0839 MSI installer 2022-05-22 14:18:51 +02:00
Adrián Arroyo Calle
6feb1f8b82 Fix build on Windows 10 2022-05-22 13:18:11 +02:00
Mark Thom
bef8eb538c throw a representation error if max arity is exceeded (#1483) 2022-05-22 00:03:55 -06:00
Mark Thom
4e3b066555 Merge pull request #1482 from triska/multiple_of_five_answers
ENHANCED: "f" on toplevel to report answers up to the next multiple of 5.
2022-05-21 12:35:35 -06:00
Mark Thom
4d23542ef3 add max arity checks at various stages (#1459) 2022-05-21 12:32:48 -06:00
Markus Triska
47a6b498e3 ENHANCED: "f" on toplevel to report answers up to the next multiple of 5.
This makes counting solutions easy.
2022-05-21 18:20:08 +02:00
Mark Thom
b6f77f4e6f check asserta/2, assertz/2, abolish/2 for uninstantiated Module variables (#1475) 2022-05-16 20:45:45 -06:00
Mark Thom
b96cd06129 detect character type errors in atom_{chars|codes}/2 (#1472) 2022-05-16 16:32:38 -06:00
Mark Thom
e8eb6765bd Merge pull request #1478 from triska/sgml_improvements
Various improvements to library(sgml)
2022-05-15 09:44:44 -06:00
Mark Thom
8df552e952 Merge pull request #1477 from triska/document_tab_completion
document atom and predicate completion with TAB
2022-05-15 09:44:26 -06:00
Markus Triska
18c52e076f indent enumerations 2022-05-15 10:55:56 +02:00
Markus Triska
1810dabc14 clarify the representation 2022-05-15 10:55:27 +02:00
Markus Triska
609a3a229f strengthen and improve type checks 2022-05-15 10:51:00 +02:00
Markus Triska
dff56643f0 clarify comment 2022-05-15 10:23:00 +02:00
Markus Triska
77f8d52271 use phrase_from_file/2 directly on the file name 2022-05-15 10:19:00 +02:00
Markus Triska
1e9821ec0c document atom and predicate completion with TAB
This feature, added via
https://github.com/mthom/scryer-prolog/pull/1467, makes the toplevel
interaction a lot more convenient in many cases.

Many thanks to @euanlacy!
2022-05-15 10:05:30 +02:00
Mark Thom
66e047083a Merge pull request #1474 from triska/correct_can_be_chars
FIXED: can_be(chars, [a,X]), i.e., if variables occur as elements
2022-05-14 23:28:04 -06:00
Mark Thom
e6438e79d8 consider deallocate a head instruction (#1473) 2022-05-14 11:01:26 -06:00
Markus Triska
a5e72679bc prioritize type errors over instantiation errors
Example:

    ?- must_be(chars, [a,X,cc]).
       error(type_error(character,cc),can_be/2).

See https://github.com/mthom/scryer-prolog/pull/1474#issuecomment-1126664368
2022-05-14 09:53:21 +02:00
Markus Triska
15cc916333 FIXED: can_be(chars, [a,X]), i.e., if variables occur as elements
This should simplify 2f3de51e55 and
other cases like it.
2022-05-14 08:39:20 +02:00
Mark Thom
2f3de51e55 remove non-determinism in number_chars/2 and numbercodes/2 (#1473) 2022-05-13 18:38:58 -06:00
Mark Thom
cea1353fbb use must_be(chars) in number_chars/2 (#1470) 2022-05-12 01:09:06 -06:00
Mark Thom
bfbafd4168 Merge pull request #1467 from euanlacy/master
Completion of predicates in repl
2022-05-11 22:32:09 -06:00
Euan Lacy
27a15a2464 wip: add more atoms to completion list 2022-05-11 21:37:03 +01:00
Euan Lacy
c2a87f898e fix: remove unnecessary string & vec allocations 2022-05-10 18:10:18 +01:00
Euan Lacy
aaa75c3ffc wip: basic completion of predicates 2022-05-10 18:10:18 +01:00
Mark Thom
2dfa108034 unify partial string tail later in create_partial_string (#1462, #1465, #1427) 2022-05-08 14:52:22 -06:00
Mark Thom
4895cb7b22 fix culprit in stream_position permission_error (#1463) 2022-05-06 17:38:25 -06:00
Mark Thom
2d3eb8483f correct cycle detection in unify_* (#1455) 2022-05-05 18:58:56 -06:00
Mark Thom
36ef988514 Merge pull request #1461 from triska/clpz_sign
ADDED: sign/1
2022-05-05 17:24:54 -06:00
Markus Triska
d58dd7cc91 ADDED: sign/1 2022-05-05 22:51:49 +02:00
Markus Triska
7e06abebd5 remove comment that seems no longer valid 2022-05-05 22:51:49 +02:00
Mark Thom
8dd7f51ae3 fix rnd_i fixnum casting bug (#1456, #1458) 2022-05-04 22:44:12 -06:00
Mark Thom
6030fae685 track f64 offsets in Literal (#1190) 2022-05-04 21:54:46 -06:00
Mark Thom
0f502fff84 compact lists of characters to partial strings in read_term_from_heap (#1452, #1453) 2022-05-03 19:12:16 -06:00
Mark Thom
789f662ec8 fix match_partial_string, compare_pstr_to_string (#1451) 2022-04-30 19:51:19 -06:00
Mark Thom
72536037ca remove redundant register assignments in numeric comparisons (#1438, #1448) 2022-04-29 09:16:22 -06:00
Mark Thom
e4eefc92f4 remove redundant skip_stub_try_me_else condition (#1444) 2022-04-29 09:16:22 -06:00
Mark Thom
23c4e935b4 Merge pull request #1436 from triska/must_be_term
ADDED: can_be(term, ...) and must_be(term, ...)
2022-04-26 13:31:43 -06:00
Mark Thom
68b4951bc9 replace SliceDeque with VecDeque 2022-04-25 22:55:28 -06:00
Mark Thom
ed89c43e48 catch existence_error exceptions from top-level calls to attribute_goals/3 (#1432) 2022-04-24 20:59:00 -06:00
Mark Thom
16137ace0e unify structures from left to right (#1396) 2022-04-22 19:00:42 -06:00
Mark Thom
b4ef7556da update to crossterm 0.20.0 (#1439) 2022-04-21 18:41:07 -06:00
Markus Triska
eea83d9474 ADDED: can_be(term, ...) and must_be(term, ...)
This terminology is a bit harder to understand than that of the other
type checks.

Scryer Prolog comprises two individually consistent but incompatible
notions of terms, namely terms and rational trees (which are also
called "cyclic terms"). This leads to a confusion in terminology,
because cyclic terms are not terms in the former sense even though
they also contain the word "term" in their name.

This terminological confusion is not restricted to terms: We also find
it for example in the notion of lists. Lists are defined inductively:

    - The empty list (written as "" or [], called 'nil') is a list.
    - A term with principal functor '.'/2 is a list if its second argument
      is a list.

Note that a list may contain cyclic terms as elements, and still be
called a list. However, if we post:

    ?- Ls = [_|Ls].

then Ls is not a list, because it does not fit the inductive
definition. Still, it is sometimes referred to as a "cyclic list" or
"circular list", even though it is not a list. Even Prolog
implementors that aim for strict conformance to the Prolog ISO
standard and are deeply familiar with the standard use this
terminology when talking about such terms, see for example:

    https://github.com/ichiban/prolog/pull/198

Consequently, must_be(list, Ls) raises a *type error* in this case.

Terms are distinguished from cyclic terms completely analogously. This
leads to the counterintuitive consequence that *cyclic lists are not
terms*. The reason for this apparent contradiction in terminology is
the mutual incompatibility of different notions of terms. The notion
of "term" precludes rational trees, similar to the notion of "list"
which precludes cyclic lists.

We therefore introduce:

    * must_be(term, Term)
      - raises an instantiation error if Term contains variables (since
        it could still become a rational tree)
      - raises a type error if Term is a rational tree

    * can_be(term, Term)
      - raises a type error if Term is a rational tree

Note that using the notion of "cyclic term" and "acyclic term" in this
terminology would not be a good idea, because this confusion is
precisely what we want to eliminate: must_be(term, Term) should be
usable as a test that reliably determines whether Term can be treated
as a term with the logical properties we expect from terms.

This addresses #1428.
2022-04-20 22:15:32 +02:00
Mark Thom
9d5264c5a3 very minor optimizations 2022-04-17 20:10:13 -06:00
Mark Thom
66075bf45b mark unsafe variables and substitute temporary variables in is/2 when appropriate (#1430) 2022-04-17 17:33:09 -06:00
Mark Thom
35b8f69f92 fix panic caused by jmp offset off by one error (#1429) 2022-04-17 12:22:34 -06:00
Mark Thom
2d5fe21b05 avoid writing chars to the atom table in several places 2022-04-17 12:20:00 -06:00
Mark Thom
b448681872 Merge pull request #1421 from gruhn/master
push Docker image on new release
2022-04-16 11:11:33 -06:00
Mark Thom
05c14d5780 fix comparisons to partial string tails (#1420) 2022-04-14 22:14:23 -06:00
Niklas Gruhn
bb9de52a53 push Docker image on new release
Setup GitHub action which automatically builds and pushes Docker
images, when new release tags are created.
2022-04-14 21:42:28 +02:00
Mark Thom
7595ec16e5 instantiate Module in definition of retract/1 (#1392) 2022-04-13 20:31:16 -06:00
Mark Thom
d8cf0f320d mark cells that are about to be iterated in the stackful iterator (#1418) 2022-04-12 22:51:20 -06:00
Mark Thom
d644a3996e use '$call' all throughout setup_call_cleanup/3 2022-04-12 17:27:48 -06:00
Mark Thom
525050c407 dereference head of list in is_continuable (#1417) 2022-04-11 17:01:47 -06:00
Mark Thom
468088fd6b stop detecting cycles in compare_pstr_to_string 2022-04-10 19:46:34 -06:00
Mark Thom
95c192a988 mark variable referents in stackful iterator, fix tests (#1408) 2022-04-10 14:17:47 -06:00
Mark Thom
d6287fae06 Merge pull request #1415 from wkral/set_output-error
Fix reported source for set_output/1 error (#1407)
2022-04-10 14:11:43 -06:00
William Kral
9e98f75495 Fix reported source for set_output/1 error (#1407) 2022-04-10 12:00:59 -07:00
Mark Thom
56681af1b6 print dot after errors, fix tests (#1408) 2022-04-10 10:15:00 -06:00
Mark Thom
8bf3d4ea71 fix tests, use '$first_answer' to print indentation before errors (#1408) 2022-04-09 20:32:52 -06:00
Mark Thom
00eab4d415 print errors as goals (#1408) 2022-04-09 14:01:48 -06:00
Mark Thom
0876d46880 unmark dereferenced cells in term_variables/2 (#1412) 2022-04-09 12:15:46 -06:00
Mark Thom
ed803d30cd dereference bindings returned by stackful iterator (#1410, #1411) 2022-04-09 11:47:54 -06:00
Mark Thom
b6504bf377 deduplicate variable list in term_variables/2 (#1409) 2022-04-08 21:18:59 -06:00
Mark Thom
85b4f235ef throw errors on cyclic terms when evaluating is/2 expressions 2022-04-07 23:06:58 -06:00
Mark Thom
064bfa5e0d fix loop in stackful iterator (#1405, #1384) 2022-04-07 20:48:40 -06:00
Mark Thom
4a6ffb6b9e detect immediately cyclic lists (#1384) 2022-04-06 22:53:48 -06:00
Mark Thom
d952b7ace8 restore correct order to term_variables/2 (#1400, #1401) 2022-04-06 08:39:16 -06:00
Mark Thom
3b6138eaaa limit use of stackless iterator to test suite 2022-04-05 21:02:39 -06:00
Mark Thom
f3167f6b5f add forwarding bit to all heap cells (#1384) 2022-04-05 20:34:27 -06:00
Mark Thom
8c99d748e2 allocate floats in dedicated buffer 2022-04-05 20:34:27 -06:00
Mark Thom
0ab928063e make marker into an iterators, recover post_order_iterator 2022-04-05 20:34:27 -06:00
Mark Thom
c9a34bde3f removal of old stackless iterator, implementation of new more faithful one 2022-04-05 20:34:27 -06:00
Mark Thom
7f85c682b8 Merge pull request #1395 from wkral/fix-test-indentation
Fix indentation before false in tests (#676)
2022-04-05 10:58:12 -06:00
William Kral
181185bad6 Fix indentation before false in tests (#676) 2022-04-04 23:58:20 -07:00
Mark Thom
01a9fd9e25 indent plain false (#676) 2022-04-03 20:35:11 -06:00
Mark Thom
3be00045cf Merge pull request #1386 from triska/better_call_nth
ENHANCED: more memory efficient call_nth/2 (#1264)
2022-04-03 01:38:37 -06:00
Mark Thom
86176dce8d compare complete strings to one another in write_literal_to_var (#1388) 2022-04-03 01:37:19 -06:00
Markus Triska
1fa8a0a969 ENHANCED: more memory efficient call_nth/2 (#1264)
I hope that this will allow more extensive tests of Scryer Prolog. Enjoy!
2022-04-02 17:42:45 +02:00
Mark Thom
d5fe2e88d1 don't mark forwarded refs in stackless iterator/marker (#1384) 2022-04-02 01:29:51 -06:00
Mark Thom
9177dbce7f be aware of temporary variables of stackless iterator in term_variables (#1383) 2022-03-31 18:20:41 -06:00
Mark Thom
55a896367d Merge pull request #1381 from wkral/build-fmt-error
Improve rustfmt missing error during build (#1379)
2022-03-31 17:59:02 -06:00
William Kral
f2e49c84cc Improve rustfmt missing error during build (#1379) 2022-03-31 11:57:17 -07:00
Mark Thom
afa0bea1b1 Merge pull request #1380 from triska/as_is
as --> is
2022-03-30 13:56:25 -06:00
Markus Triska
f7e31fceac as --> is 2022-03-30 21:33:46 +02:00
Mark Thom
c490d818fb fix dif/2 crash (#1378) 2022-03-29 18:39:45 -06:00
Mark Thom
32bdedde6d Merge pull request #1373 from aarroyoc/http-open
Add Hyper based `http_open/3`
2022-03-28 23:10:08 -06:00
Mark Thom
48960f1beb print closed stream handle as '$dropped_value' (#1376) 2022-03-28 19:03:33 -06:00
Mark Thom
cf65cbe2f1 dereference numbervars terms (#1377) 2022-03-28 18:58:38 -06:00
Adrián Arroyo Calle
45c35eca3e Add close handling of http stream 2022-03-28 21:04:46 +02:00
Adrián Arroyo Calle
bb2a8c9090 http_open/3 try_or_throw 2022-03-28 20:38:55 +02:00
Adrián Arroyo Calle
6798b22b49 http_open/3 with headers and data 2022-03-28 20:38:55 +02:00
Adrián Arroyo Calle
3acbe2a418 http_open/3 with method option 2022-03-28 20:38:52 +02:00
Mark Thom
c45cdd6ea0 extend small_letter_char! to include all non-uppercase letters (#1364) 2022-03-27 13:34:29 -06:00
Mark Thom
f520c38b60 Stream::close() should close file handles (#1374) 2022-03-27 13:08:43 -06:00
Mark Thom
046a2175ab use ryu to print floats with a modification for compatible syntax (#1368, #1372) 2022-03-27 11:28:10 -06:00
Mark Thom
83def95383 fix char comparison misordering (#1371) 2022-03-26 21:44:37 -06:00
Mark Thom
012fefa37e retrieve F64 behind Cons tags properly (#1369) 2022-03-26 21:18:07 -06:00
Mark Thom
4878e42e07 Merge pull request #1370 from triska/files_must_be_chars
ENHANCED: use newly available must_be(chars, ...), which is very fast
2022-03-26 12:30:58 -06:00
Markus Triska
1a7992e524 ENHANCED: use newly available must_be(chars, ...), which is very fast 2022-03-26 19:09:54 +01:00
Mark Thom
94d7c6dc5f fix functor/3 arity check (#1366) 2022-03-25 18:07:22 -06:00
Mark Thom
23bfb4da50 advance arg in arithmetic comparison code (#1367) 2022-03-25 17:30:47 -06:00
Mark Thom
1f21a5fe62 detect float rounding overflows (#1365) 2022-03-24 10:25:42 -06:00
Mark Thom
2173a8e3cb recognize missing syntax errors (#1354, #1361) 2022-03-22 22:48:51 -06:00
Mark Thom
067e2633af compare TypedArenaPtr<T> by value not pointer (#1362) 2022-03-22 00:55:44 -06:00
Mark Thom
d916da9ba8 use Rust's native UTF-8 functions (#1355) 2022-03-19 16:52:27 -06:00
Mark Thom
c2fc33afec correct float version of sign/1 (#1360) 2022-03-19 15:55:23 -06:00
Mark Thom
3d4e400ed2 accept remaining UTF-8 codepoints as alphabetic characters (#1355) 2022-03-18 17:49:54 -06:00
Mark Thom
75d719d204 print most characters directly ((#1355) 2022-03-17 18:43:30 -06:00
Mark Thom
172e3e9f34 check self.ignore_ops and max_depth in print_rational (#1359) 2022-03-17 18:08:30 -06:00
Mark Thom
8e32bdd8db remove pstr offsets unconditionally from printer iteration stack, deal with fallout after the fact (#1357) 2022-03-16 19:11:39 -06:00
Mark Thom
895b02b641 improve length/2 (#1325) 2022-03-15 18:43:57 -06:00
Mark Thom
d06b5f7ab5 prepare for publishing to crates.io (#1335) 2022-03-15 00:07:42 -06:00
Mark Thom
e88ec6736c add (:) meta-predicate argument indicator (#1302) 2022-03-13 13:54:58 -06:00
Mark Thom
922abf21e7 derefence target variable in check_sort_errors (#1350) 2022-03-13 13:54:58 -06:00
Mark Thom
c55bfa2c6e throw errors on cycles in sort/2 and keysort/2 (#1350 and #1351) 2022-03-13 11:03:52 -06:00
Mark Thom
5463c1d47f point code index to switch_on_term after appending indexed clause to single-clause predicate (#1346) 2022-03-12 20:44:09 -07:00
Mark Thom
3513a9c7ba Merge pull request #1349 from Skgland/min-rust-version
Set minimum rust version in Cargo.toml (Attempt 2)
2022-03-12 13:12:03 -07:00
Skgland
45db236ec7 add a CI job to verify msrv is still correct 2022-03-12 19:23:34 +01:00
Skgland
5848ff5735 add min rust version
was proposed in https://github.com/mthom/scryer-prolog/issues/1335#issuecomment-1062039516 and got positive feedback

(cherry picked from commit fcfa3beaa3)
2022-03-12 19:23:33 +01:00
Mark Thom
64c9ac4071 Merge pull request #1348 from mthom/revert-1347-min-rust-version
Revert "Set minimum rust version in Cargo.toml"
2022-03-12 11:10:25 -07:00
Mark Thom
75fc922898 Revert "Set minimum rust version in Cargo.toml" 2022-03-12 11:10:17 -07:00
Mark Thom
59e2c3fd5e Merge pull request #1347 from Skgland/min-rust-version
Set minimum rust version in Cargo.toml
2022-03-12 11:07:03 -07:00
Skgland
5bd73741cf add a CI job to verify msrv is still correct 2022-03-12 19:02:34 +01:00
Skgland
fcfa3beaa3 add min rust version
was proposed in https://github.com/mthom/scryer-prolog/issues/1335#issuecomment-1062039516 and got positive feedback
2022-03-12 18:57:33 +01:00
Mark Thom
dfbdaa9dab Merge pull request #1342 from wkral/no-add-history
Add --no-add-history flag
2022-03-11 18:25:47 -07:00
William Kral
5f1f07e5a1 Add --no-add-history flag
Flag prevents the input stream from saving terms to ~/.scryer_history
when set. Use the flag when running tests to increase test isolation.
2022-03-10 21:48:41 -08:00
Mark Thom
eace0d9b37 print rationals that are integers as integers (#663) 2022-03-09 21:24:16 -07:00
Mark Thom
d83b32a200 print variables instead of offsets in setup_call_cleanup tests 2022-03-08 22:05:54 -07:00
Mark Thom
9cefb33388 correct loading of variable name strings in write_term/3 2022-03-08 22:00:12 -07:00
Mark Thom
bd5d6d0686 fix parser bounds check bug (#1333, #1301) 2022-03-08 21:25:19 -07:00
Mark Thom
ecebaf8216 unify empty list to '' in atom_chars/2 (#1334, #1336) 2022-03-08 18:25:40 -07:00
Mark Thom
8762647b55 wrap meta-predicate specifications in functors (#1330) 2022-03-07 22:36:52 -07:00
Mark Thom
664c0ee77c fix float formatting (#1331) 2022-03-07 19:44:39 -07:00
Mark Thom
7a9c3d351d Merge pull request #1332 from triska/call_nth_0
ENHANCED: call_nth(Goal, 0) now fails, correct error for N < 0.
2022-03-07 15:16:47 -07:00
Markus Triska
69e52d1ed8 ENHANCED: call_nth(Goal, 0) now fails, correct error for N < 0.
This addresses #1307.
2022-03-07 23:38:30 +01:00
Mark Thom
bd594e0c05 fix number/1 (#1329) 2022-03-06 19:17:52 -07:00
Mark Thom
3bf42860e2 Merge pull request #1328 from pmoura/fix_bounded_and_max_arity_flags
Fix querying the values of the bounded and max_arity flags
2022-03-06 18:51:14 -07:00
Paulo Moura
0532f51cc2 Fix querying the values of the bounded and max_arity flags 2022-03-07 00:30:35 +00:00
Mark Thom
1808597258 compare functor arity first (#1327) 2022-03-06 16:37:21 -07:00
Mark Thom
2744989cf1 fix compare/3 (#1327) 2022-03-06 15:49:01 -07:00
Mark Thom
0d04abb5c7 Merge pull request #1326 from pmoura/fix_halt_1_predicate_compliance
Fix halt/1 built-in predicate for ISO Prolog Core standard compliance
2022-03-06 14:46:46 -07:00
Paulo Moura
495168e7bb Fix halt/1 built-in predicate for ISO Prolog Core standard compliance 2022-03-06 21:33:49 +00:00
Mark Thom
475fbf9561 Merge pull request #1323 from triska/simplex
ADDED: library(simplex), for solving linear programming problems.
2022-03-06 13:46:32 -07:00
Markus Triska
c6264cf098 ADDED: library(simplex), for solving linear programming problems. 2022-03-06 21:49:52 +01:00
Mark Thom
bc9123affb only recommend git cloning to get the latest scryer version in README.md 2022-03-06 10:27:25 -07:00
Mark Thom
7fd12972ad Merge pull request #1322 from triska/explain_strings_better
DOC: Better explanation of strings and partial strings.
2022-03-06 10:07:37 -07:00
Mark Thom
2d19243b3b Merge branch 'rebis-dev' into 0.9.0 release
Some checks failed
Test / build (macos-10.15, beta) (push) Has been cancelled
Test / build (macos-10.15, stable) (push) Has been cancelled
Test / build (ubuntu-20.04, beta) (push) Has been cancelled
Test / build (ubuntu-20.04, stable) (push) Has been cancelled
2022-03-06 09:45:05 -07:00
Markus Triska
8ad4f188f2 DOC: Better explanation of strings and partial strings. 2022-03-06 11:05:31 +01:00
Mark Thom
0c19c56909 mark variables in ArithmeticEvaluator (#690) 2022-03-05 17:57:10 -07:00
Mark Thom
de35baadf3 use must_be(chars) in read_from_chars/2 (#1305) 2022-03-05 17:39:13 -07:00
Mark Thom
66c209f9e4 reset ReadlineStream from read_query_line (#1317, #1285) 2022-03-05 17:39:13 -07:00
Mark Thom
d7a3ed2d4a change domain_error(integer, ..) to type_error(integer, ..) in random.pl (#1310) 2022-03-05 17:39:13 -07:00
Mark Thom
0c25ffc26e dereference list link in delete_attribute (#1148) 2022-03-05 17:39:03 -07:00
Markus Triska
9f864574de ADDED: "f" to enumerate the next 5 solutions, similar to GUPU. 2022-03-02 21:05:49 +01:00
Mark Thom
a38f7c8524 save arguments to delayed goal before calling verify_attrs (#1304) 2022-03-01 23:59:41 -07:00
Mark Thom
bf85cd404c Merge pull request #1313 from triska/all_solutions
ADDED: "a" to enumerate all solutions
2022-03-01 15:34:21 -07:00
Markus Triska
102adb3544 ADDED: "a" to enumerate all solutions
Example:

    ?- member(X, "hello").
    %@    X = h   <-- press "a"
    %@ ;  X = e
    %@ ;  X = l
    %@ ;  X = l
    %@ ;  X = o
    %@ ;  false.
2022-03-01 23:52:51 +01:00
Mark Thom
c2b360d03e Merge pull request #1312 from triska/str_loc_as_cell
FIXED: load_html/3: use str_loc_as_cell! to store attribute structures
2022-03-01 12:09:42 -07:00
Markus Triska
1bec1b7002 FIXED: load_html/3: use str_loc_as_cell! to store attribute structures 2022-03-01 20:21:08 +01:00
Mark Thom
1b4b4807a5 refer to structures using str_loc_as_cell! (#1311) 2022-02-28 18:28:13 -07:00
Mark Thom
d4d135f2a9 fix unexpected error in length/2 (#1303) 2022-02-27 11:38:48 -07:00
Mark Thom
96faad1c01 add proper error throwing for call_with_inference_limit/3 (#1296) 2022-02-27 11:38:44 -07:00
Mark Thom
d55d5f15ae compare '[]' in pstr_comparator of compare_term_test (#1299) 2022-02-25 23:57:27 -07:00
Mark Thom
26e4560429 pop pstr offsets from iterator stack in printer (#1290) 2022-02-25 23:36:26 -07:00
Mark Thom
775bd3a08b unify '' to [] in unify_complete_string (#1292, #1288) 2022-02-25 23:01:08 -07:00
Mark Thom
d92d8bce89 recognize [] as equivalent to "" in unify_atom (#1288) 2022-02-22 23:45:58 -07:00
Mark Thom
1b91663244 Merge pull request #1287 from triska/rebis-dev-sgml
FIXED: library(sgml): load_html/3 and load_xml/3 now both work again.
2022-02-22 15:55:03 -07:00
Markus Triska
8fb673e93e use newly available get_n_chars/3 from library(charsio) 2022-02-23 00:03:36 +01:00
Markus Triska
d1372d9b3b FIXED: library(sgml): load_html/3 and load_xml/3 now both work again.
This addresses #1249.
2022-02-23 00:03:27 +01:00
Mark Thom
063f0da565 correct '$skip_max_list/4' for non-lists (#1276) 2022-02-20 23:44:18 -07:00
Mark Thom
c893247107 update setup_call_cleanup tests 2022-02-19 01:00:02 -07:00
Mark Thom
a5adcfff4c adjust dynamic external indices upon retraction, reset dynamic_mode to Next regardless of success or failure 2022-02-19 01:00:02 -07:00
Mark Thom
d3583276b3 throw instantiation_error on variables from (#1283) 2022-02-19 01:00:02 -07:00
Mark Thom
55d8de1b23 delay callable errors in control predicates (#1282) 2022-02-19 00:59:59 -07:00
Mark Thom
5b829636cb build CStr's to vars in write_literal_to_var (#1284) 2022-02-15 22:33:29 -07:00
Mark Thom
68ac92a616 don't unify module-qualified variables to ! (#1281) 2022-02-14 18:46:15 -07:00
Mark Thom
db20cda27a use VecDeque for generating indices during code generation (#1053) 2022-02-11 19:23:43 -07:00
Mark Thom
60dd47c696 add missing fact to beginning of tmember_t/3 (#1275) 2022-02-11 17:25:01 -07:00
Mark Thom
42da543980 group predicate subsequences by first instantiated arg (#1053) 2022-02-08 23:34:42 -07:00
Mark Thom
e4ea547623 print bounded depth partial strings correctly 2022-02-07 14:09:22 -07:00
Mark Thom
33a6c81a07 update setup_call_cleanup tests 2022-02-06 21:46:06 -07:00
Mark Thom
9ba503cd6b use printer cycle detection when printing partial strings (#1263), refactor skip_max_list functions 2022-02-06 21:36:49 -07:00
Mark Thom
f3f3dccf8e reference partial strings properly in read_term (#1271) 2022-02-06 15:14:18 -07:00
Mark Thom
2f0718e885 fix write_canonical on strings (#1233) 2022-02-05 20:40:28 -07:00
Mark Thom
7b8001d060 fix '$skip_max_list'/4 (#1260) 2022-02-05 18:33:30 -07:00
Mark Thom
3c022e4332 fix float formatting (#1233, #1258) 2022-02-05 18:33:27 -07:00
Mark Thom
37e34c5209 reset instruction pointers with calls, make HCPrinter::range_from safe (#1233) 2022-01-31 21:24:19 -07:00
Mark Thom
4b71607215 count cycle lengths in skip_max_list_cycle (#1260) 2022-01-31 18:23:16 -07:00
Mark Thom
e62875ac90 tag length/2 as the source of finite_memory errors in list.pl (#1259) 2022-01-31 18:08:00 -07:00
Mark Thom
835345b89e Merge pull request #1257 from mthom/rebis-dev_improved-length
Improved length/2 and arg/3 range checking
2022-01-30 11:30:16 -07:00
Mark Thom
4ddacc707d add range check to arg/3 (#1250) 2022-01-29 12:50:09 -07:00
Mark Thom
0d653a2ce6 improve '$skip_max_list'/4 and length/2 (#1023, #110) 2022-01-29 12:47:26 -07:00
Mark Thom
3208260ef8 Merge pull request #1254 from triska/valid_dotdotdot
ENHANCED: Make toplevel output a Prolog term that can be read back also for "...".
2022-01-28 11:55:52 -07:00
Markus Triska
2e57789d10 ENHANCED: Make toplevel output a Prolog term that can be read back also for "...".
This addresses #1240.
2022-01-28 18:47:55 +01:00
Mark Thom
b3006f6fd8 inline store & deref calls in '' (#1176) 2022-01-26 23:03:19 -07:00
Mark Thom
142ddcd57a use expand_goal directly for existential-qualified goals in all-solutions predicates (#1246) 2022-01-26 17:34:36 -07:00
Mark Thom
a562793fce don't read into the heap while incrementing self.s (#1233, #1245) 2022-01-25 20:37:29 -07:00
Mark Thom
e6c4ecfc10 lazily throw exceptions of dcg_body from goal-expanded phrase/{2,3} (#1244) 2022-01-22 14:55:18 -07:00
Mark Thom
5ff579f793 recognize []/N as callable (#1241, #989) 2022-01-21 08:10:59 -07:00
Mark Thom
8df346f377 expand phrase/{2,3} using dcg_body whenever possible 2022-01-21 08:10:55 -07:00
Mark Thom
af76068297 module-qualify callables more liberally but not for built-ins (#1243) 2022-01-20 17:40:45 -07:00
Mark Thom
5dddf0a460 dereference car of Lis in HeapPStRIter::step (#1238) 2022-01-19 20:51:23 -07:00
Mark Thom
1854338ff4 throw errors from phrase/{2,3} where expected (#1220) 2022-01-19 20:19:47 -07:00
Mark Thom
11b96875e0 streamline and fix phrase/{2,3} (#1237) 2022-01-19 20:07:15 -07:00
Mark Thom
6462c524f4 Merge pull request #1236 from triska/omit-module-prefix
omit module prefix, because the goals are already module-qualified
2022-01-19 17:22:44 -07:00
Markus Triska
b703303dd4 omit module prefix, because the goals are already module-qualified 2022-01-20 00:48:30 +01:00
Mark Thom
ab77b6b28e Merge pull request #1235 from triska/better-initialization-warning
ENHANCED: more specific warning when initialization/1 fails (#1149)
2022-01-19 16:41:43 -07:00
Markus Triska
0da9d1c036 ENHANCED: more specific warning when initialization/1 fails (#1149) 2022-01-20 00:04:09 +01:00
Mark Thom
88436b8627 Merge pull request #1234 from aarroyoc/ctrld
Fix Ctrl-D in toplevel
2022-01-18 21:34:30 -07:00
Mark Thom
f6116510a1 print -0.0 as 0.0 (#1164) 2022-01-18 21:31:14 -07:00
Mark Thom
5a132aaff4 throw error instead of overwriting builtin export (#1225) 2022-01-18 19:16:14 -07:00
Mark Thom
59992c8af2 remove number/3 from arithmetic.pl (#1170) 2022-01-18 17:38:45 -07:00
Adrián Arroyo Calle
ff3ec78df9 Fix Ctrl-D (#1168) 2022-01-18 19:27:27 +01:00
Mark Thom
b980ae1e8c fix floor for f64 (#1223) 2022-01-17 22:04:10 -07:00
Mark Thom
97b9d488d4 include library(error) in toplevel.pl (#1226) 2022-01-17 21:53:52 -07:00
Mark Thom
3ebf8d5db9 clear alias in close before resetting the stream to null (#1231) 2022-01-17 17:58:14 -07:00
Mark Thom
89e33903b2 Merge pull request #1232 from triska/toplevel_read_from_chars
FIXED: toplevel to use (newly renamed) read_from_chars/2
2022-01-17 17:44:58 -07:00
Markus Triska
6a610ac57d FIXED: toplevel to use (newly renamed) read_from_chars/2 2022-01-18 01:12:47 +01:00
Mark Thom
413f797155 Merge pull request #1228 from triska/charsio-read-renames
MODIFIED: Rename two predicates in library(charsio)
2022-01-17 17:03:46 -07:00
Mark Thom
6c8dc49216 Merge pull request #1229 from triska/faster_decryption
ENHANCED: library(crypto): Retain a compact internal representation of the ciphertext throughout decryption.
2022-01-17 17:03:29 -07:00
Mark Thom
9ded1447ec Merge pull request #1230 from josd/patch-1
Update clpz.pl
2022-01-17 17:03:03 -07:00
Markus Triska
516ed1fd5b ENHANCED: library(crypto): Retain a compact internal representation of the ciphertext throughout decryption.
This allows efficient decryption also of very large files and long
strings.

It is usually highly advisable to stick to common and portable library
predicates such as append/3. However, since append/3 does not yet
recognize this opportunity for improvement, I apply it manually in
this case, so that also very large files can be efficiently decrypted
using the compact internal string representation.

Without this change, decrypting a 1 GB file takes 48 GB of RAM,
whereas with this change, it only takes 2 GB (one for the string, one
for its copy with the appended tag).
2022-01-17 23:02:56 +01:00
Jos De Roo
1a4f8f992b Update clpz.pl
While running with scryer-prolog the resource control file should be ~/.scryerrc
2022-01-17 22:35:31 +01:00
Markus Triska
23adfef281 MODIFIED: library(charsio): read_n_chars/3 is now called get_n_chars/3
This is because "read" is associated with general Prolog terms.
2022-01-17 20:37:55 +01:00
Markus Triska
20b6816562 MODIFIED: library(charsio): read_term_from_chars/2 is now called read_from_chars/2
This is for compatibility with SICStus Prolog and GNU Prolog.
2022-01-17 20:21:18 +01:00
Mark Thom
c6400550e1 dereference second argument of '/2 2022-01-17 00:00:23 -07:00
Mark Thom
f26749ad79 Merge pull request #1224 from triska/working_directory
correct reference to '$working_directory'/2
2022-01-16 15:46:11 -07:00
Markus Triska
177c98fa95 correct reference to '$working_directory'/2 2022-01-16 23:20:43 +01:00
Mark Thom
7baa187863 Merge pull request #1222 from triska/retain_string_of_nil
retain the string "[]" as is, instead of converting it to '[]' (i.e., "")
2022-01-16 11:58:15 -07:00
Markus Triska
11d504e8f4 retain the string "[]" as is, instead of converting it to '[]' (i.e., "")
This addresses #1215.
2022-01-16 17:50:20 +01:00
Mark Thom
83378e4373 deduplicate but do not sort anonymous variables in toplevel (#1196) 2022-01-15 19:24:22 -07:00
Mark Thom
06abe2302b add missing cases to retract_clause (#1214) 2022-01-15 00:51:38 -07:00
Mark Thom
f3e5f7879d allow late dynamic declaration for predicates (#1205) 2022-01-14 16:31:49 -07:00
Mark Thom
bc5125b719 put_complete_string should push the empty list to the heap for empty strings (#1209) 2022-01-14 16:31:49 -07:00
Mark Thom
c6d23f9a0b fix off-by-one error in DynamicIndexedChoice (#1210) 2022-01-14 16:31:22 -07:00
Mark Thom
3b8afce7c7 fix syntax regressions (#1198, #1164) 2022-01-13 23:54:55 -07:00
Mark Thom
39e28f1f2a write plaintext and ciphertext directly to atoms (#1193) 2022-01-13 08:47:56 -07:00
Mark Thom
08363b1d73 Merge pull request #1208 from triska/mention-rebis-dev
add links to the rebis-dev branch and its announcement
2022-01-13 08:03:25 -07:00
Markus Triska
91aa0f200e add links to the rebis-dev branch and its announcement 2022-01-13 08:46:24 +01:00
Mark Thom
d9e190096c delimit partial strings around \x0\ 2022-01-12 22:10:59 -07:00
Mark Thom
4dca86d5cf serialize call_0 test (#1206) 2022-01-12 21:42:26 -07:00
Mark Thom
d3b628bb24 Merge pull request #1207 from triska/semi-deterministic
deterministic --> semi-deterministic
2022-01-12 15:30:24 -07:00
Markus Triska
cfbb05fb1b deterministic --> semi-deterministic 2022-01-12 21:58:23 +01:00
Mark Thom
340d428c88 Merge pull request #1199 from Skgland/do_not_gen_in_src
Generate into $OUT_DIR instead of src/
2022-01-11 23:01:59 -07:00
Mark Thom
d22bbc54c7 Merge pull request #1195 from triska/rebis-dev-format-U
ADDED: format specifier ~NU, using underscores to separate groups of digits
2022-01-11 22:49:38 -07:00
Mark Thom
c5cda99f9d evaluate floats referenced from the heap by tagged pointers (#1203) 2022-01-11 18:42:01 -07:00
Mark Thom
67854e0720 execute trust instead of retry at the end of dynamic choice blocks (#1204, #1173) 2022-01-11 18:24:26 -07:00
Mark Thom
cfe257495a recognize characters as separate from atoms in ''/7 (#1192) 2022-01-10 21:18:11 -07:00
Mark Thom
5f4e701461 render [] as empty string in AtomOrString::as_str() (#1193) 2022-01-10 20:46:00 -07:00
Mark Thom
e3622e0860 improve between_/3 implementation (#1186, #1191) 2022-01-10 18:34:25 -07:00
Mark Thom
f0e6b8ca47 imitate Rc-style equality for TypedArenaPtr (#1190) 2022-01-10 18:25:30 -07:00
Mark Thom
ef0b239e70 correctly print [] functors (#1189) 2022-01-10 17:26:57 -07:00
Skgland
590d80268e only rerun build.rs when something in src/ has changed
by default (when no rerun-if is emitted) build.rs is rerun if something in the package changes
2022-01-10 21:20:07 +01:00
Skgland
a5de329712 don't genrate code in src/
[Outputs of Build Script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script) states that only files in $OUT_DIR may be modified
2022-01-10 21:19:18 +01:00
Markus Triska
2889a4438b ADDED: format specifier ~NL to limit the number of digits per line
Example:

    %?- format("~65L", [2^1000]).
    %@ 10715086071862673209484250490600018105614048117055336074437503883_
    %@ 70351051124936122493198378815695858127594672917553146825187145285_
    %@ 69231404359845775746985748039345677748242309854210746050623711418_
    %@ 77954182153046474983581941267398767559165543946077062914571196477_
    %@ 686542167660429831652624386837205668069376   true.
2022-01-10 17:52:42 +01:00
Markus Triska
f5952088e3 ADDED: format specifier ~NU, using underscores to separate groups of digits
Example:

    ?- format("~2U", [10^12]).
    %@ 10_000_000_000.00   true.
2022-01-10 16:07:05 +01:00
Mark Thom
bcacb49c05 compare bigints by value not by pointer (#1183) 2022-01-09 23:33:26 -07:00
Mark Thom
976b8e426d Merge pull request #1160 from aarroyoc/add-ugraphs-library
Add ugraphs library (ported from SWI)
2022-01-09 12:43:46 -07:00
Mark Thom
90ecd34cfd Merge pull request #1182 from aarroyoc/sockets-arity
fix socket_client_open/3
2022-01-09 12:24:39 -07:00
Adrián Arroyo Calle
35670c8654 remove TLS option in socket_client_open/3 2022-01-09 17:04:54 +01:00
Adrián Arroyo Calle
07bc97fb31 fix socket_client_open/3 2022-01-08 23:31:32 +01:00
Mark Thom
d01806ee2d correct heap offsets in setup_call_cleanup tests 2022-01-08 12:50:09 -07:00
Mark Thom
a54e42961c unify current time as a complete string, not an atom (#1175) 2022-01-08 11:47:35 -07:00
Mark Thom
2e46aa33c0 correct read/2 arity to 2 (#1171) 2022-01-08 00:19:17 -07:00
Mark Thom
d90cf6384c complete handling of control operators in interpreted (,)/2 (#1172) 2022-01-08 00:04:04 -07:00
Adrián Arroyo Calle
af3f676683 Minor fixes 2022-01-07 19:28:07 +01:00
Adrián Arroyo Calle
abf980d603 Merge remote-tracking branch 'upstream/rebis-dev' into add-ugraphs-library 2022-01-07 19:14:34 +01:00
Mark Thom
693b6d2547 add version dependency information to README 2022-01-07 07:52:56 -07:00
Mark Thom
06313cac64 update README.md 2022-01-07 00:17:17 -07:00
Mark Thom
cf1e315d72 add parser tests 2022-01-06 22:09:38 -07:00
Mark Thom
955e1799c8 flatten the instruction dispatch loop 2022-01-06 22:09:36 -07:00
Mark Thom
3db86f1e25 relocate most instruction routines from MachineState to Machine 2022-01-06 21:46:23 -07:00
Mark Thom
6f9b6a29c4 remove LocalCodePtr::IndexingBuf 2022-01-06 21:44:41 -07:00
Mark Thom
b056d40eba module-qualify incomplete goals in expand_goal/3 2022-01-06 21:44:41 -07:00
Mark Thom
708c3bc3ce dereference first argument of (is)/2 2022-01-06 21:44:41 -07:00
Mark Thom
39efc12dc8 generate heap_loc cells to refer to 0-arity atoms in read.rs 2022-01-06 21:44:41 -07:00
Mark Thom
4211151fe6 fix unify_float 2022-01-06 21:44:41 -07:00
Mark Thom
3974b6e6cd dereference variables when looking for string terminators 2022-01-06 21:44:41 -07:00
Mark Thom
b24df6e195 properly iterate over read terms in MachineState::read_term 2022-01-06 21:44:41 -07:00
Mark Thom
bcd33dc8e3 get test suite working 2022-01-06 21:44:41 -07:00
Mark Thom
6c66c236fb fix printing of CStr's 2022-01-06 21:44:41 -07:00
Mark Thom
520121b2b2 remove skeletons from replaced modules 2022-01-06 21:44:41 -07:00
Mark Thom
48c1d05151 use heap_loc to refer to 0-arity atom instead of str_loc 2022-01-06 21:44:41 -07:00
Mark Thom
8ba61a1da1 defer installation of inference counter for call_with_inference_limit til after goals expanded 2022-01-06 21:44:41 -07:00
Mark Thom
cd129e32a7 fix bugs revealed by src/tests/builtins.pl 2022-01-06 21:44:41 -07:00
Mark Thom
2b3e43f160 start to retune testing infrastructure 2022-01-06 21:44:41 -07:00
Mark Thom
d7bf04d2c0 fix off by one bug in system_calls 2022-01-06 21:44:41 -07:00
Mark Thom
4cde8cd501 fix bug in error_form 2022-01-06 21:44:41 -07:00
Mark Thom
fb4e627e62 fix various partial string bugs (copying using them in arg/3) 2022-01-06 21:44:41 -07:00
Mark Thom
ef3a97cedd detect attributed variables by properly detecting them in copy_term/2 2022-01-06 21:44:41 -07:00
Mark Thom
1a86ad5cec upgrade rustyline 2022-01-06 21:44:41 -07:00
Mark Thom
529c401eee don't allow [] as a stream alias, restore domain error on source sink for open/{3,4} 2022-01-06 21:44:41 -07:00
Mark Thom
a87236fea2 keep cursor position after writing to byte stream 2022-01-06 21:44:41 -07:00
Mark Thom
975c1ca62c fix stream errors 2022-01-06 21:44:41 -07:00
Mark Thom
d02b9d848c break from loop upon successful peek in peek_char/1 and peek_code/1 2022-01-06 21:44:41 -07:00
Mark Thom
f340f9ac94 break from loop in get_code upon successful character read 2022-01-06 21:44:41 -07:00
Mark Thom
1b3f290037 throw instantiation error if Arity is a variable in abolish/1 2022-01-06 21:44:41 -07:00
Mark Thom
b551ef315f use strip module in retract/1, a meta-predicate 2022-01-06 21:44:41 -07:00
Mark Thom
10bb6ab3bb restore old thread_goals to fix top-level solutions printing bug 2022-01-06 21:44:41 -07:00
Mark Thom
4af57b0dd3 fix HeapPStrIter bug not recognizing nil focus if PStrLoc points to PStrOffset to CStr 2022-01-06 21:44:41 -07:00
Mark Thom
bc613eeff9 fix number not recognizing floats 2022-01-06 21:44:41 -07:00
Mark Thom
7507e88406 detect module resolved cut in interpreted (,) 2022-01-06 21:44:41 -07:00
Mark Thom
073f281f1e fix arg/3 bug 2022-01-06 21:44:41 -07:00
Mark Thom
3355b49724 add bounds check for attributed variables slice 2022-01-06 21:44:41 -07:00
Mark Thom
0e2db4a23e tag DCG constructs with module names for proper resolution 2022-01-06 21:44:41 -07:00
Mark Thom
addc817cca break from get_char loop after successful char unification 2022-01-06 21:44:41 -07:00
Mark Thom
a0a86d0f62 unmark cell bits in occurs check 2022-01-06 21:44:41 -07:00
Mark Thom
b24e7cce38 support comparison and unification of cyclic partial strings 2022-01-06 21:44:41 -07:00
Mark Thom
ffd1b7069f greatly reduce the number of goal expansions done in callable if/then/else 2022-01-06 21:44:41 -07:00
Mark Thom
0404c3bd94 use new heap term representation 2022-01-06 21:44:38 -07:00
Mark Thom
d0b74a95f4 Merge pull request #1156 from mthom/proper_var_list_order_issue_1121
Correct order of variables in read_term/3 equation and variable lists
2022-01-06 20:46:59 -07:00
Adrián Arroyo Calle
0288d5dc19 Add ugraphs library 2021-12-31 12:56:24 +01:00
Mark Thom
9d06229cba create read_term/3 variable lists in order of variable occurrence within terms 2021-12-23 13:31:49 -07:00
Mark Thom
c60ada8421 Merge pull request #1132 from triska/tls_library
ADDED: library(tls) for negotiating TLS connections
2021-12-13 19:11:04 -07:00
Mark Thom
74a1d5cf38 Merge pull request #1141 from triska/layout_text_sequence
ENHANCED: Support also comments in integers with underscores
2021-12-13 19:09:37 -07:00
Mark Thom
43532e5322 Merge pull request #1142 from triska/s
report time with "s" instead of "seconds", in analogy to time(1)
2021-12-13 19:09:20 -07:00
Mark Thom
68cd1d6631 Merge pull request #1143 from heydtn/patch-1
Fix typo in abnf_lwsp/2
2021-12-13 19:04:46 -07:00
Mark Thom
afc18cc390 Merge pull request #1147 from triska/pio_improvements
ENHANCED: Use newly available fast chars test from library(error).
2021-12-13 19:04:27 -07:00
Markus Triska
57d15936cb ENHANCED: Use newly available fast chars test from library(error). 2021-12-12 17:43:17 +01:00
Nate Heydt
14406dbf76 Fix typo in abnf_lwsp/2 2021-12-09 07:42:48 -08:00
Markus Triska
12c561cee0 report time with "s" instead of "seconds", in analogy to time(1)
This addresses https://github.com/mthom/scryer-prolog/pull/1131#issuecomment-988670049 .
2021-12-08 16:13:54 +01:00
Markus Triska
f79b8a1ca5 ENHANCED: support full layout text sequence (also comments) in integers with underscores
Example:

    ?- X = 1_/**/2.
    %@    X = 12.

Following the comment in https://github.com/mthom/scryer-prolog/pull/1112#issuecomment-981540485
2021-12-08 10:42:19 +01:00
Markus Triska
637daa5bda remove redundant test: '\n' is a layout char. 2021-12-08 10:37:37 +01:00
Mark Thom
2eae6b4be7 Merge pull request #1131 from triska/cpu_time
walltime --> CPU time
2021-12-07 20:30:00 -07:00
Markus Triska
dc5e935ecd use newly available predicates from library(tls) for HTTPS 2021-12-05 18:16:47 +01:00
Markus Triska
538085169a ADDED: library(tls), providing all predicates for TLS connections.
The currently available predicates for TLS-connections can be extended
with predicates to load and reason about certificates etc.
2021-12-05 18:16:47 +01:00
Markus Triska
7e8a635e7e implement tls_client_negotiate/3 for explicit negotiation 2021-12-05 17:39:22 +01:00
Markus Triska
74e76b6f97 MODIFIED: Remove TLS-related predicates from library(sockets).
They will become available in a new library, library(tls).
2021-12-05 17:39:22 +01:00
Markus Triska
cb6309d370 walltime --> CPU time 2021-12-05 00:56:16 +01:00
Mark Thom
8065889862 Merge pull request #1129 from triska/tls_servers
ADDED: Support for creating TLS servers.
2021-12-04 16:23:43 -07:00
Mark Thom
e7a8950d09 Merge pull request #1124 from triska/test_corrections
several corrections to test cases
2021-12-04 16:23:31 -07:00
Mark Thom
88e9dc2177 Merge pull request #1127 from triska/retract_correction
Correct retract/1 issues due to module qualification
2021-12-04 16:23:00 -07:00
Mark Thom
2c555c969e Merge pull request #1122 from triska/better_time
ENHANCED: Better reporting for time/1.
2021-12-04 16:22:14 -07:00
Markus Triska
77c04c3a14 ADDED: Support for creating TLS servers.
The new predicates tls_server_context/2 and tls_server_negotiate/3 can
be used to negotiate TLS connections with clients for encrypted and
authenticated communication.
2021-12-03 16:45:27 +01:00
Markus Triska
48cea6efdf FIXED: retract/1 issues due to module qualification
This addresses #1125.
2021-12-01 21:46:12 +01:00
Markus Triska
89a90d9522 ENHANCED: Better reporting for time/1.
This addresses #378.
2021-12-01 21:23:00 +01:00
Markus Triska
0026f3fdef use anonymous variable 2021-12-01 20:54:06 +01:00
Markus Triska
ee054fd99c several corrections to test cases 2021-12-01 19:45:36 +01:00
Mark Thom
7abdade7c1 Merge pull request #1120 from triska/char_type_correction
ENHANCED: Correct type error for char_type/2.
2021-11-29 19:38:30 -05:00
Markus Triska
79a50de697 ENHANCED: Correct type error for char_type/2.
This addresses #905.
2021-11-29 19:33:22 +01:00
Mark Thom
e47aef5615 Merge pull request #1116 from aarroyoc/fix-open-lis
Allow all kinds of string to be processed in open/4
2021-11-28 16:18:02 -05:00
Mark Thom
b96ae1bac0 Merge pull request #1119 from mthom/expand_call_goals_as_call_goals
Expand call goals as call goals so that goals in control constructs are qualified properly
2021-11-28 16:16:47 -05:00
Mark Thom
7dafcb0860 expand call goals as call goals (#1114) 2021-11-28 10:27:50 -07:00
Mark Thom
5a6a686f42 Merge pull request #1117 from triska/indicate_failed_initialization
ENHANCED: indicate failed initialization/1 goal
2021-11-28 11:53:54 -05:00
Mark Thom
b576bb55ef Merge pull request #1115 from triska/get_char_type_test
ENHANCED: Character type checks for get_char/[1,2].
2021-11-28 11:53:15 -05:00
Markus Triska
fc8205d375 ENHANCED: indicate failed initialization/1 goal
This addresses #1109.
2021-11-28 14:50:42 +01:00
Adrián Arroyo Calle
7eb0669de5 Fix use_module import errors 2021-11-28 13:20:09 +01:00
Adrián Arroyo Calle
86161ccf2a Allow all kinds of string to be processed in open/4 2021-11-28 12:37:16 +01:00
Markus Triska
5e55732cb0 ENHANCED: Character type checks for get_char/[1,2].
This addresses #906.
2021-11-28 10:49:40 +01:00
Mark Thom
a87f0481b8 Merge pull request #1096 from aarroyoc/number_chars_fix
Prevents panic in some strange cases. Seen in #721
2021-11-27 22:37:30 -05:00
Mark Thom
c3d61361f8 Merge pull request #1112 from triska/underscores_in_integers
ENHANCED: Support '_' followed by layout text sequence in integers.
2021-11-27 20:29:49 -05:00
Mark Thom
a48934e31c Merge pull request #1113 from triska/seq
Use newly available seq//1 and ... //0 in several libraries
2021-11-27 20:29:31 -05:00
Mark Thom
ac75f67e2a Merge pull request #1111 from triska/fast_list_test
Use '$skip_max_list'/4 for fast list tests in can_be/2 and must_be/2
2021-11-27 20:29:17 -05:00
Markus Triska
45cfa6c8d8 use seq//1 2021-11-27 16:32:45 +01:00
Markus Triska
25a06b0bea use seq//1 and ... //0 which are now available in library(dcgs) 2021-11-27 16:32:44 +01:00
Markus Triska
91af72e8b1 use seq//1 2021-11-27 16:17:45 +01:00
Markus Triska
fd9b354c70 use seq//1 which is now available in library(dcgs) 2021-11-27 16:17:15 +01:00
Markus Triska
1647e67dd4 ENHANCED: Support '_' followed by layout text sequence in integers.
This is handy for writing large integers, for example in cryptographic
applications.

This addresses #994.

Examples:

    ?- X = 1_000_000.
    %@    X = 1000000.

    ?- X = 1_
    000_
    000.
    %@    X = 1000000.
2021-11-27 10:09:39 +01:00
Markus Triska
803e120a51 use must_be(list, ...) earlier, since it is now faster 2021-11-26 17:11:51 +01:00
Markus Triska
6ba374c62b ENHANCED: use '$skip_max_list'/4 for fast list tests in can_be/2 and must_be/2
This also (partially) addresses #1108.
2021-11-26 17:11:35 +01:00
Mark Thom
ca28f24e42 Merge pull request #1107 from triska/fast_chars_test
New type tests: must_be(chars, ...) and can_be(chars, ...)
2021-11-25 19:01:03 -05:00
Markus Triska
0d4c38138a use newly available must_be(chars, ...) for fast string tests 2021-11-22 20:00:06 +01:00
Markus Triska
fe291e90f0 use newly available must_be(chars, ...) for fast string tests 2021-11-22 19:58:36 +01:00
Markus Triska
220e1e8d83 ADDED: must_be(chars, ...) and can_be(chars, ...) for string tests.
Internal features of Scryer Prolog are used to make these tests fast.
2021-11-22 19:55:34 +01:00
Mark Thom
2c0fb3adb0 Merge pull request #1098 from triska/format_improvements
Various smaller improvements to library(format)
2021-11-21 15:28:32 -05:00
Mark Thom
b851eefb03 Merge pull request #1099 from aarroyoc/uninstantiation_error-missing
Fix uninstantiation_error missing. Fix #1031
2021-11-21 15:27:38 -05:00
Mark Thom
eaad2d8b1f Merge pull request #1100 from aarroyoc/phrase-to-file-options
Add phrase_to_file/3 (phrase_to_file with Options)
2021-11-21 15:27:17 -05:00
Mark Thom
575d235296 Merge pull request #1102 from triska/meta_predicate_corrections
Meta predicate corrections
2021-11-21 15:27:03 -05:00
Markus Triska
faf74519dc use round brackets for meta_predicate/1 declaration 2021-11-20 22:43:53 +01:00
Markus Triska
66becaf91c FIXED: meta_predicate/1 declaration of cond_t/3. 2021-11-20 22:43:33 +01:00
Markus Triska
6610ba67c4 FIXED: meta_predicate/1 declaration of (',')/3 and (;)/3. 2021-11-20 22:43:07 +01:00
Markus Triska
e05dd5ebb5 FIXED: meta_predicate/1 declaration for tfilter/3. 2021-11-20 22:39:38 +01:00
Markus Triska
cf77f29988 FIXED: meta_predicate/1 declaration for tmember_t/3. 2021-11-20 22:38:27 +01:00
Markus Triska
2be8ed886b FIXED: meta_predicate/1 declaration for tmember/2. 2021-11-20 22:37:59 +01:00
Markus Triska
21e5b0ab52 FIXED: meta_predicate/1 declaration for tpartition/4.
This addresses #1101.
2021-11-20 22:37:31 +01:00
Markus Triska
d72cb74ffa mention phrase_to_file/3 which is being prepared in #1100 2021-11-17 21:33:15 +01:00
Markus Triska
3c988d555f 'f' --> f 2021-11-17 21:20:40 +01:00
Markus Triska
5981a65cc2 better layout 2021-11-17 21:20:40 +01:00
Markus Triska
9900762747 use newly available seq//1 from library(dcgs)
I am using seq(Ls) instead of plain Ls so that DCGs can be debugged
declaratively, by generalizing away nonterminals in rules.
2021-11-17 21:20:40 +01:00
Adrián Arroyo Calle
0db2ca6659 Fix mistake in phrase_to_file/2 definition 2021-11-17 08:36:39 +01:00
Adrián Arroyo Calle
8e68626f14 Add phrase_to_file/3 (phrase_to_file with Options) 2021-11-16 23:54:04 +01:00
Adrián Arroyo Calle
72a88d1f91 Fix uninstantiation_error missing. Fix #1031 2021-11-16 23:22:24 +01:00
Markus Triska
bd75e9c184 more elegant solution for parsing numeric arguments, using a DCG 2021-11-16 18:25:35 +01:00
Markus Triska
23df16ecf9 mention the format("~s", [Ls]) pattern and new library(pio) predicates 2021-11-16 18:20:58 +01:00
Adrián Arroyo Calle
387732d2f9 Prevents panic in some strange cases. Seen in #721 2021-11-15 00:17:40 +01:00
Mark Thom
75b01d5021 Merge pull request #1082 from pmoura/fix_format_predicates_missing_numbervars_option_on_w_and_q_formats
Fix the format/2-3 predicates missing the numbervars(true) option in the ~w and ~q formats
2021-11-13 00:05:26 -05:00
Mark Thom
b7fa5db570 Merge pull request #1087 from Skgland/fix_beta_check
fix failing lint warnings in beta build
2021-11-13 00:04:51 -05:00
Mark Thom
297f126f66 Merge pull request #1078 from triska/pio_improvements
Various improvements for pure output
2021-11-13 00:03:57 -05:00
Mark Thom
bd6400f17f Merge pull request #1086 from Skgland/pass_-f_flag_in_cargo_test
pass -f to scryer-prolog in cargo test so that we ignore .scryerrc
2021-11-13 00:03:38 -05:00
Mark Thom
21e55023a4 Merge pull request #1088 from triska/call_nth_metapredicate
FIXED: meta_predicate/1 directive for call_nth/2.
2021-11-13 00:03:26 -05:00
Skgland
49e024bdd8 remove unused fields instead, prompting more dead_code removal 2021-11-11 19:32:35 +01:00
Markus Triska
57877107d8 use functional notation for all meta_predicate/1 directives 2021-11-11 19:29:32 +01:00
Markus Triska
e9b4a99c8f FIXED: meta_predicate/1 directive for call_nth/2.
This addresses #1021.
2021-11-11 19:26:27 +01:00
Skgland
7bc4876071 fix failing lint warnings in beta build 2021-11-11 18:53:08 +01:00
Skgland
e7899ee15e pass -f to scryer-prolog in cargo test so that we ignore .scryerrc
fixes issue #1085
2021-11-11 11:37:05 +01:00
Paulo Moura
7ea20d9ce9 Fix the format/2-3 predicates missing the numbervars(true) option in the ~w and ~q formats 2021-11-08 22:00:02 +00:00
Markus Triska
3045f327d5 FIXED: instantiation errors for alias(Var) in open/4 options
This addresses #1030.
2021-11-08 22:41:04 +01:00
Markus Triska
2d1f182c49 FIXED: instantiation errors for type(Var) in open/4 options
This addresses #1030.
2021-11-08 22:37:46 +01:00
Markus Triska
0677f51717 add motivation and comments about library(pio) predicates 2021-11-08 22:18:30 +01:00
Markus Triska
a9bfeb0e96 use newly available library predicate read_n_chars/3 2021-11-08 21:51:03 +01:00
Markus Triska
c44d27fb7f mention pure output predicates in the README 2021-11-08 20:29:39 +01:00
Markus Triska
a0a01b8ba7 ADDED: library(format): DCG nonterminal portray_clause_//1, in analogy to format_//2. 2021-11-07 17:47:05 +01:00
Markus Triska
e32215e19a express format/3 and portray_clause/2 in terms of phrase_to_stream/2 2021-11-07 17:47:05 +01:00
Markus Triska
893fb0e3cc ADDED: phrase_to_stream/2, writing a list of characters to a stream. 2021-11-07 17:44:45 +01:00
Mark Thom
1d2a838717 Merge pull request #1077 from pmoura/fix_get_code_predicates_at_end_of_file
Fix the get_code/1-2 predicates to return -1 at the end of stream as per standard
2021-11-07 09:40:29 -05:00
Mark Thom
8457a19792 Merge pull request #1071 from triska/read_n_chars
ADDED: read_n_chars/3, reading N characters from a stream.
2021-11-07 09:40:03 -05:00
Mark Thom
0b2638b201 Merge pull request #1070 from triska/open_stream
ENHANCED: open/4 to allow opening a stream by specifying stream(S).
2021-11-07 09:39:41 -05:00
Mark Thom
4dce57a1b6 Merge pull request #1069 from triska/crypto_improvements
Performance improvements for library(crypto)
2021-11-07 09:39:13 -05:00
Paulo Moura
658b835a70 Fix the get_code/1-2 predicates to return -1 at the end of stream 2021-11-06 19:41:25 +00:00
Markus Triska
52af955463 import also partial_string/3 (used in #1071) 2021-11-04 18:50:40 +01:00
Markus Triska
09e886db0b ADDED: read_n_chars/3, reading N characters from a stream. 2021-11-04 18:36:27 +01:00
Markus Triska
f668640e3d move error handling to Prolog by using the new '$first_non_octet'/2 2021-11-04 18:35:22 +01:00
Markus Triska
afcd44deaa ENHANCED: open/4 to allow opening a stream by specifying stream(S).
This allows switching standard output to binary, using for example:

  ?- current_output(S0), open(stream(S0), write, S, [type(binary)]).

format/3 can then be used to write binary data to S. This is needed
for example when piping binary data to other programs.

This addresses #614, please read the discussion for more information.

The current implementation is very preliminary: Specifically, it works
by destructively modifiying the parameters of the underlying stream,
making it no longer usable in its original mode. Currently, if the
type of standard output is set to binary, then the toplevel no longer
works. Therefore, after writing binary output to standard output,
the program should either halt, or set the stream type back to text.
2021-11-04 18:33:40 +01:00
Markus Triska
8c8c21c63b use partial_string/1 for much quicker test 2021-11-04 00:12:00 +01:00
Markus Triska
55dabbe16a use '$first_non_octet'/2 for much faster domain check 2021-11-04 00:12:08 +01:00
Markus Triska
494bd7b79c ADDED: '$first_non_octet'/2, for much more efficient domain checks in library(crypto).
'$first_non_octet'(Cs, C) <=> C is the leftmost character in the
string Cs whose character code is not in 0..255.
2021-11-04 00:12:00 +01:00
Markus Triska
320ee072e6 ENHANCED: Much faster Base64 encoding/decoding, using partial_string/1 for a quick check. 2021-11-03 22:07:20 +01:00
Mark Thom
67ef5fe8e6 Merge pull request #1065 from aarroyoc/pio-string
Disable check of atom and leverage to open/4 the domain_error
2021-11-03 13:27:45 -02:30
Mark Thom
7c5c700bb8 Merge pull request #1066 from aarroyoc/rust-2021
Rust 2021
2021-11-03 13:27:18 -02:30
Adrián Arroyo Calle
dd51908439 Rust 2021 2021-11-01 23:03:51 +01:00
Adrián Arroyo Calle
6a0f638d40 Disable check of atom and leverage to open/4 the domain_error 2021-10-29 23:52:08 +02:00
Adrián Arroyo Calle
2480c6633c Disable check of atom and leverage to open/4 the domain_error 2021-10-29 23:51:30 +02:00
Paulo Moura
495025dafb Add support for the float_integer_part/1 and float_fractional_part/1 standard arithmetic functions 2021-10-24 09:10:38 +01:00
Mark Thom
ca62e54652 Merge pull request #1052 from aarroyoc/shell-predicate
Implement shell/1 and shell/2
2021-10-17 11:58:28 -06:00
Adrián Arroyo Calle
44dd9ae9fb Go back and accept only list of chars 2021-10-15 17:22:15 +02:00
Adrián Arroyo Calle
3f4d62952a Accept atom or shell 2021-10-14 22:52:29 +02:00
Adrián Arroyo Calle
391cda919f Implement shell/1 and shell/2 2021-10-11 22:35:05 +02:00
Mark Thom
44fc61ed86 Merge pull request #1051 from aarroyoc/close-stream
Throw exception if closing a closed TCP stream #1046
2021-10-07 17:09:16 -06:00
Adrián Arroyo Calle
f70685d53c Close Stream test feedback 2021-09-30 23:46:52 +02:00
Adrián Arroyo Calle
807abfef4f Close Stream bug files 2021-09-30 23:01:25 +02:00
Adrián Arroyo Calle
810d4c51f9 Close Stream bug files 2021-09-30 22:59:15 +02:00
Mark Thom
1a0684cd20 Merge pull request #1049 from pmoura/add_preliminary_current_module_predicate_definition
Add preliminary current_module/1 predicate definition requiring a bound argument
2021-09-30 09:19:09 -06:00
Adrián Arroyo Calle
47d811c250 use shutdown error values to throw exceptions in close stream 2021-09-30 00:10:03 +02:00
Adrián Arroyo Calle
4d0998ef72 launch exception if closing a closed TCP stream #1046 2021-09-28 22:48:51 +02:00
Mark Thom
5d2b0377d8 reset attributed variables queue when backtracking (#678, etc.) 2021-09-27 19:12:24 -06:00
Mark Thom
f6d69b6051 reset attributed variables queue after successful verify_attributes interrupt (#669, etc) 2021-09-26 18:58:00 -06:00
Paulo Moura
490496f381 Add preliminary current_module/1 predicate definition requiring a bound argument 2021-09-24 10:13:00 +01:00
Mark Thom
bc4f719931 Merge pull request #1045 from triska/phrase_to_file
ADDED: Rudimentary version of phrase_to_file/2 in library(pio)
2021-09-05 23:31:57 -06:00
Markus Triska
ded4a75b9c use round brackets for meta_predicate declarations
This is because meta_predicate is not a standard operator.
2021-09-04 22:02:17 +02:00
Markus Triska
9e75eb35a0 ADDED: Rudimentary version of phrase_to_file/2 in library(pio)
See #691 for more information.
2021-09-04 21:13:51 +02:00
Mark Thom
326fb99849 Merge pull request #1033 from aarroyoc/fix-1022
Add a -f switch to load alternative initialization files
2021-08-23 22:26:15 -06:00
Mark Thom
fe1ced9f58 Merge pull request #1032 from aarroyoc/fix-1009
Fix #1009 by providing a naive num-bigint implementation of count_ones
2021-08-23 22:25:44 -06:00
Adrián Arroyo Calle
00d0502cbd Rename init_file to disable_init_file 2021-08-23 09:53:15 +02:00
Adrián Arroyo Calle
c30bd51b91 use consult instead of use_module 2021-08-22 11:44:17 +02:00
Adrián Arroyo Calle
9391dd9d51 Rename to disable_init_file and change description 2021-08-22 11:36:27 +02:00
Adrián Arroyo Calle
3cd112b60f PR feedback 2021-08-21 17:53:20 +02:00
Adrián Arroyo Calle
dce0c43e26 Read scryerrc if goals specified but not -f specified 2021-08-20 14:15:16 +02:00
Adrián Arroyo Calle
80e228f236 Clean the code 2021-08-20 14:06:57 +02:00
Adrián Arroyo Calle
8ee2545b05 Add a -f switch to load alternative initialization files 2021-08-20 14:00:32 +02:00
Adrián Arroyo Calle
9bcc56e337 Make it line 2021-08-20 12:40:27 +02:00
Adrián Arroyo Calle
3c5a94452a Fix #1009 by providing a naive num-bigint implementation of count_ones 2021-08-20 12:38:15 +02:00
Mark Thom
fce7f8aa68 Merge pull request #1029 from triska/format
ENHANCED: Domain error non_empty_list for empty arguments, addressing #1024
2021-08-15 08:59:06 -06:00
Markus Triska
9e13f18463 ENHANCED: Domain error non_empty_list for empty arguments, addressing #1024.
Example:

    ?- format("~d", []).
    %@ caught: error(domain_error(non_empty_list,[]),format_//2)
2021-08-15 12:29:28 +02:00
Mark Thom
2905f6b465 Merge pull request #1027 from triska/format
ENHANCED: format_string domain error for invalid radix in format string
2021-08-14 23:06:28 -06:00
Markus Triska
9d3f3eb013 ENHANCED: format_string domain error for invalid radix in format string
This addresses #1024.

Example:

    ?- format("hello ~0r!", [12]).
    %@ caught: error(domain_error(format_string,"~0r"),format_//2)
2021-08-14 20:04:07 +02:00
Mark Thom
75b5afa759 Merge pull request #1026 from triska/format
ENHANCED: If N is omitted in ~Nr or ~NR, it defaults to 8.
2021-08-14 09:15:30 -06:00
Markus Triska
78c2f19e72 ENHANCED: If N is omitted in ~Nr or ~NR, it defaults to 8.
This is for compatibility with Quintus, SICStus and GNU Prolog,
addressing #1024.

Example:

    ?- format("~r", [10]).
    %@ 12   true.
2021-08-14 13:48:21 +02:00
Mark Thom
9a66a626f7 run user-level and module-level initialization goals from loader.pl (#1012) 2021-08-01 09:25:55 -06:00
Mark Thom
f42b7f4efa Merge pull request #1001 from triska/master
ADDED: ... //0, describing an arbitrary number of elements
2021-07-08 14:44:29 -06:00
Markus Triska
bf9654e138 ADDED: ... //0, describing an arbitrary number of elements
This is a very versatile nonterminal. For instance, repeated elements:

    ?- phrase((...,[E],...,[E],...), "hello!!").
    %@    E = l
    %@ ;  E = !
    %@ ;  false.
2021-07-03 09:54:01 +02:00
Mark Thom
4decd1d784 Merge pull request #996 from triska/master
address #995: wrong results for popcount/1
2021-06-22 11:56:56 -06:00
Markus Triska
3e7cd24814 address #995: wrong results for popcount/1
Many thanks to @notoria and @flexoron for very useful test cases!
2021-06-21 21:19:37 +02:00
Mark Thom
3e0bece53a Merge pull request #993 from triska/master
ADDED: popcount(+Integer)
2021-06-18 18:13:30 -06:00
Mark Thom
c1b89b3b06 Merge pull request #986 from Regan-Koopmans/981
Add popcount/2
2021-06-18 18:13:18 -06:00
Regan-Koopmans
f5eadb2957 981 Prefer must_be/2 2021-06-18 08:22:43 +02:00
Markus Triska
ee393c66dd ADDED: popcount(+Integer)
Example:

    ?- X #= popcount(3+5).
       X = 1.

This builds on #986 provided by @Regan-Koopmans. Many thanks!
2021-06-17 20:18:36 +02:00
Regan-Koopmans
72a7765b58 981 Reimplement as library system call 2021-06-17 12:10:25 +02:00
Mark Thom
176daeec03 Merge pull request #983 from triska/master
check for correct domain of integers in reifiable expressions also in the expanded code
2021-06-03 18:32:48 -06:00
Markus Triska
066f740819 check for correct domain of integers in reifiable expressions also in the expanded code
This is to preserve domain errors instead of failing silently. Example:

   ?- 5 #> 3 #<==> 2.
   %@ caught: error(domain_error(clpz_reifiable_expression,2),unknown(2)-1)
2021-06-03 22:57:58 +02:00
Mark Thom
04121644a3 Merge pull request #978 from Skgland/master
fix beta build and tests
2021-06-03 12:38:18 -06:00
Mark Thom
1e37a0d9e6 Merge pull request #982 from triska/master
ENHANCED: Goal expansion for reified constraints.
2021-06-03 12:35:31 -06:00
Markus Triska
fc8d33a98a ENHANCED: Goal expansion for reified constraints.
Used in package precautionary by @dcnorris.
2021-06-03 20:26:44 +02:00
Skgland
2089727c7f ignore setup_call_cleanup tests as their output is apparently non-deterministic 2021-06-02 17:41:14 +02:00
Skgland
fbbf705d10 fix tests 2021-06-02 17:15:31 +02:00
Skgland
e08c302756 fix beta build 2021-06-02 16:43:10 +02:00
Mark Thom
87ef3519d9 Merge pull request #972 from pmoura/add_pid_predicate
Add pid/1 predicate to the os library
2021-05-19 14:09:21 -06:00
Mark Thom
9002c33046 leave the expansion of incomplete goals in meta-predicates to call/N (#967, #970) 2021-05-19 14:07:46 -06:00
Paulo Moura
b9ad6f4fd2 Add pid/1 predicate to the os library 2021-05-18 20:05:30 +01:00
Mark Thom
57db17853e Merge pull request #971 from pmoura/add_rename_file_predicate
Add rename_file/2 predicate to the files library
2021-05-18 12:49:52 -06:00
Paulo Moura
58555d598b Add rename_file/2 predicate to the files library 2021-05-18 18:08:30 +01:00
Mark Thom
0eeae24049 Merge pull request #968 from pmoura/add_make_directory_path_predicate
Add make_directory_path/1 predicate to the files library
2021-05-18 10:26:06 -06:00
Mark Thom
3def7c66ad Merge pull request #969 from pmoura/add_delete_directory_predicate
Add delete_directory/1 predicate to the files library
2021-05-18 10:25:52 -06:00
Paulo Moura
eeac3bc436 Add delete_directory/1 predicate to the files library 2021-05-18 08:41:19 +01:00
Paulo Moura
bdebc7f32e Add make_directory_path/1 predicate to the files library 2021-05-18 00:21:11 +01:00
Mark Thom
e7d6811948 Merge pull request #965 from pmoura/fix_current_predicate_error_checking
Fix current_predicate/1 predicate error checking
2021-05-16 23:37:20 -06:00
Paulo Moura
0e263dd753 Fix current_predicate/1 predicate error checking 2021-05-16 23:49:21 +01:00
Mark Thom
56bbcb1cb3 Merge pull request #956 from pmoura/fix_subsumes_term_predicate
Fix subsumes_term/2 predicate to use unify_with_occurs_check/2 instead of (=)/2
2021-05-13 23:18:58 -06:00
Mark Thom
f02648022a Merge pull request #960 from triska/master
FIXED: correct propagation of tuples_in/2 (#929)
2021-05-13 23:18:47 -06:00
Mark Thom
9bb1f4e6f8 Merge pull request #958 from pmoura/fixes_for_retract_predicates
Fixes for retract predicates
2021-05-13 23:18:36 -06:00
Mark Thom
d219f0bdc6 Merge pull request #957 from pmoura/fix_at_end_of_stream_predicate_missing_check_for_instantiation_error
Fix at_end_of_stream/1 predicate missing check for instantiation error
2021-05-13 23:17:59 -06:00
Mark Thom
c8d0f6ff20 Merge pull request #955 from pmoura/fix_abolish_predicate_throw_of_instantiation_error
Fix abolish/1 predicate throw of instantiation_error
2021-05-13 23:17:30 -06:00
Mark Thom
2813c75292 Merge pull request #954 from pmoura/fix_set_stream_position_exception_term_missing_argument
Fix set_stream_position/2 predicate missing argument in exception term
2021-05-13 23:17:12 -06:00
Markus Triska
581e055359 FIXED: correct propagation of tuples_in/2 (#929)
Many thanks to @notoria for producing a very short test case.
2021-05-13 21:48:43 +02:00
Paulo Moura
88a2cfc5e1 Fix retract_clause/2 internal predicate to correctly handle module qualification and no lose body bindings 2021-05-12 23:48:12 +01:00
Paulo Moura
fb29830521 Fix retractall/1 predicate to retract both facts and rules 2021-05-12 23:46:05 +01:00
Paulo Moura
6540fea4da Fix at_end_of_stream/1 predicate missing check for instantiation error 2021-05-12 21:17:11 +01:00
Paulo Moura
4fd33b015e Fix subsumes_term/2 predicate to use unify_with_occurs_check/2 instead of (=)/2 2021-05-12 20:02:09 +01:00
Paulo Moura
d2fcdb3b6c Fix abolish/1 predicate throw of instantiation_error 2021-05-12 19:39:20 +01:00
Paulo Moura
c2fe0876c2 Fix set_stream_position/2 predicate missing argument in exception term 2021-05-12 19:32:24 +01:00
Mark Thom
39aebd7144 Merge pull request #952 from panasenco/dockerfile
Made rust version in Dockerfile static
2021-05-12 11:02:38 -06:00
panasenco
6a7d0b8c0a Made rust version in Dockerfile static, this seems to have really fixed the cache issues 2021-05-11 22:46:11 -07:00
Mark Thom
7b92bee596 Merge pull request #951 from pmoura/add_max_arity_prolog_flag
Add max_arity Prolog flag
2021-05-11 19:22:38 -06:00
Paulo Moura
f7eda362c7 Add max_arity Prolog flag 2021-05-12 00:34:47 +01:00
Mark Thom
0fb8459bc1 Merge pull request #948 from pmoura/fix_bounded_and_integer_rounding_function_flags_for_current_prolog_flag
Fix querying bounded and integer_rounding_function flag values
2021-05-11 16:55:36 -06:00
Paulo Moura
42d9b57733 Fix querying bounded and integer_rounding_function flag values 2021-05-11 12:08:11 +01:00
Mark Thom
ebe143d9c9 Merge pull request #946 from pmoura/fix_char_code_predicate_error_term_on_bould_non_atom_first_argument
Fix char_code/2 predicate wrong error term when the first argument is bound but is not an atom
2021-05-10 14:42:13 -06:00
Paulo Moura
8acbdfbf1d Fix char_code/2 predicate wrong error term when the first argument is bound but is not an atom 2021-05-10 21:27:04 +01:00
Mark Thom
6eb36226b1 Merge pull request #934 from panasenco/dockerfile
Dockerfile update: Switched from using @LukeMathWalker's image to using the official Rust image.
2021-05-10 11:10:39 -06:00
Mark Thom
21984f0bbe Merge pull request #938 from pmoura/fix_bitwise_shift_functions_type_error_in_second_argument
Fix bitwise shift functions type error in the second argument
2021-05-10 11:10:20 -06:00
Mark Thom
5eac945bc0 Merge pull request #937 from pmoura/fix_open_predicate_error_term_on_bound_stream_argument
Fix open/3-4 predicates error term when the stream argument is bound
2021-05-10 11:10:12 -06:00
Mark Thom
2736b4198a Merge pull request #936 from pmoura/fix_throw_1_control_construct_with_var_argument
Fix throw/1 control construct to throw an instantiation error when the argument is not bound
2021-05-10 11:09:59 -06:00
Mark Thom
a4f2f7faa6 Merge pull request #939 from pmoura/fix_missing_argument_in_current_op_3_predicate_exception_term
Fix missing argument in current_op/3 predicate exception term
2021-05-10 11:09:44 -06:00
Mark Thom
94923175a8 Merge pull request #940 from pmoura/fix_power_infix_operator_type_as_per_standard
Fix (**)/2 operator type
2021-05-10 11:09:23 -06:00
Mark Thom
f1c629e7bf Merge pull request #944 from triska/master
FIXED: module qualification for between/3 in goal expansion (#941)
2021-05-10 11:09:09 -06:00
Mark Thom
5d0c60bd24 Merge pull request #945 from pmoura/fix_char_code_error_checking
Fix char_code/2 predicate failure instead of exception on non-integer second argument
2021-05-10 11:08:58 -06:00
Mark Thom
59f08cd651 Merge pull request #942 from pmoura/fix_op_3_predicate_operator_priority_domain_error
Fix op/3 predicate operator_priority domain error
2021-05-10 11:07:04 -06:00
Paulo Moura
63db194140 Fix char_code/2 predicate failure instead of exception on non-integer second argument 2021-05-10 00:37:09 +01:00
Markus Triska
38db8d4e1a FIXED: module qualification for between/3 in goal expansion (#941)
Many thanks to @dcnorris for reporting this issue!
2021-05-09 23:54:37 +02:00
Paulo Moura
c2e8cbb846 Fix op/3 predicate operator_priority domain error 2021-05-09 22:25:37 +01:00
Paulo Moura
3c567b895f Fix (**)/2 operator type 2021-05-09 21:02:44 +01:00
Paulo Moura
673c75fb72 Fix missing argument in current_op/3 predicate exception term 2021-05-09 20:51:41 +01:00
Paulo Moura
7a576ee36e Fix bitwise shift functions type error in the second argument 2021-05-09 19:58:35 +01:00
Paulo Moura
73c09e3365 Fix open/3-4 predicates error term when the stream argument is bound 2021-05-09 19:21:21 +01:00
Paulo Moura
07dd2b279e Fix throw/1 control construct to throw an instantiation error when the argument is not bound 2021-05-09 12:42:51 +01:00
panasenco
c7943d2521 Switched from using @LukeMathWalker's image to using the official Rust image. Was experiencing cache issues before that, either due to the image, or due to Docker cache being weird... 2021-05-08 17:06:52 -07:00
Mark Thom
9b483d381f Merge pull request #928 from panasenco/permutation
Ported permutation/2 from SWI library(lists)
2021-05-08 15:09:01 -06:00
Mark Thom
4e25337779 Merge pull request #933 from pmoura/add_epsilon_arithmetic_constant
Add epsilon/0 arithmetic constant
2021-05-08 15:08:13 -06:00
panasenco
1e5041b8b0 Moved MIT header to top of lists.pl 2021-05-08 13:32:30 -07:00
Paulo Moura
3f4bbe9b9e Add epsilon/0 arithmetic constant 2021-05-08 21:23:54 +01:00
Mark Thom
56eaf883dc Merge pull request #932 from pmoura/fix_abolish_bug_with_no_existing_predicates
Fix abolish/1 to succeed on non-existing predicates as per standard
2021-05-08 12:39:28 -06:00
Paulo Moura
d8c0af7ded Fix abolish/1 to succeed on non-existing predicates as per standard 2021-05-08 11:13:08 +01:00
panasenco
8724a6b6e2 Ported permutation/2 from SWI library(lists) 2021-05-07 00:29:48 -07:00
Mark Thom
b968b2c438 add missing default RevJmpBy arm to thread_choice_instr_at_to (prompted by #922) 2021-05-05 11:16:39 -06:00
Mark Thom
533d1ea9ab set self.dynamic_mode to FirstOrNext::Next independently of succeed or failure in dynamic indexing instructions (prompted by #922) 2021-05-04 20:56:25 -06:00
Mark Thom
c9e32c449a correct assertz/1 bugs (#922) 2021-05-04 17:53:02 -06:00
Mark Thom
d9e42bfcba fix incremental compilation and multifile bugs 2021-05-03 16:59:12 -06:00
Mark Thom
f552564fc1 import builtins to dynamically generated modules unless builtins is being defined 2021-05-02 11:01:17 -06:00
Mark Thom
b21a096516 add read/2 and nl/1 (#896) 2021-05-01 16:12:00 -06:00
Mark Thom
d0b25de554 add user_error stream (#917) 2021-04-30 21:58:03 -06:00
Mark Thom
bba836dc31 fail on undefined multifile/discontiguous/dynamic predicates (#915) 2021-04-30 21:46:50 -06:00
Mark Thom
14fc8e2efa support full paths in load_context_path/2 (#916) 2021-04-30 20:38:26 -06:00
Mark Thom
d8bd4fbea6 fail when retracting undefined dynamic predicates (#918) 2021-04-30 20:36:56 -06:00
Mark Thom
7cc89da879 Merge pull request #920 from panasenco/serialize
Character logic cleanup and extension
2021-04-29 13:11:13 -06:00
panasenco
baed12f45e Oops, we want to keep digits as characters in library(abnf), but as numbers in library(json). 2021-04-28 23:05:02 -07:00
panasenco
dfbf291725 Restructuring and improving documentation. 2021-04-28 22:22:20 -07:00
panasenco
cb07074246 Replaced object() with pairs() in library(json), and made key type explicit. 2021-04-28 16:09:38 -07:00
panasenco
0198fe90b6 Added ABNF grammar to library(charsio) as well as octet character type that it depends on. Modified library(json) to use the new ABNF grammar. 2021-04-27 22:48:03 -07:00
panasenco
061221b073 Alphabetized character logic in macros.rs and system_calls.rs 2021-04-27 14:01:49 -07:00
Mark Thom
7e4cfede7d fix use of local skeletons to reload predicates (#919) 2021-04-27 02:01:00 -06:00
Mark Thom
48225c3c0a Merge pull request #913 from panasenco/json
Another thorough rewrite of library(json) to better preserve the complete set of answers as much as possible
2021-04-26 13:34:04 -06:00
panasenco
02b89362b2 Replaced raw_chars//1 in library(pio) with seq//1 in library(dcgs). 2021-04-25 14:53:37 -07:00
panasenco
e0e812f95c Added aw_chars//1 to library(pio). Began using setup_call_cleanup/3 as suggested by @triska. 2021-04-24 21:29:50 -07:00
panasenco
2cbc7e4f9a Another thorough rewrite of library(json) to better preserve the complete set of answers as much as possible and thereby write more elegant and simple code. Some performance gains too! 2021-04-23 10:30:38 -07:00
Mark Thom
7bec37bfd8 Merge pull request #912 from panasenco/json
library(json) beta
2021-04-22 17:44:44 -06:00
panasenco
828550687c Rewrote many parts of library(json) to leave no choicepoints when generating JSON. However, the generating performance actually worsened slightly... 2021-04-22 15:21:27 -07:00
panasenco
d3caba4073 Now preserving distinction between ints and floats 2021-04-20 19:59:01 -07:00
panasenco
7e802706fe Seem to be generating JSON correctly and at a good speed too! 2021-04-20 17:33:30 -07:00
panasenco
c87e3eac08 Removed CLP(Z) from library(json), achieving a 100x speedup in JSON parsing. 2021-04-20 17:30:41 -07:00
panasenco
5b1b12ec9e Fixed forward slash special case issue, added a bunch of test files that were successfully read! 2021-04-20 17:30:41 -07:00
panasenco
c0c6f13d44 Fixed defaulty representations of json_members//1 and json_elements//1 2021-04-20 17:30:41 -07:00
panasenco
20f192daa1 Changed formatting to match Markus Triska's as much as I can tell 2021-04-20 17:30:41 -07:00
panasenco
0e73b53803 Complete reordering and partial rewrite to match the official McKeeman form of the JSON specification 2021-04-20 17:30:41 -07:00
panasenco
e2923c378e Added objects and type distinction based on the principal functor 2021-04-20 17:30:41 -07:00
panasenco
216d4da85a Parsing and generating JSON numbers works perfectly now as far as I can tell 2021-04-20 17:30:24 -07:00
panasenco
407e775282 Began working on json library (fresh start after thinking about instantiation in terms of search strategies) 2021-04-20 17:29:36 -07:00
Mark Thom
e71afa63b0 Merge pull request #909 from triska/master
add a new section about support and discussions
2021-04-17 10:34:48 -06:00
Markus Triska
30fd99679a add a new section about support and discussions 2021-04-17 13:45:41 +02:00
Mark Thom
a9ef15cdfa Merge pull request #900 from triska/master
remove rectractall/1 (built-in since 8188e3d0cf).
2021-04-14 15:28:59 -06:00
Mark Thom
b08442b46f assertz/1, asserta/1, retract/1, retractall/1 are meta-predicates (#902, #903) 2021-04-14 15:28:16 -06:00
Markus Triska
f56e2fc48e remove rectractall/1 (built-in since 8188e3d0cf).
This resolves #899.
2021-04-14 20:18:50 +02:00
Mark Thom
5452b55e38 Merge pull request #897 from panasenco/master
Switched to cargo-chef for preparing the Docker image
2021-04-12 21:55:58 -06:00
panasenco
bec8d36961 Switched to cargo-chef for preparing the Docker image 2021-04-12 17:35:20 -07:00
Mark Thom
8188e3d0cf add missing standard predicates (#896) 2021-04-12 17:26:11 -06:00
Mark Thom
10e92eec32 call '$erase_ball' before running cleanup code in setup_call_cleanup (#886) 2021-03-24 16:56:53 -06:00
Mark Thom
37f2336eee stop unifying ! to free variables in control_functor/1 (#887) 2021-03-24 15:05:59 -06:00
Mark Thom
290cb1b517 make retract_local_clauses safe, remove warning about overwriting warning in do_not_duplicate_path_components test 2021-03-23 12:37:43 -06:00
Mark Thom
7520fe7000 use occurs check when enabled in UnifyValue (#885) 2021-03-22 22:05:03 -06:00
Mark Thom
9f861dfe89 reorder declaration matching in loader.pl 2021-03-22 18:13:01 -06:00
Mark Thom
fffb87d013 flush loader term queue before compiling declarations, declare '/1' as dynamic before asserting 2021-03-22 16:53:23 -06:00
Mark Thom
0cb731c584 remove redundant retraction records for incremental compilation 2021-03-22 15:27:45 -06:00
Mark Thom
233faea200 compare the tails of partial string prefixes in compare_pstr_prefixes (#883) 2021-03-22 12:44:58 -06:00
Mark Thom
1b9015a049 copies only those attributes planted by the calling module 2021-03-21 13:00:29 -06:00
Mark Thom
111de1462c remove vestigial attribute goals struct field and related predicates 2021-03-21 12:06:53 -06:00
Mark Thom
7fb0b4a8df rename issue841-occure-check.pl to issue841-occurs-check.pl 2021-03-19 21:39:28 -06:00
Mark Thom
627c49c5db recognize cuts in (->)/(,)/(;) calling contexts (#878) 2021-03-19 16:34:55 -06:00
Mark Thom
665b1ad58a Merge pull request #872 from notoria/charsio
Extend alnum, add forgotten graphic_token
2021-03-18 14:51:36 -06:00
Mark Thom
4623e9d7fc fix findall/4 (#873) 2021-03-18 12:50:12 -06:00
Mark Thom
a3f0290432 restore deleted parts of number_chars/2 and number_codes/2 (#721) 2021-03-17 20:23:58 -06:00
Mark Thom
69b1798af7 print floating point zero as 0.0 (#859) 2021-03-17 20:17:08 -06:00
Mark Thom
10af206024 make chars callable (#713) 2021-03-17 19:50:41 -06:00
Mark Thom
6c23d7aec8 always print variable bindings before names (#865) 2021-03-17 19:27:53 -06:00
Mark Thom
7937ccee30 check that a load context path is a filename before potentially returning it as a string 2021-03-17 18:58:33 -06:00
Mark Thom
b98e8c34eb findall/4 should be declared as a meta-predicate (#873) 2021-03-17 18:13:06 -06:00
Mark Thom
5c2059b4e8 issue an imcomplete reduction error if stream ends with tokens remaining to be parsed (#871) 2021-03-17 14:23:34 -06:00
notoria
f4be0cf4b3 Extend alnum, add forgotten graphic_token 2021-03-17 20:47:09 +01:00
Mark Thom
5f7abda22d remove operators declared at user-level from files when reloading 2021-03-16 18:30:34 -06:00
Mark Thom
51424aed32 clear user-level definitions when reloading a file (#455) 2021-03-16 02:30:09 -06:00
Mark Thom
914fb09ed0 don't warn about overwriting a clause asserted to a dynamic predicate whose clauses have all been retracted (#870) 2021-03-15 14:22:54 -06:00
Mark Thom
7ea7e5c951 remove intra-module predicates from module code directory when module is being re-defined (#848) 2021-03-13 23:22:24 -07:00
Mark Thom
c69807b416 Merge pull request #866 from Skgland/add_tests
Add tests for some recently closed Issues
2021-03-13 00:39:01 -07:00
Skgland
08320119f1 fix expected output for syntax_error test 2021-03-11 17:01:26 +01:00
Skgland
49dcd9bb4a address problems brought up in review 2021-03-11 16:16:31 +01:00
Skgland
8f41603101 add more tests
for some of the recently closed issues
2021-03-11 01:52:22 +01:00
Skgland
d437609365 improve comment 2021-03-11 01:52:21 +01:00
Skgland
e1c681fffe clean up tests/
give helper function a more descriptive name
2021-03-11 01:52:21 +01:00
Mark Thom
d4d47182b4 fix is_cyclic_term (#864) 2021-03-10 16:11:48 -07:00
Mark Thom
bc2d0191ff Merge pull request #861 from notoria/mod
Small improvement for mod in CLP(Z)
2021-03-10 13:52:48 -07:00
notoria
bd222ed2bf Added a test for mod in CLP(Z) 2021-03-10 21:20:18 +01:00
Mark Thom
ceac824e2b Merge pull request #862 from notoria/xor
Implemented a propagator for xor in CLP(Z)
2021-03-09 12:33:06 -07:00
notoria
93b835ae0d Use functional notation in CLP(Z) for compatibility 2021-03-07 20:59:25 +01:00
notoria
aa2d57cf37 Implemented a propagator for xor in CLP(Z) 2021-03-07 18:52:10 +01:00
notoria
f6d4821a68 Small improvement for mod in CLP(Z) 2021-03-07 18:38:04 +01:00
Mark Thom
fa025bcf39 Merge pull request #858 from triska/master
CLP(B) correction
2021-03-05 12:57:20 -07:00
Markus Triska
842176a595 is is --> is 2021-03-05 18:36:00 +01:00
Markus Triska
0fb74b56b3 FIXED: CLP(B): weighted_maximum/3 with repeated variables
Many thanks to @jburse for reporting this issue:

    https://github.com/triska/clpz/issues/15

Example:

    ?- sat(~(Y*X)), sat(Z=:=Y), weighted_maximum([7,2,5],[X,Y,Z],W).
       W = 7, Y = 0, X = 1, Z = 0
    ;  W = 7, Y = 1, X = 0, Z = 1
    ;  false.
2021-03-05 18:35:19 +01:00
Markus Triska
87abcd6a52 adapt comment to Scryer Prolog 2021-03-05 18:16:38 +01:00
Mark Thom
0a71e40030 qualify '$print_project_attributes_exception' call (#857) 2021-03-05 01:14:56 -07:00
Mark Thom
1b9db035ba call project_attributes from top-level (#846) 2021-03-04 16:05:06 -07:00
Mark Thom
34c3035c2b Merge pull request #856 from triska/master
Improvements for library(format)
2021-03-04 13:53:25 -07:00
Markus Triska
d92951ba5b ENHANCED: more readable indentation of nested disjunctions
Example:

    ?- portray_clause((h :- a ; b ; c)).
    h :-
       (  a
       ;  b
       ;  c
       ).
       true.
2021-03-04 21:40:24 +01:00
Markus Triska
c5749cbbb1 remove unnecessary argument 2021-03-04 21:40:24 +01:00
Mark Thom
a2e5bcc137 Merge pull request #854 from triska/master
Better indentation for nested ( If -> Then ; Else ) constructs
2021-03-03 16:11:03 -07:00
Markus Triska
761d707b69 use the new portray_clause/1 output for generated definitions 2021-03-03 22:34:09 +01:00
Markus Triska
d327a05e12 separate side-effects from declarative description to facilitate test cases etc. 2021-03-03 22:34:09 +01:00
Markus Triska
6477d21e24 ENHANCED: more readable indentation of nested ( If -> Then ; Else ) constructs
Example:

    ?- portray_clause((h :- ( a -> b ; c -> d ; e, f))).
    h :-
       (  a ->
          b
       ;  c ->
          d
       ;  e,
          f
       ).
       true.
2021-03-03 22:34:09 +01:00
Mark Thom
d3612e956e catch exceptions thrown from initialization goals (#852) 2021-03-03 13:56:13 -07:00
Mark Thom
5a3ee3a46e has_tail must be false for use as a filename from open/{3,4} 2021-03-03 12:16:47 -07:00
Mark Thom
23cb743ce2 Merge pull request #851 from Skgland/fix_num_test2
Workaround to make num tests work
2021-03-02 23:36:59 -07:00
Skgland
40e5a2dc35 workaround to make num tests work 2021-03-03 01:18:24 +01:00
Mark Thom
73eb4079ef Merge pull request #849 from triska/master
Remove duplicated definitions
2021-03-02 11:59:22 -07:00
Markus Triska
5b60c8aa7e remove min_/3 and max_/3 which are also defined elsewhere 2021-03-02 19:59:57 +01:00
Markus Triska
8c5a688566 remove group_pairs_by_key/2, which is now provided by library(pairs) 2021-03-02 19:58:20 +01:00
Mark Thom
7ea9706c94 warn when overwriting a predicate (#848) 2021-03-02 11:43:47 -07:00
Mark Thom
5976e2d873 do not check for non-unifiability in dif:attribute_goals, which is sure to succeed, resulting in no goals being printed at top-level (#844) 2021-03-02 10:34:25 -07:00
Mark Thom
d32d452583 Merge pull request #845 from triska/master
explain the new occurs_check flag
2021-03-01 11:45:53 -07:00
Markus Triska
b77bdabca6 explain the new occurs_check flag 2021-03-01 19:42:16 +01:00
Mark Thom
e8971e0d8b use atom_chars to convert .scryerrc path string to atom 2021-02-28 23:26:22 -07:00
Mark Thom
498c4660d0 use plain ! while interpreting control functors in metacalls (#724) 2021-02-28 19:12:35 -07:00
Mark Thom
54c142fc0d apply expand_module_names to call(A) goals 2021-02-28 19:01:36 -07:00
Mark Thom
6079402dc4 suppress tabled/2 existence errors in tabling library, do not print evaluation errors generated by term and goal expansion in loader.pl 2021-02-28 18:56:24 -07:00
Mark Thom
3d4a7f97e1 Merge pull request #843 from mthom/rebis-dev
Merge rebis-dev into master
2021-02-28 18:33:24 -07:00
Mark Thom
d6e04beb95 check that Module is an atom before calling Module:goal_expansion/2 2021-02-28 18:28:12 -07:00
Mark Thom
9a225e6244 wrap variable goals in module-expanded call/1 2021-02-28 18:15:33 -07:00
Mark Thom
a03f00628b do not print error messages if .scryerrc[.pl] does not exist (#842) 2021-02-28 17:57:35 -07:00
Mark Thom
360485d830 print errors arising from term and goal expansion calls from loader.pl 2021-02-28 16:19:37 -07:00
Mark Thom
3f1cfd2995 introduce bind_fn, use in applicable Fact/Query instructions (#841) 2021-02-28 16:19:06 -07:00
Mark Thom
08e2b601f1 pop non-composite terms from iter stack in is_cyclic_term 2021-02-28 12:28:19 -07:00
Mark Thom
101ed9a633 add error value to occurs_check prolog flag (#783) 2021-02-28 11:44:23 -07:00
Mark Thom
81ecd17b93 Merge pull request #838 from Skgland/librarify
Split main.rs into lib.rs and bin/scryer-prolog.rs
2021-02-28 11:39:24 -07:00
Skgland
5a78f02dcb revert removal of PartialEq 2021-02-28 19:21:32 +01:00
Skgland
0a08464d4f move the signal handler to the binary 2021-02-28 19:21:31 +01:00
Skgland
a638d42d92 remove #[allow(dead_code)]
only commenting out the unused variant as `OptArgIndexKeyType`
as it appears to mirror `OptArgIndexKey` and there List is not unused
so this appears to be not yet used rather than obsolete
2021-02-28 19:21:31 +01:00
Skgland
90256ea2f5 fix CI lib build with beta compiler 2021-02-28 19:21:31 +01:00
Skgland
90aefd35f0 adjust ci 2021-02-28 19:21:30 +01:00
Skgland
2f428b7261 split into lib and bin
* makes most pub things in src/ pub(crate) as not to expose things accidentally
  * only those things needed by src/bin/scryer-prolog.rs and tests/scryer.rs
    should be pub
* split src/main.rs into src/lib.rs and src/bin/scryer-prolog.rs
* add tests folder and run most of the files in src/tests with cargo test
  added bytes method to Stream in src/machine/streams.rs to check if stdout is as expected
2021-02-28 19:21:30 +01:00
Mark Thom
f935060b2b restore .scryerrc loading 2021-02-28 11:03:55 -07:00
Mark Thom
a367812348 add occurs_check flag (#309) 2021-02-28 10:41:32 -07:00
Mark Thom
8e6a89b279 enable op declarations with lists of operands using term expansion (#839) 2021-02-28 09:15:03 -07:00
Mark Thom
0747697d10 add lines read from devour_whitespace (#836) 2021-02-28 02:09:53 -07:00
Mark Thom
8c7494885f set compilation_target of assert loader to match that of predicate qualifier 2021-02-28 00:27:50 -07:00
Mark Thom
590a0b8077 update the parser with the number of lines already read by the underlying stream (#836) 2021-02-27 23:56:58 -07:00
Mark Thom
064d261357 implement logical update semantics for dynamic database predicates 2021-02-27 23:33:10 -07:00
Mark Thom
adb96710bf Merge pull request #837 from triska/rebis-dev
Small improvements for Rebis
2021-02-25 15:17:16 -07:00
Markus Triska
dd64268bc7 add entry for library(lambda) 2021-02-25 23:12:56 +01:00
Markus Triska
aecbd0eda3 omit internal residual goals for global_cardinality/2 2021-02-25 23:12:36 +01:00
Markus Triska
2c1b7e3b14 remove unused attribute_goal/2 2021-02-25 23:12:36 +01:00
Mark Thom
3eb6357892 Merge pull request #835 from triska/lambda
ADDED: library(lambda) by Ulrich Neumerkel
2021-02-25 14:26:41 -07:00
Markus Triska
e0c98a5c79 adapt libraries and toplevel output to Scryer Prolog 2021-02-25 22:08:25 +01:00
Markus Triska
dfb60ec2ed use individual meta_predicate/1 declarations 2021-02-25 22:08:25 +01:00
Markus Triska
b85e260b92 ADDED: library(lambda) by Ulrich Neumerkel.
Source: http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl

More information:

    http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
2021-02-25 22:08:00 +01:00
Mark Thom
4d72845c58 add copy_term_nat/2 (#795) 2021-02-22 22:39:34 -07:00
Mark Thom
9067f76bd6 no longer delay verify_attributes for cut instructions (#807) 2021-02-22 18:33:35 -07:00
Mark Thom
6c447da730 no longer generate a choice point in bb_b_put/2 (#742) 2021-02-22 18:27:30 -07:00
Mark Thom
1a9f6f06df consume whitespace before reading a term in loader.pl, modify prolog_load_context at file key to better reflect loading context, use it when reporting singleton variables (#812) 2021-02-22 13:23:22 -07:00
Mark Thom
5f8bdc564b extend existing local predicate skeletons in LoadState::compile 2021-02-22 02:00:25 -07:00
Mark Thom
f6498f2a7b anonymize singleton variables in iso_ext.pl, charsio.pl 2021-02-21 19:20:42 -07:00
Mark Thom
0ef5f7f9b1 issue singleton variable warnings from loader.pl (#812) 2021-02-21 19:20:42 -07:00
Mark Thom
a323a4dd8e wrap stream instances in one Rc<RefCell<..>>, use Ref/RefMut to access stream options 2021-02-21 19:20:42 -07:00
Mark Thom
d5581ffd05 Merge pull request #834 from aarroyoc/rebis-http
Fix HTTP server in rebis
2021-02-21 13:32:09 -07:00
Adrián Arroyo Calle
77968ab33a Fix typo 2021-02-21 21:08:03 +01:00
Adrián Arroyo Calle
265a5955d7 Use notoria's comment 2021-02-21 20:22:08 +01:00
Mark Thom
465ab2fa34 Merge pull request #830 from aarroyoc/rebis-http
Fix HTTP server on Rebis. Breaking change
2021-02-21 12:10:09 -07:00
Mark Thom
d60bfef924 tweak bimetatrans_tests.pl 2021-02-21 12:08:36 -07:00
Mark Thom
5225587ff5 add set_prolog_flag to declarations recognized by loader.pl 2021-02-21 12:08:14 -07:00
Mark Thom
fec790e108 correct comment before call meta_predicate declarations 2021-02-20 19:10:34 -07:00
Mark Thom
eb5ea28bcd add 'e' as evaluable functor for Euler's constant (#832) 2021-02-20 18:32:04 -07:00
Mark Thom
a9fe2ab5c4 use env::current_dir in Machine::current_dir (#833) 2021-02-20 18:25:34 -07:00
Mark Thom
f2db0886dd move to a local num-rug-adapter crate addressing #822 2021-02-19 17:35:10 -07:00
Mark Thom
f6926a9642 remove nl after top-level use_module (#818) 2021-02-19 14:36:30 -07:00
Mark Thom
d3442bb08f qualify command-line specified goals with user: (#820) 2021-02-19 14:12:34 -07:00
Mark Thom
a08f5c3016 treat LocalCodePtr::Halt received at lookup_local_instr as an interrupt (#823) 2021-02-19 13:44:22 -07:00
Mark Thom
eff892ccb8 add qualified imports use_module library modules 2021-02-18 17:58:16 -07:00
Adrián Arroyo Calle
b565eaaf5a Fix HTTP server to work on Rebis branch. Breaking change 2021-02-19 00:13:00 +01:00
Mark Thom
3831a371a4 Merge pull request #829 from aarroyoc/uuidv4
UUIDv4 library
2021-02-18 14:29:06 -07:00
Adrián Arroyo Calle
77ec8ebfc3 UUIDv4 generation 2021-02-18 22:16:24 +01:00
Mark Thom
c272e4d1e8 use add_dynamically_generated_module in get_or_insert_local_code_index 2021-02-18 14:15:28 -07:00
Mark Thom
d69b7f41f2 add '$remove_module_exports' to loader.rs 2021-02-18 14:08:25 -07:00
Mark Thom
c8a47d839a Merge pull request #828 from triska/rebis-dev
enable meta_predicate/1 declarations
2021-02-18 12:21:21 -07:00
Markus Triska
b3db8913c6 enable meta_predicate/1 declarations 2021-02-18 20:19:23 +01:00
Mark Thom
e8f8f34a76 Merge pull request #827 from triska/rebis-dev
add appropriate meta_predicate/1 declarations
2021-02-18 12:15:12 -07:00
Markus Triska
5bec2c87cb add appropriate meta_predicate/1 declarations 2021-02-18 20:15:04 +01:00
Mark Thom
d4d283480f Merge pull request #826 from triska/rebis-dev
add appropriate meta_predicate/1 declarations
2021-02-18 11:17:00 -07:00
Markus Triska
71a524662d add appropriate meta_predicate/1 declarations 2021-02-18 19:16:11 +01:00
Mark Thom
172aef7e26 Merge pull request #825 from tniessen/readme-typo-fix
Fix typo in README
2021-02-18 11:15:50 -07:00
Tobias Nießen
395b5faa2d instantianted -> instantiated 2021-02-18 16:53:10 +01:00
Tobias Nießen
f4a765c5ed Fix typo in README 2021-02-18 15:41:18 +01:00
Mark Thom
f5ad845d57 try to canonicalize to absolute path in current_dir(), use it in setting LoadContext directories (#821) 2021-02-17 18:49:51 -07:00
Mark Thom
2a70ca375c restore support for tabling and delimited continuations (#779) 2021-02-17 16:18:49 -07:00
Mark Thom
396c589743 add second term expansion to capture the addition of hook predicates to the expansion process in loader.pl, loader.rs 2021-02-17 15:39:52 -07:00
Mark Thom
7670b81633 remove VNs variable from loader.pl 2021-02-17 13:31:58 -07:00
Mark Thom
f9b98f97b6 remove unnecessary cause of failure in parser, qualify call to op_/3 in builtins.pl 2021-02-17 11:56:58 -07:00
Mark Thom
00bf39204d add missing variable checks in various places 2021-02-17 11:12:19 -07:00
Mark Thom
e9ba3ad223 handle user:goal_expansion, but not Target:goal_expansion, explicitly in loader.pl 2021-02-17 01:19:51 -07:00
Mark Thom
6b6666be47 support discontiguous and multifile declarations 2021-02-16 22:08:32 -07:00
Mark Thom
e2a413df78 compile scoped clauses from loader.pl 2021-02-13 19:41:04 -07:00
Mark Thom
b24f68eee7 remove vestigial uses of constant_eq 2021-02-11 19:22:03 -07:00
Mark Thom
72c1a0222c Box LoadStatePayload when storing it in the heap 2021-02-11 19:21:20 -07:00
Mark Thom
bd97083268 remove unused is_internal function from indexing.rs 2021-02-11 18:51:21 -07:00
Mark Thom
e7cf5d4f3d use machine-generated PartialEq instance for hashing Constant (#817) 2021-02-11 18:40:23 -07:00
Mark Thom
2429971bcd update call/N indices in user-level code_dir in addition to those of pre-loaded modules 2021-02-11 15:38:30 -07:00
Mark Thom
170a71bd02 offset SwitchOnTerm's Internal indices only if the proper instructions were emitted 2021-02-11 15:38:16 -07:00
Mark Thom
14efbb1356 roll back extent of heap when loads are complete in loader.pl 2021-02-11 15:37:43 -07:00
Mark Thom
20cd0dd77a use IndexMap over HashMap in prolog_parser 2021-02-11 15:35:14 -07:00
Mark Thom
2db1fac1eb break out of the first inner loop if constants contains no key in remove_constant_indices (#816) 2021-02-10 14:13:37 -07:00
Mark Thom
ce8490ed41 Merge pull request #813 from triska/rebis-dev
~| now incorporates the number of characters described so far
2021-02-09 17:57:08 -07:00
Mark Thom
7e208984de reset merging_ptr offset before insertion of each overlapping constant (#816) 2021-02-09 17:18:00 -07:00
Mark Thom
4d29a3ae3c check for control functors (,/;/->) before jumping to internal interpretation (#815) 2021-02-09 16:40:25 -07:00
Mark Thom
547c63b28e qualify exception handling code in loader.pl (#809) 2021-02-09 15:47:14 -07:00
Mark Thom
9004aae597 Merge branch 'rebis-dev' of https://github.com/mthom/scryer-prolog into rebis-dev 2021-02-09 14:30:09 -07:00
Markus Triska
1bdfc5a1a4 ~| now incorporates the number of characters described so far
Therefore, subsequent uses of ~N| now yield the specified column,
instead of potentially overshooting.

Example:

    ?- format("hello~|~t~8|!", []).
    hello   !   true.

Such cases are probably rather uncommon: Relative positioning with ~N+
is more likely to be used in such cases, and that worked as intended
also previously as it does now:

    ?- format("hello~|~t~3+!", []).
    hello   !   true.

In fact, if absolute positions are used, then ~| can be omitted entirely:

    ?- format("hello~t~8|!", []).
    hello   !   true.
2021-02-09 20:55:46 +01:00
Mark Thom
195273f01d throw exceptions when modules do not contain claimed exports 2021-02-09 12:17:34 -07:00
Mark Thom
605aea2211 Merge pull request #811 from triska/master
link to announcement of Rebis Development Branch, call for testing
2021-02-09 11:59:59 -07:00
Markus Triska
d1afcb941f link to announcement of Rebis Development Branch, call for testing 2021-02-09 19:14:25 +01:00
Mark Thom
cc7e21170f correct faulty removal of clauses in abolish/1 2021-02-08 19:02:26 -07:00
Mark Thom
30602c0849 clean up implementation of (->)/2, (;)/2, and (,)/2 2021-02-07 21:13:27 -07:00
Mark Thom
1dabe95899 remove tidy_trail 2021-02-07 15:39:48 -07:00
Mark Thom
4995c0ed94 append .pl to names of files that do not exist in loader.pl 2021-02-07 15:38:03 -07:00
Mark Thom
df82dbe5f5 use parent() instead of ancestors().next() in load_context_directory() 2021-02-07 13:51:01 -07:00
Mark Thom
de9c74e1d9 Merge branch 'Skgland-clean_up' into rebis-dev 2021-02-07 00:34:57 -07:00
Bennet Bleßmann
d89eb9ff0e change reposity url 2021-02-06 22:38:40 +01:00
Skgland
5041042925 rename prolog_parser_rebis to prolog_parser
also remove remaining extern crate statements that slipped through earlier
2021-02-06 22:13:34 +01:00
Skgland
0d983e63a1 fix incorrect rug path 2021-02-06 22:13:06 +01:00
Skgland
3f7a60d84b more clippy lints 2021-02-06 22:13:06 +01:00
Skgland
1eb9fcf521 more clippy lints 2021-02-06 22:13:06 +01:00
Skgland
1571690bbb fix clippy lint match|if let looks like matches! macro 2021-02-06 22:13:05 +01:00
Skgland
eb2133e648 fix clippy lint Manual RangeInclusive::contains implementation 2021-02-06 22:13:05 +01:00
Skgland
9107b3ddbe fix some clippy lint warnings 2021-02-06 22:13:05 +01:00
Skgland
64433bd8dd fix macro hygien 2021-02-06 22:13:04 +01:00
Skgland
bc6159c538 change prolog_parse_rebis to use 2018 edition rust
so all crates use the same edition
2021-02-06 22:13:04 +01:00
Skgland
8e5954f36f remove use statements from main.rs that temporary replaced extern crate and fixed paths that previously used them 2021-02-06 22:13:04 +01:00
Skgland
b53ef148a0 remove extern crate declaration and fix outfall (macros now need to be imported into scope)
using use declarations in main.rs so that use paths don't need to be updated as well, this will be done in a later commit
2021-02-06 22:12:31 +01:00
Mark Thom
3f950490f9 set rustyline to check the cursor position (#802), don't add .pl extension to files in loader.pl (#800) 2021-02-06 13:47:26 -07:00
Mark Thom
49b1c1368e remove dynamic clause declaration for clause internal 2021-02-05 23:16:42 -07:00
Mark Thom
bdb5df104a shed module names from arguments of the (->)/2, (,)/2, (;)/2 predicates 2021-02-05 22:50:57 -07:00
Mark Thom
700778e574 collate paths as atoms in loader.pl (#778) 2021-02-05 20:18:56 -07:00
Mark Thom
a104b35cea gather initialization goals and call them once load succeeds (#792) 2021-02-05 18:42:30 -07:00
Mark Thom
bbbf95705b implement abolish/1 2021-02-05 18:35:06 -07:00
Mark Thom
927871d73d Merge branch 'rebis-dev' of https://github.com/mthom/scryer-prolog into rebis-dev 2021-02-05 17:17:14 -07:00
Mark Thom
62419e975f bootstrap the top-level by calling ''/1 as in master (#790) 2021-02-05 17:16:42 -07:00
Mark Thom
3fc2c4223b delay premature set_switch_var_offset_* calls in retract_clause, add module resolution for asserta/assertz/retract/clause 2021-02-05 17:12:25 -07:00
Mark Thom
84da884211 Merge pull request #798 from triska/rebis-dev
CLP(ℤ) enhancements for Rebis
2021-02-05 13:24:53 -07:00
Mark Thom
1bc8e9aebf make load_context_path/2 handle .pl file extensions, remove commented out code 2021-02-05 13:13:54 -07:00
Markus Triska
a228e46a39 ENHANCED: Enable goal expansion for CLP(ℤ).
This is now possible since #445 is resolved.
2021-02-05 21:06:08 +01:00
Markus Triska
81913a5987 Revert "preliminary workaround for #788"
This reverts commit 164b993064,
which was made obsolete by 75a52f032b.
2021-02-05 20:59:47 +01:00
Mark Thom
2d7f31a60d implement dynamic, multifile, and discontiguous properties and callable type checking for predicate_property/2 2021-02-05 02:16:14 -07:00
Mark Thom
804858d736 remove defunct reset function (#782) 2021-02-04 21:02:37 -07:00
Mark Thom
222be9cf6c modify rightmost_power/2 to ignore module qualification on (^)/2 (#794) 2021-02-04 20:51:55 -07:00
Mark Thom
75a52f032b perform goal expansion in call/N (#788, #797) 2021-02-04 20:40:48 -07:00
Mark Thom
a9e0a51059 Merge pull request #793 from triska/rebis-dev
preliminary workaround for #788
2021-02-04 12:51:09 -07:00
Markus Triska
164b993064 preliminary workaround for #788
This change can be reverted once the issue is resolved.
2021-02-04 20:48:09 +01:00
Mark Thom
62b103fa23 Merge branch 'rebis-dev' of https://github.com/mthom/scryer-prolog into rebis-dev 2021-02-03 22:34:34 -07:00
Mark Thom
e17eb01f76 respect module context in expand_module_names (#788) 2021-02-03 16:47:22 -07:00
Mark Thom
2fe55e4715 resolve calls to tranpose_ and same_length in lists.pl (#790) 2021-02-03 16:38:46 -07:00
Mark Thom
a8a82e45a0 introduce cuts over indexed (:)/2 of dcgs:phrase_/3 (#786) 2021-02-03 16:03:15 -07:00
Mark Thom
fcba140ffe Merge pull request #787 from triska/rebis-dev
add meta_predicate declaration for with_local_attributes/3
2021-02-03 15:51:15 -07:00
Markus Triska
b96ff781bc add meta_predicate declaration for must_succeed/1 2021-02-03 23:49:28 +01:00
Mark Thom
94392f248c enable phrase_ rules for module resolved grammars (#785) 2021-02-03 15:48:12 -07:00
Markus Triska
24e6c31c44 add meta_predicate declaration for with_local_attributes/3
This is needed for all_distinct/1 etc.

Example:

    ?- all_distinct([X,Y,Z]).
       clpz:all_distinct([X,Y,Z])
    ;  false.
2021-02-03 23:45:21 +01:00
Mark Thom
cab0e4395a manually expand module names in higher-order predicates of lists.pl and give call_residue_vars/2 a meta-predicate definition 2021-02-03 15:37:16 -07:00
Markus Triska
ae66e299e6 Use term expansion for generated predicates. 2021-02-03 15:21:39 -07:00
Mark Thom
88ad2ee103 restore cut after dcg_constr check (#784) 2021-02-03 15:21:20 -07:00
Mark Thom
48f3f4ca37 add meta-predicate declarations to reif library 2021-02-03 12:46:33 -07:00
Mark Thom
f3ab17a3c0 Merge branch 'master' into rebis-dev 2021-02-03 12:00:00 -07:00
Mark Thom
5749d43fb6 restore prolog_parser test files (#782) 2021-02-03 11:20:55 -07:00
Mark Thom
f5d808e68f do not traverse data structures when binding to local variables in unify_with_occurs_check (#781) 2021-02-03 11:11:22 -07:00
Mark Thom
88f1160e2b use find_inner_choice_instr when appending an indexed clause to an indexed subsequence 2021-02-03 01:22:13 -07:00
Mark Thom
b7218d2279 Merge branch 'rebis-dev' of https://github.com/mthom/scryer-prolog into rebis-dev 2021-02-02 22:59:28 -07:00
Mark Thom
e928a0aaea expand attributed variable goals 2021-02-02 21:47:59 -07:00
Mark Thom
a2447ecaa3 replace Char '!' with QueryTerm::BlockedCut 2021-02-02 21:03:26 -07:00
Mark Thom
09a089d5f1 set target_pos' clause_start correctly in append_compiled_clause 2021-02-02 21:02:08 -07:00
Mark Thom
137b0cd837 Merge pull request #774 from brightly-salty/re-add-prolog_parser
Add prolog_parser to scryer_prolog
2021-02-02 17:56:26 -07:00
Caden Haustein
4ffdd9eb15 Add prolog_parser 2021-02-02 18:35:41 -06:00
Mark Thom
4e29099ed9 export loader's public predicates from builtins, handle module resolution from DCGs 2021-02-02 15:43:52 -07:00
Mark Thom
8900df6f13 add built_in to predicate_property 2021-02-02 15:03:14 -07:00
Mark Thom
814c034683 add meta-predicate declarations before their definitions 2021-02-01 19:26:50 -07:00
Mark Thom
e1ec4bee75 move term expansion logic entirely into loader.pl 2021-02-01 16:50:05 -07:00
Mark Thom
6ed7767512 add module scoping to predicate_property, expand subgoals in module resolved predicates 2021-02-01 16:09:19 -07:00
Mark Thom
08b18af8a0 call attribute variable goals with module resolution 2021-02-01 14:48:13 -07:00
Mark Thom
75908ab88f replace (:) with 0 in meta-predicate declarations, remove support for (:) in meta-predicate declarations 2021-01-31 18:00:10 -07:00
Mark Thom
fcba33997f Merge branch 'master' into rebis-dev 2021-01-31 12:41:18 -07:00
Mark Thom
134be307d3 Merge pull request #771 from notoria/args
Handled the empty case (#770)
2021-01-31 12:11:57 -07:00
Caden Haustein
092f8e6482 Fix errors, move prolog_parser 2021-01-31 12:43:39 -06:00
Caden Haustein
cf5960afad Add prolog_parser to scryer_prolog 2021-01-31 11:40:20 -06:00
notoria
e5204e55d3 Handled the empty case (#770) 2021-01-31 11:03:17 +01:00
Mark Thom
61b14d1cd9 fix bug in append_compiled_clause, generalize merging indexed subsequences of clauses 2021-01-31 01:18:45 -07:00
Mark Thom
c2e3b47d29 properly thread functors whose first subterm is a variable in thread_goals/4 2021-01-30 23:37:23 -07:00
Mark Thom
a239007db0 target prolog_parser_rebis on crates.io 2021-01-30 22:03:07 -07:00
Mark Thom
c5e5eb8b86 explain motive for Rebis development branch in README.md 2021-01-30 21:29:41 -07:00
Mark Thom
a4d15bfb88 move to a predicate-based module system, move to loader.[rs|pl]-based compilation, add support for incremental clause compilation 2021-01-30 21:07:51 -07:00
Mark Thom
b33158b92e Merge pull request #766 from aarroyoc/http-form
HTTP Server: urlencoded forms and some syntax improvements
2021-01-30 13:55:40 -07:00
Mark Thom
3b30c4d487 Merge pull request #769 from notoria/between
Removed redundant choicepoint from between/3
2021-01-30 13:55:05 -07:00
notoria
dfd7ac633a Removed redundant choicepoint from between/3 2021-01-30 17:45:55 +01:00
Adrián Arroyo Calle
213f8a604e Test against macOS 10.15 2021-01-27 23:40:26 +01:00
Adrián Arroyo Calle
13499352fd urlencoded forms and some syntax improvements 2021-01-27 23:34:38 +01:00
Mark Thom
70aa4934c5 Merge pull request #762 from aarroyoc/gh-action
GitHub Actions
2021-01-23 13:31:02 -07:00
Adrián Arroyo Calle
1d538ee70c Fix Beta 2021-01-16 22:32:50 +01:00
Adrián Arroyo Calle
2ed2e6d62f Disable Windows 2021-01-16 22:00:05 +01:00
Adrián Arroyo Calle
aea0570d2b Minor fix 2021-01-16 19:12:53 +01:00
Adrián Arroyo Calle
def33a77da Delete Travis CI 2021-01-16 19:11:07 +01:00
Adrián Arroyo Calle
29db677a9e GitHub Actions 2021-01-16 19:10:50 +01:00
Mark Thom
d362ca3a6d Merge pull request #747 from triska/determinism
reflect better determinism thanks to #732
2020-12-29 14:43:30 -07:00
Markus Triska
3796792421 reflect better determinism thanks to #732 2020-12-29 22:24:56 +01:00
Mark Thom
b8020db029 Merge pull request #726 from aarroyoc/http-server
HTTP Server
2020-12-29 13:07:59 -07:00
Adrián Arroyo Calle
a90030ca2d PR feedback 2020-12-28 22:55:32 +01:00
Adrián Arroyo Calle
3f8d3afe5c URL Decode 2020-12-28 14:42:20 +01:00
Adrián Arroyo Calle
155004bdbb Log time 2020-12-27 22:36:24 +01:00
Adrián Arroyo Calle
534c74b67c Improve docs & Route matching 2020-12-27 20:14:21 +01:00
Adrián Arroyo Calle
5428935ab1 File response 2020-12-27 14:48:05 +01:00
Adrián Arroyo Calle
fc14d089b1 Use phrase instead of forall 2020-12-27 14:11:09 +01:00
Adrián Arroyo Calle
4e543238e1 Queries 2020-12-27 13:23:38 +01:00
Adrián Arroyo Calle
6579a542b8 Merge branch 'master' into http-server 2020-12-27 12:18:05 +01:00
Adrián Arroyo Calle
27e3dcea6c Redirections, default status code, rout matching 1.0 2020-12-27 12:16:46 +01:00
Mark Thom
01f73b11d8 fix bug in code walker causing entire clauses to be skipped (#736) 2020-12-26 22:35:28 -07:00
Mark Thom
dd07226ab4 Merge pull request #743 from triska/determinism
reflect determinism improvement thanks to the latest changes
2020-12-23 13:22:02 -07:00
Markus Triska
67d856e4b7 reflect determinism improvement thanks to the latest changes 2020-12-23 18:06:35 +01:00
Mark Thom
6ad1e57123 Merge pull request #741 from triska/determinism
reflect improved determinism thanks to the improvements by @notoria
2020-12-22 19:18:46 -07:00
Markus Triska
27a52ef56a reflect improved determinism thanks to the improvements by @notoria 2020-12-23 00:05:29 +01:00
Mark Thom
d290596c1d Merge pull request #740 from triska/indexing
small documentation improvements related to the new indexing strategy
2020-12-22 15:39:17 -07:00
Mark Thom
342b4a3b52 Merge pull request #734 from triska/deterministic_format
ENHANCED: format_//2, format/[2,3], portray_clause/1 are now deterministic
2020-12-22 14:51:56 -07:00
Mark Thom
19652e6367 Merge pull request #732 from notoria/indexing
Implemented a different way to index clauses
2020-12-22 14:51:10 -07:00
Markus Triska
1c76c869ef small documentation improvements related to the new indexing strategy 2020-12-22 21:59:11 +01:00
notoria
706d842102 Renamed find_optimal_index to first_instantiated_index 2020-12-21 20:27:53 +01:00
notoria
2889631b61 Merge pull request #6 from triska/indexing
document first instantiated argument indexing
2020-12-21 20:02:22 +01:00
Markus Triska
5b9f0f45a9 document first instantiated argument indexing
Many thanks to @notoria for this brilliant idea and implementation!
2020-12-21 19:58:54 +01:00
notoria
ecc059bf8b Organized changes into find_optimal_index 2020-12-21 12:19:21 +01:00
Adrián Arroyo Calle
e1f4a50e65 HTTP Body 2020-12-21 00:15:00 +01:00
notoria
ec2c5a9b2c Simplified the code, removed first_arg, the Option 2020-12-19 21:04:17 +01:00
Markus Triska
4efbc20a4f ENHANCED: format_//2, format/[2,3], portray_clause/1 are now deterministic.
This works as soon as #732 is merged, since then maplist/N and foldl/N
are deterministic in the required cases.

This also resolves the extra choicepoint of time/1 (see #378).

Many thanks to @notoria for implementing better indexing in #732,
which allowed me to find this opportunity for improvement!
2020-12-19 18:18:14 +01:00
notoria
657e4f12bb Implemented a different way to index clauses 2020-12-19 14:52:38 +01:00
Mark Thom
22ffb1f53f Merge pull request #729 from brightly-salty/replace-dirs
Replace dirs with dirs-next
2020-12-15 10:04:46 -07:00
brightly-salty
4854da4805 Replace dirs with dirs-next 2020-12-15 06:59:26 -06:00
Adrián Arroyo Calle
33a0df20c3 Read body 2020-12-14 22:57:53 +01:00
Adrián Arroyo Calle
e4d1e4b7a0 Request and Response headers 2020-12-12 21:28:33 +01:00
Adrián Arroyo Calle
dbc193ab2a WIP http_server 2020-12-09 23:40:00 +01:00
Mark Thom
7bde174b40 Merge pull request #722 from aarroyoc/history-file
History file support (Rustyline 7.0) (#152)
2020-12-06 15:50:52 -07:00
Mark Thom
cf8014582b Merge pull request #720 from aarroyoc/max-min-list
Add list_max & list_min to lists module
2020-12-06 15:39:42 -07:00
Adrián Arroyo Calle
e2796dd351 History file support (Rustyline 7.0) 2020-12-06 23:16:25 +01:00
Adrián Arroyo Calle
0696a18e0b Change name to list_max, list_min as PR feedback 2020-12-06 21:58:37 +01:00
Adrián Arroyo Calle
0cc9388af0 Use foldl as PR feedback suggested 2020-12-06 17:31:42 +01:00
Adrián Arroyo Calle
a73529969a Add max_list & min_list to lists 2020-12-05 14:20:50 +01:00
Mark Thom
c55de17ca8 Merge pull request #710 from triska/clpz-reif
ADDED: Provisional support for (#=)/3 and (#<)/3.
2020-11-08 14:40:32 -07:00
Markus Triska
41a751e7f5 ADDED: Provisional support for (#=)/3 and (#<)/3.
These predicates are intended for constructs from library(reif), such
as if_/3. For the time being, they are defined here. If you have any
recommendations or comments regarding the best location of these
predicates, or need more of them, please file an issue.

Suggested by @Qqwy in https://github.com/triska/clpz/issues/12.

Many thanks!
2020-11-08 09:26:50 +01:00
Mark Thom
b9a53e441e support number/1 2020-11-03 23:38:55 -07:00
Mark Thom
add62c2093 Merge branch 'master' of https://github.com/mthom/rusty-wam into master 2020-10-22 00:24:30 -06:00
Mark Thom
de01ac233c Merge pull request #706 from malbarbo/fix-num
Fix build with num features
2020-10-20 21:43:03 -06:00
Mark Thom
c9e926f451 Merge branch 'master' of https://github.com/mthom/rusty-wam into master 2020-10-20 15:25:38 -06:00
Marco A L Barbosa
8d405849be Update num-rug-adapter to fix build with num feature. 2020-10-18 19:20:45 -03:00
Mark Thom
5fbdb1af9f Merge pull request #702 from triska/showterm
Add showterm.el and showterm.pl to the distribution
2020-10-03 12:20:02 -06:00
Markus Triska
83350f8866 use "r" interactive specifier 2020-10-03 17:13:17 +02:00
Markus Triska
b4ccd889af refer to new tools directory 2020-10-03 09:59:31 +02:00
Markus Triska
35a3f2dc91 ADDED: showterm.el and showterm.pl to draw terms as trees in Emacs 2020-10-03 09:56:26 +02:00
Mark Thom
ed7a4514de Merge pull request #700 from triska/development_environment
DOC: Development environment recommendations.
2020-10-01 13:41:52 -06:00
Markus Triska
2e295e354a DOC: Development environment recommendations. 2020-10-01 21:15:40 +02:00
Mark Thom
d71d9cc8ef Merge branch 'master' of https://github.com/mthom/rusty-wam into master 2020-09-14 10:46:11 -06:00
Mark Thom
108b62d839 Merge pull request #698 from triska/file_must_exist
ENHANCED: library(files): Error handling if requested files do not exist.
2020-09-13 10:30:50 -06:00
Markus Triska
46dfaa5b28 ENHANCED: library(files): Error handling if requested files do not exist.
We now throw exceptions instead of failing silently, or even crashing
when using file_size/2 etc. with nonexistent files.
2020-09-13 10:23:23 +02:00
Mark Thom
323e9c3eb3 refactor SystemClauseType::Open in anticipation of #614 2020-09-05 18:57:03 -06:00
Mark Thom
d677d3d2ef preface the 'spelling error' with an explainer comment (#687) 2020-09-05 18:07:58 -06:00
Mark Thom
c39b239d78 Merge pull request #696 from triska/format_distinct_variables
FIXED: format_//2: Keep different variables distinct.
2020-09-05 08:50:07 -06:00
Markus Triska
5f3ab823fd FIXED: format_//2: Keep different variables distinct.
Example:

        ?- phrase(format_("~w~w", [_,_]), Ls).
        %@    Ls = "AB"
        %@ ;  false.
2020-09-05 09:58:49 +02:00
Mark Thom
03d1da4bf2 Merge pull request #694 from triska/write_all
FIXED: reliably write all characters when using format/3
2020-09-02 12:52:53 -06:00
Markus Triska
78656d220b FIXED: reliably write all characters when using format/3
This addresses #693.

Many thanks to @notoria for a brilliant test case, and the
suggestion of this correction!
2020-09-02 19:29:04 +02:00
Mark Thom
7e7aa7992a Merge pull request #689 from matteoredaelli/patch-1
Update README.md
2020-08-25 12:27:13 -03:00
Matteo Redaelli
a53b4df8b6 Update README.md
wrong link to source file dcgs.pl
2020-08-25 17:19:45 +02:00
Mark Thom
3ba2b8ade6 Merge pull request #686 from triska/call_nth
ADDED: Preliminary version of call_nth/2.
2020-08-24 16:07:40 -03:00
Markus Triska
79cb4cd6a5 ADDED: First version of call_nth/2.
A thread-safe implementation is possible for example with
'$nb_setarg'/3 (see #390).
2020-08-24 19:29:08 +02:00
Mark Thom
d3ab4b5def flatten passage of cut point B in (,)/2, (->)/2 and (;)/2 (#685, #683) 2020-08-23 22:49:10 -03:00
Mark Thom
cdeb07520f Merge pull request #682 from triska/dif_improvements
Improvements to dif/2
2020-08-22 20:17:32 -03:00
Markus Triska
cc77ef680d dif/2: Omit entailed residual goals, if the arguments are not unifiable.
This addresses #135.
2020-08-22 17:50:15 +02:00
Markus Triska
e75ebd9b6e dif/2: Succeed unconditionally if the arguments are not unifiable.
This addresses one part of #135.
2020-08-22 17:50:15 +02:00
Mark Thom
62c9b8390b Merge pull request #677 from notoria/clpz_mod
Made mod stronger and addressed #675
2020-08-15 13:55:48 -03:00
notoria
0724c044d6 Use nonterminal fd_put//3 in mod from clpz 2020-08-15 17:56:07 +02:00
notoria
bed4afe74f Simplified the code 2020-08-15 17:39:34 +02:00
notoria
d4263cc8b9 Using queue_goal//1 to correctly bind variables 2020-08-15 17:06:12 +02:00
notoria
b4b11465a1 Fixed variable bindings in mod from clpz 2020-08-15 13:37:33 +02:00
notoria
daaebc59cb Made mod stronger and addressed #675 2020-08-15 12:53:28 +02:00
Mark Thom
79a74038ac Merge pull request #674 from notoria/clpz_mod
Improved mod in clpz
2020-08-14 00:21:19 -03:00
notoria
314baabf1d More improvement on mod from CLP(Z) 2020-08-13 21:36:36 +02:00
notoria
a24fbb8f61 Improved mod in CLP(Z)
This is still a work in progress.
2020-08-13 10:33:36 +02:00
Mark Thom
32eaab0783 Merge pull request #671 from triska/clpb_restriction
FIXED: CLP(B): Delay BDD restriction until after the instantiation.
2020-08-12 16:59:51 -03:00
Markus Triska
e185b626bd FIXED: CLP(B): Delay BDD restriction until after the instantiation.
This is necessary to actually take the new value into account.

Example:

    ?- sat(A*B>=C*D), A=1,B=0,C=1,D=1.
    false.

This addresses #670.
2020-08-12 19:51:25 +02:00
Mark Thom
74dc94f6bc Merge pull request #668 from triska/xbrl
library(sgml): Correctly parse XML leaf nodes that are not text nodes.
2020-08-11 19:53:02 -03:00
Markus Triska
099d9aaca6 library(sgml): Correctly parse XML leaf nodes that are not text nodes.
Example:

    ?- load_xml("<schemaRef type=\"simple\"/>", Node, []).
       Node = [element(schemaRef,[type="simple"],[])].

This is necessary for example to parse XBRL files. See #665.
2020-08-11 21:20:33 +02:00
Mark Thom
5fa3b9f2fb Merge pull request #667 from triska/clpb_taut
omit internal attributes in residual goals when using taut/2
2020-08-11 15:54:34 -03:00
Markus Triska
ad8e2ad4f6 omit internal attributes in residual goals when using taut/2
Examples:

    ?- taut(X=:=X,1).
       clpb:sat(X=:=X)
    ;  false.

    ?- taut(X=\=X,0).
       clpb:sat(X=:=X)
    ;  false.
2020-08-11 20:49:10 +02:00
Mark Thom
8203eff47b update prolog_parser version (#657) 2020-08-08 16:29:35 -06:00
Mark Thom
ad333047d9 Merge branch 'master' of https://github.com/mthom/scryer-prolog 2020-08-08 13:12:09 -06:00
Mark Thom
6e5d2d6a36 fix bugs in PausedPrologStream (#661) 2020-08-08 13:11:09 -06:00
Mark Thom
4b610b6293 Merge pull request #656 from notoria/try_from_number
Fixed some conversion issues
2020-08-08 12:24:29 -03:00
Mark Thom
2bd998e82f Merge pull request #660 from triska/shorter_crypto
Shorten and improve implementation of several cryptographic routines
2020-08-08 12:23:40 -03:00
Markus Triska
c55cc3c472 ensure proper lengths of key and initialization vector
This avoids crashes when using unsuitable lengths.
2020-08-06 23:27:49 +02:00
Markus Triska
674483a4c6 remove entailed constraint 2020-08-06 23:17:08 +02:00
Markus Triska
a16f84560d use self.deref(...) (see #653) 2020-08-06 20:12:57 +02:00
Markus Triska
1b4500339e use atom_argument_to_string 2020-08-06 20:12:23 +02:00
notoria
3143468751 Fixed some conversion issues 2020-08-06 11:39:55 +02:00
Mark Thom
f627b32355 fix crash in CryptoPasswordHash (#653), conversion of Rational integers in number_chars/2 (#655) 2020-08-06 00:17:55 -06:00
Mark Thom
10ba6fb773 Merge pull request #654 from triska/aad
ADDED: library(crypto): Support for additional authenticated data (AAD).
2020-08-06 02:40:51 -03:00
Markus Triska
2d3f1e51ec shorten, and increase readability 2020-08-05 21:49:46 +02:00
Markus Triska
1c23336cff use "octet" as a string literal, reducing the number of arguments 2020-08-05 20:21:46 +02:00
Markus Triska
a622ffddfe ADDED: library(crypto): Support for additional authenticated data (AAD).
Additional authenticated data can now be specified with the new
aad(Chars) option for encryption and decryption. It is authenticated,
but not encrypted.
2020-08-05 20:09:07 +02:00
Mark Thom
79cf0c63c4 update prolog_parser to 0.8.67 (#648) 2020-08-04 23:35:10 -06:00
Mark Thom
d57a592273 unify '[]' with proper [] in atom_chars/2 (#569) 2020-08-03 19:29:53 -06:00
Mark Thom
4f15802fbc reconcile '[]' and [] (#644), solve remaining conformity issues (#648), move (-->) from dcgs.pl to builtins.pl (#649) 2020-08-02 23:35:53 -06:00
Mark Thom
357ae7a8aa Merge pull request #647 from notoria/newline
Improved readline
2020-07-31 18:19:12 -03:00
notoria
ac00ae4daf Improved readline 2020-07-31 21:16:33 +02:00
Mark Thom
249f034a38 Merge pull request #645 from triska/curve25519
ADDED: library(crypto): ECDH key exchange over Curve25519 (X25519)
2020-07-30 10:29:20 -03:00
Markus Triska
32c612b747 ADDED: library(crypto): ECDH key exchange over Curve25519 (X25519) 2020-07-29 23:51:11 +02:00
Mark Thom
386f7cf65d the indexer now categorizes partial strings only as lists (#623, #642) 2020-07-27 16:43:43 -06:00
Mark Thom
8dc07882b6 try to build strings from list as potential matches in SwitchOnConstant (#623) 2020-07-26 19:16:05 -06:00
Mark Thom
320802633f Merge pull request #639 from triska/flush_output
ENHANCED: flush output for impure I/O (format/[2,3], portray_clause/1 etc.)
2020-07-25 13:20:45 -03:00
Markus Triska
dcc4b91b35 ENHANCED: flush output for impure I/O (format/[2,3], portray_clause/1 etc.)
Without this, we do not get a (timely) prompt in cases like:

    ?- format("press a key: ", []), get_single_char(C).

whereas for example write/1 already works in such cases:

    ?- write('press a key: '), get_single_char(C).
    press a key:
2020-07-25 09:49:02 +02:00
Mark Thom
e7c27ed999 Merge pull request #638 from triska/base64
ADDED: chars_base64/3 for efficient bidirectional Base64 conversion.
2020-07-23 19:49:12 -03:00
Markus Triska
928c9c9aad throw an error if a character cannot be encoded 2020-07-23 00:35:23 +02:00
Markus Triska
4a90f13dee better error handling for options 2020-07-23 00:27:31 +02:00
Markus Triska
61dddcee3f use newly available chars_base64/3 2020-07-22 20:35:48 +02:00
Markus Triska
4c510001ce ADDED: chars_base64/3 for efficient bidirectional Base64 conversion. 2020-07-22 20:35:48 +02:00
Mark Thom
82dfa690d2 Merge pull request #636 from triska/path_segments
ADDED: path_segments/2 for portable reasoning about path components.
2020-07-19 13:16:27 -03:00
Markus Triska
2768beec4c ADDED: path_segments/2 for portable reasoning about path components.
The platform-specific directory separator is taken into account.
The clean representation of segments as a list simplifies reasoning.
2020-07-19 12:32:01 +02:00
Mark Thom
bd0aa16322 Merge pull request #633 from triska/file_time
ADDED: file_creation_time/2 and file_access_time/2.
2020-07-18 12:40:53 -03:00
Mark Thom
a1746a5bf1 Merge pull request #631 from cduret/lib_csv
add write_csv & change skip_header to with_header option
2020-07-18 12:40:28 -03:00
Mark Thom
fb502fb66b Merge pull request #635 from triska/more_links
DOC: add more links to libraries, and include iso_ext in the enumeration
2020-07-18 12:40:09 -03:00
Markus Triska
c9a69263b6 DOC: add more links to libraries, and include iso_ext in the enumeration 2020-07-18 08:12:26 +02:00
Mark Thom
f0c8056334 look up operator precedence when arity does not match what the atom records, don't print brackets around outermost '+' (#629) 2020-07-17 11:02:58 -06:00
Markus Triska
17dd9239b6 ADDED: file_creation_time/2 and file_access_time/2.
The code can be simplified once if- and while-let-chains are available:

    https://github.com/rust-lang/rust/issues/53667
2020-07-17 18:48:39 +02:00
Mark Thom
6c691d9223 Merge pull request #632 from triska/path_canonical
ADDED: path_canonical/2, obtaining the canonical absolute path.
2020-07-16 21:03:13 -03:00
Cyrille Duret
920644afaf set domain_error exception & use format/3 with setup_call_cleanup/3 for stream writing 2020-07-17 01:21:40 +02:00
Markus Triska
8668aee7fd ENHANCED: Reorder fields in time stamps so that (@<)/2 is meaningful. 2020-07-16 23:40:03 +02:00
Markus Triska
4f386b3e5e ADDED: file_modification_time/2, obtaining a time stamp.
This addresses a remaining aspect of #511.
2020-07-16 23:40:03 +02:00
Markus Triska
0f4667d942 ADDED: path_canonical/2, obtaining the canonical absolute path.
This addresses a remaining aspect of #511.
2020-07-15 20:43:34 +02:00
Cyrille Duret
5705c42820 set throw() to follow ISO recommendations 2020-07-15 18:26:57 +02:00
794404
f5f0d00a75 add write_csv & change skip_header to with_header option 2020-07-15 13:02:30 +02:00
Mark Thom
ec75e21898 Merge pull request #630 from triska/delete_file
ADDED: delete_file/1, addressing a remaining aspect of #511
2020-07-14 20:26:51 -03:00
Markus Triska
94e9e17c79 ADDED: working_directory/2, addressing a remaining aspect of #511 2020-07-14 23:05:29 +02:00
Markus Triska
5134e64cae ADDED: delete_file/1, addressing a remaining aspect of #511 2020-07-14 22:21:46 +02:00
Mark Thom
53d39ccb4b Merge pull request #626 from triska/compact_crypto
ENHANCED: library(crypto): Retain the compact representation of strings.
2020-07-12 12:17:58 -03:00
Markus Triska
b227e160f0 mention symmetric encryption and ChaCha20-Poly1305 2020-07-12 11:59:34 +02:00
Markus Triska
88a2b82f7e ENHANCED: library(crypto): Retain the compact representation of strings.
This avoids the costly (in terms of space requirements!) conversion of
compact lists of characters to lists of integers, making hashing, HKDF,
encryption, decryption, signing and signature verification an order of
magnitude more efficient (primarily in terms of space, also in time).

This makes library(crypto) suitable to process also very large files.
2020-07-12 11:54:37 +02:00
Mark Thom
0016365446 Merge pull request #625 from triska/os
ADDED: library(os), reasoning about environment variables.
2020-07-11 23:50:01 -03:00
Markus Triska
0fa8feb475 use newly available character type in must_be/2 2020-07-11 21:00:25 +02:00
Markus Triska
eb872f8fca ADDED: library(os), reasoning about environment variables.
Together with library(files), this addresses #511.
2020-07-11 21:00:25 +02:00
Mark Thom
5fd78320dd slight update to the BiMetaTrans README 2020-07-10 15:22:15 -06:00
Mark Thom
3195042c7d update bimetatrans tests 2020-07-10 10:26:48 -06:00
Mark Thom
b0234fa8b7 add bimetatrans README 2020-07-09 20:53:13 -06:00
Mark Thom
2a629fee37 Merge pull request #621 from notoria/tabling
Tabling
2020-07-03 14:40:52 -03:00
notoria
bf13700a95 Enhanced the implementation
The restriction has been removed by using read_library_path from
cfd15f4e02.
2020-07-01 13:14:12 +02:00
notoria
83268f5ff6 Allowing paths in use_module(library(..)) (#604)
In a module, the path is restricted in being an atom.
2020-07-01 10:22:17 +02:00
notoria
1eb42654e0 Revert "allow paths in use_module(library(..)) (#604)"
This reverts commit cfd15f4e02.
2020-07-01 10:07:26 +02:00
notoria
e05c34d1ee Revert "build.rs recursively delves into directories during library bake stage, correct misnamed file at machine/mod.rs:455 (#617)"
This reverts commit c1b577f2c7.
2020-07-01 10:06:20 +02:00
Mark Thom
8325bb11e2 Merge pull request #606 from triska/files
ADDED: library(files), for reasoning about files and directories.
2020-06-30 13:34:39 -03:00
Mark Thom
c1b577f2c7 build.rs recursively delves into directories during library bake stage, correct misnamed file at machine/mod.rs:455 (#617) 2020-06-29 00:58:10 -06:00
Mark Thom
29a61db275 Merge pull request #613 from cduret/csv_lib
add csv library
2020-06-27 16:28:10 -03:00
Cyrille Duret
e2c61485a1 add csv library 2020-06-25 21:13:29 +02:00
Markus Triska
65f200e02c directory_files/2: throw representation error if into_string() fails
Suggested by @notoria in #606. Many thanks!
2020-06-24 23:30:40 +02:00
Markus Triska
aa9432e24f comment on indexing, addressing a comment by @pmoura in #606
If indexing is needed for lists of characters, it should be added to
the engine.
2020-06-24 22:29:34 +02:00
Markus Triska
30d1585468 ADDED: library(files), for reasoning about files and directories. 2020-06-24 22:29:34 +02:00
Mark Thom
376c5263f0 Merge pull request #608 from triska/xml
ADDED: load_xml/3 to load XML files from streams, files and strings.
2020-06-22 12:21:35 -03:00
Markus Triska
bcd6d4e8a7 library(format) is not used in this example 2020-06-21 09:46:05 +02:00
Markus Triska
32eb896c56 ADDED: load_xml/3 to load XML files from streams, files and strings. 2020-06-21 09:45:37 +02:00
Mark Thom
4603163e88 Merge pull request #607 from triska/xpath
ADDED: library(xpath) for convenient analysis of HTML and XML documents.
2020-06-20 14:46:52 -03:00
Markus Triska
b3c9fb2fea import member/2 from library(lists)
This is needed when processing redirects.
2020-06-20 19:07:43 +02:00
Markus Triska
d66ea07ba4 ADDED: library(xpath) for convenient analysis of HTML and XML documents. 2020-06-20 18:08:11 +02:00
Mark Thom
496279c92d Merge pull request #596 from triska/sgml
ADDED: library(sgml), providing load_html/3 to parse HTML documents
2020-06-19 12:59:06 -03:00
Mark Thom
e0ae925ca3 Merge pull request #605 from notoria/debug
Added library(debug)
2020-06-19 12:58:26 -03:00
notoria
1799c19933 Added an entry in README 2020-06-19 17:48:55 +02:00
notoria
94eddd3b42 Added library(debug) 2020-06-19 17:18:59 +02:00
Markus Triska
79829cb6d2 ADDED: library(sgml), providing load_html/3 to parse HTML documents 2020-06-19 16:40:01 +02:00
Mark Thom
0d20ca0bf2 Merge pull request #592 from triska/http_open
ADDED: library(http/http_open), opening HTTP and HTTPS streams for reading
2020-06-19 11:30:23 -03:00
Mark Thom
3ede5ea28f Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-06-19 00:58:43 -06:00
Mark Thom
cfd15f4e02 allow paths in use_module(library(..)) (#604) 2020-06-19 00:57:56 -06:00
Mark Thom
1f9ff2dd88 clarify meaning of AssertItems and QueryItems in BiMetaTrans source-level documentation 2020-06-18 23:47:54 -06:00
Mark Thom
7740a39a4d Merge pull request #602 from triska/put_char
put_char/[1,2]: throw type errors for atoms that are not characters
2020-06-18 12:16:47 -03:00
Markus Triska
5eda2dfe0e put_char/[1,2]: throw type errors for atoms that are not characters
Example:

    ?- put_char(hello).
    %@ caught: error(type_error(character,hello),put_char/2)
2020-06-18 00:15:00 +02:00
Mark Thom
1509c6a471 Merge pull request #597 from triska/faster_format
ENHANCED: much faster format/3 for text streams
2020-06-17 18:48:49 -03:00
Markus Triska
19acd608a5 ADDED: library(http/http_open), opening HTTP and HTTPS streams for reading
Example:

   ?- http_open("https://github.com/mthom/scryer-prolog", Stream, []),
      length(Ls, 10),
      maplist(get_char(Stream), Ls).

Yielding:

   %@    Stream = '$stream'(0x7fba4c59ef10), Ls = "\n\n\n\n\n<!DOC"
   %@ ;  false.
2020-06-17 20:10:22 +02:00
Mark Thom
bc81ff28d8 cover Addr::Fixnum when not referenced as an Addr::Con, undefine dynamic predicate definitions from within modules too (#588) 2020-06-16 19:03:07 -06:00
Mark Thom
ba867e95c3 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-06-16 18:47:53 -06:00
Mark Thom
53f99ca434 fix copy_partial_string bug (#572) 2020-06-16 18:47:39 -06:00
Markus Triska
8958ea036e ENHANCED: much faster format/3 for text streams
This is now also used by format/2 to emit output on the terminal,
and significantly speeds up toplevel output of long strings.
2020-06-16 21:13:03 +02:00
Mark Thom
d3563c30e7 Merge pull request #590 from triska/read_line_to_chars
ADDED: read_line_to_chars/3, reading up to and including "\n" from a stream
2020-06-16 00:06:01 -03:00
Mark Thom
0f017339b7 change the plurality of AssertItem(s), QueryItem(s) in bimetatrans.pl 2020-06-15 16:38:27 -06:00
Mark Thom
4d3a3d806f Merge pull request #595 from triska/faster_format
ENHANCED: faster format/3 when writing to binary streams
2020-06-14 12:37:06 -03:00
Markus Triska
10a0f708b9 use format/3 to benefit from efficiency improvements 2020-06-14 10:51:24 +02:00
Markus Triska
409d3c168d ENHANCED: faster format/3 when writing to binary streams
This is also more secure, since it does not change the atom table
and therefore leaves little trace of what was processed.
2020-06-14 10:43:25 +02:00
Mark Thom
005220b6d4 Merge pull request #589 from triska/lazy_pio
ENHANCED: Read more characters at once, significantly speeding up library(pio)
2020-06-13 21:09:19 -03:00
Mark Thom
8462b039d3 Merge pull request #593 from triska/portray_clause
ADDED: portray_clause/2, writing to a specified stream.
2020-06-13 21:08:54 -03:00
Mark Thom
2e3cabce6b Merge pull request #594 from triska/scryerrc
explain .scryerrc configuration file
2020-06-13 17:55:32 -03:00
Mark Thom
2c6b615b8c fix broken links in README (#591) 2020-06-13 10:46:53 -06:00
Markus Triska
f910e013a6 use take() for extra fast processing of binary files
Suggested by @notoria in #589. Many thanks!
2020-06-13 16:47:46 +02:00
Markus Triska
5f1b03261c better naming: str --> string
Suggested by @notoria in #589. Many thanks!
2020-06-13 16:47:46 +02:00
Markus Triska
862197fc96 explain .scryerrc configuration file 2020-06-13 16:47:02 +02:00
Markus Triska
44ebd894d5 ADDED: portray_clause/2, writing to a specified stream. 2020-06-13 16:45:47 +02:00
Markus Triska
b85ff7db36 ENHANCED: Read more characters at once, significantly speeding up library(pio). 2020-06-13 16:25:41 +02:00
Markus Triska
22fd216de5 ADDED: read_line_to_chars/3, reading up to and including "\n" from a stream, yielding a list difference.
This works for both binary and text streams.
2020-06-13 09:14:44 +02:00
Mark Thom
2f02c428cc rename bimetatrans example files and directory 2020-06-12 18:32:48 -06:00
Mark Thom
1732413ee1 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-06-12 18:28:07 -06:00
Mark Thom
33325f1574 remove vestigial prolog/ directory (#444) 2020-06-12 18:26:38 -06:00
Mark Thom
4f288c6fd9 Merge pull request #587 from triska/lazy_pio
ENHANCED: phrase_from_file/[2,3] now read the file lazily.
2020-06-12 11:24:52 -03:00
Mark Thom
5ffb4597b3 add missing ! in int_pow (#580) 2020-06-11 22:28:05 -06:00
Mark Thom
d9de38b935 adjust the tail created by CreatePartialString to point to the last cell it pushed to the heap (#586) 2020-06-11 21:25:20 -06:00
Mark Thom
ad459b83c0 credit Ulrich Neumerkel for partial strings in README 2020-06-11 21:24:20 -06:00
Markus Triska
d96ea6b815 include library(pio) and library(charsio) in the itemization 2020-06-12 00:02:41 +02:00
Markus Triska
40c3e31955 ENHANCED: phrase_from_file/[2,3] now read the file lazily.
This allows processing extremely large files. In addition, the
efficient string representation helps to reduce memory usage.

These features unleash the full power of Prolog for text processing,
the exact use case Prolog was designed for.
2020-06-12 00:02:41 +02:00
Mark Thom
f84c831cda remove most cuts from bimetatrans_ruleml.pl 2020-06-11 12:22:35 -06:00
Mark Thom
904cf97f7d fix printing of atoms like '.x' (#585) 2020-06-11 11:11:04 -06:00
Mark Thom
791e22dc24 eliminate unnecessary find_min_time_ predicate in least_time.pl example 2020-06-10 22:25:23 -06:00
Mark Thom
c82a0b3d2d Merge pull request #582 from triska/format_time
ADDED: format_time//2 for describing strings involving dates and times
2020-06-10 20:21:44 -03:00
Markus Triska
2fc887724b ADDED: format_time//2 for describing strings involving dates and times
current_time/1 yields the current system time as an opaque time stamp.
2020-06-11 00:55:38 +02:00
Mark Thom
e16762a137 scryer and prolog_parser version bump (#581) 2020-06-10 14:29:22 -06:00
Mark Thom
4a07ffac69 prolog_parser version bump, scryer version bump 2020-06-09 22:15:11 -06:00
Mark Thom
9331c4ce9e Merge pull request #579 from triska/master
ENHANCED: throw Prolog exception on expired certificates
2020-06-09 18:56:29 -03:00
Markus Triska
184ef94e7e ENHANCED: throw Prolog exception on expired certificates
Example:

    ?- socket_client_open('expired.badssl.com':443, S, [tls(true)]).
    caught: error(permission_error(open,source_sink,'expired.badssl.com'),socket_client_open/3)
2020-06-09 23:01:28 +02:00
Mark Thom
d67740d44d Merge pull request #577 from triska/tls
ADDED: Encrypted client connections in library(sockets) via new option tls/1.
2020-06-09 10:56:17 -03:00
Markus Triska
7b30daf88d ADDED: Encrypted client connections in library(sockets) via new option tls/1.
Use tls(true) to negotiate an encrypted network connection via TLS.
2020-06-09 07:43:29 +02:00
Markus Triska
d5e76da475 ADDED: type checks for type boolean 2020-06-08 00:41:47 +02:00
Mark Thom
5d91c1af81 Merge pull request #578 from triska/format_improvements
Various improvements for format_//2
2020-06-07 19:36:16 -03:00
Mark Thom
bb013e78d2 Merge pull request #576 from triska/crypto_curve_scalar_mult
ENHANCED: Faster Rust-based crypto_curve_scalar_mult/4 using OpenSSL.
2020-06-07 19:34:12 -03:00
Markus Triska
c22816de08 type check for ~d and ~D specifiers 2020-06-08 00:09:55 +02:00
Markus Triska
9bb851d437 ENHANCED: format_//2 now evaluates arithmetic expressions for ~d, ~D, ~f, ~r and ~R
Example:

    ?- phrase(format_("~d", [1+2]), Cs).
       Cs = "3"
    ;  false.
2020-06-08 00:09:55 +02:00
Markus Triska
c8a9f8dcf5 better domain error in format_//2
Example:

    ?- format("", [hello]).
    caught: error(domain_error(empty_list,[hello]),format_//2)
2020-06-07 23:59:37 +02:00
Markus Triska
e8653ffe32 add type check for scalar argument in crypto_curve_scalar_mult/4
Suggested by @notoria in #576. Many thanks!
2020-06-07 18:51:13 +02:00
Markus Triska
5499df418a use secp256k1 in the example 2020-06-07 11:04:24 +02:00
Markus Triska
b586618411 ENHANCED: Faster Rust-based crypto_curve_scalar_mult/4 using OpenSSL. 2020-06-07 11:04:24 +02:00
Mark Thom
3b5730be54 s/prolog-implementation/prolog-system (cargo does not allow keywords to exceed 20 characters) 2020-06-04 23:29:48 -06:00
Mark Thom
961c4a1b9c bump version number 2020-06-04 23:25:21 -06:00
Mark Thom
72c5908f09 update prolog_parser version, correct atom_chars/2 (#379) 2020-06-04 23:23:49 -06:00
Mark Thom
2a588ff943 remove double_quotes checks from unnecessary places in system_calls.rs and elsewhere (#513, #542) 2020-06-04 21:03:41 -06:00
Mark Thom
24f11b5ae9 remove unreachable branch in increment_s_ptr (#575) 2020-06-03 22:05:46 -06:00
Mark Thom
1d44d99875 correct unexpected bad variables while ensuring better names are generated in order (#571) 2020-05-30 00:17:34 -06:00
Mark Thom
eebcdfb24f Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-27 11:11:37 -06:00
Mark Thom
526b56a650 order generation of variable names in attributed goals after toplevel variables (#465) 2020-05-27 11:11:26 -06:00
Mark Thom
20675f56e6 plug missing variables in equations (#488), exclude/3 regression (#452), incorrect answer substitution (#326) 2020-05-26 23:46:09 -06:00
Mark Thom
e5fbdeb3a9 Merge pull request #568 from triska/logo
How about an actual raven for a logo?
2020-05-27 00:19:41 -03:00
Markus Triska
7cc92ec1c1 ADDED: Logo.
Motivation and considerations:

- A Scryer certainly needs a raven. Ravens are among the most
  intelligent animals on earth.
- When writing Prolog programs, a few strokes are often enough.
- Purple is the colour most associated with magic and royalty,
  indicating the almost surreal and pure features provided by Scryer,
  in the lineage of Marseille Prolog.
- The shape of the silhouette looks a bit like an "S" for "Scryer".
- A square which surrounds the image is traditionally associated with
  finishing a proof (square, Latin "quadratum", has the same starting
  letters as "quod erat demonstrandum").

I call this raven: *Cryer*. Cryer is an archaic spelling for "crier",
an officer who makes public announcements in a court of justice.
The Prolog top-level likewise makes announcements about what is true.
2020-05-26 22:13:51 +02:00
Mark Thom
fe0bf6f2ef Merge pull request #524 from matt2xu/decode_utf8
Add decoding of UTF-8 sequences
2020-05-26 13:42:42 -03:00
Mark Thom
828c19d478 Merge pull request #563 from triska/master
ADDED: halt/1, halting with specified exit code
2020-05-23 16:02:05 -03:00
Mark Thom
15db77558c throw evaluable type error for unrecognized atoms in arith_eval_by_metacall 2020-05-23 13:33:05 -06:00
Mark Thom
18cf4a3bd3 Add type errors where appropriate in arith_eval_by_metacall (#392) 2020-05-23 13:07:40 -06:00
Mark Thom
e0378acfc2 throw type_error(number, E) in arith_eval_by_metacall (#392) 2020-05-23 12:39:29 -06:00
Mark Thom
53cb2af202 (**)/2 should always evaluate to floating point (#558) 2020-05-23 12:24:00 -06:00
Mark Thom
f74005a166 update (^)/2 in light of Draft Technical Corrigendum 3 (#559) 2020-05-23 12:13:48 -06:00
Markus Triska
b0df981b01 ADDED: halt/1, halting with specified exit code 2020-05-23 19:28:17 +02:00
Mark Thom
888d844ec5 address arity discrepancies in builtins.n and call/N (#525) 2020-05-22 23:57:32 -06:00
Mark Thom
3a7eb9fc0c Merge pull request #560 from notoria/cargo
Added some informations in Cargo.toml
2020-05-22 23:43:06 -03:00
Mark Thom
46276aacd9 Merge pull request #557 from mthom/docker
Merge Master with Docker branch
2020-05-22 23:42:55 -03:00
notoria
3a7a29868f Added some informations in Cargo.toml 2020-05-23 02:03:24 +02:00
Mark Thom
0060c8988a use -1 as eof_code for binary streams (#555) 2020-05-22 15:58:07 -06:00
Mark Thom
458f482c2a Merge pull request #556 from panasenco/docker
Valid Dockerfile and README
2020-05-22 18:54:10 -03:00
Matthieu Wipliez
cc9d6587a3 Implementation of UTF-8 bytes to chars 2020-05-22 23:33:12 +02:00
panasenco
dadf1b6ff9 Phrasing 2020-05-22 14:01:10 -07:00
panasenco
db56bb92f0 Fixed link in Dockerfile documentation. Updated README with working Docker link. Made general improvements to the Docker section of the README now that I'm not in a sleep-deprived zombie state. 2020-05-22 13:57:48 -07:00
panasenco
e82e36f51e Revert "Revert "Created and Tested Dockerfile""
This reverts commit e00d864199.
2020-05-22 13:57:48 -07:00
Mark Thom
f9aad34d28 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-22 14:50:51 -06:00
Mark Thom
b2d720b853 correct get_byte/1 not emitted -1 upon discovery of end_of_stream position (#555) 2020-05-22 14:50:40 -06:00
Mark Thom
c10c05e924 Merge pull request #552 from mthom/master
Scryer Dockerfile
2020-05-22 16:04:03 -03:00
Mark Thom
8909246725 Merge pull request #554 from triska/format3
ADDED: format/3, writing formatted output to a stream
2020-05-22 14:32:44 -03:00
Markus Triska
48c0b0ab3c ENHANCED: Faster format/3 for binary streams.
This speeds up web servers considerably when sending binary files.
2020-05-22 17:30:29 +02:00
Markus Triska
cbbed310c5 ADDED: format/3, writing formatted output to a stream
Both binary and text streams are supported.
2020-05-22 17:23:51 +02:00
Mark Thom
9e9c3b6342 modify int_pow so that a power of -1 is valid (#548) 2020-05-21 22:33:22 -06:00
Mark Thom
fefd262c2e Merge pull request #545 from triska/ed25519
ADDED: Public key signatures and signature verification with Ed25519
2020-05-21 11:30:47 -03:00
Markus Triska
1108c99688 document that lists of integers can be specified if encoding(octet) is used
This seems to be a good compromise: The API now strongly encourages
lists of characters, which are ideally suited to represent text, and
also allows lists of bytes if the encoding(octet) option is used.
2020-05-21 13:41:57 +02:00
Markus Triska
93da831ef0 correct mode indication for ed25519_verify/4
Noted by @notoria in #545. Many thanks!
2020-05-21 01:27:06 +02:00
Markus Triska
72bf45912e "PrivateKey" --> "KeyPair" 2020-05-21 00:14:15 +02:00
Markus Triska
5d94276c4f remove several mentions of list of bytes in predicate descriptions
This is to focus more on the intended core representation of text: In
Prolog, text is ideally represented as a list of characters, and this
is what we want to encourage, especially given Scryer's compact
representation for strings.

For the time being, library(crypto) still also supports lists of bytes in
several predicates. This will likely be removed at some point in the
future. Please use lists of characters to make your code future-proof.
2020-05-21 00:07:42 +02:00
Markus Triska
b43f27030e require PKCS#8 v2 format for better security
Notably, this format requires that the public key also be present.
This format is what ed25519_new_keypair/1 generates, and it is
strongly encouraged for higher security.
2020-05-20 23:55:21 +02:00
Markus Triska
2845f55157 ADDED: ed25519_keypair_public_key/2, relating a key pair to its public key 2020-05-20 23:43:28 +02:00
Markus Triska
e254d84710 clarify format of public key 2020-05-20 23:17:42 +02:00
Markus Triska
0ef7b5488d ADDED: ed25519_new_keypair/1 to dynamically create a new Ed25519 key pair 2020-05-20 23:11:56 +02:00
Markus Triska
56b04f8df8 use LessSafeKey to simplify the implementation of authenticated encryption
The nonce is explicitly specified, and the application programmer
must (and always had to) ensure that it is unique for a given key.
2020-05-20 22:32:39 +02:00
Markus Triska
2d036c6b25 "codes" --> "bytes"
Support for lists of bytes may be dropped from library(crypto). Use
lists of characters to make your code future-proof. Lists of
characters will always be supported due to their compactness,
and because Prolog applications should move towards characters.
2020-05-20 22:32:39 +02:00
Markus Triska
ad3be5c848 ADDED: Public key signatures and signature verification with Ed25519 2020-05-20 22:32:39 +02:00
Mark Thom
a0544cc345 revert printing of characters 2020-05-19 17:34:55 -06:00
Mark Thom
3245261162 Merge pull request #537 from triska/master
import member/2 from library(lists)
2020-05-19 15:16:38 -03:00
Markus Triska
21b7348c6a import member/2 from library(lists) 2020-05-19 20:13:06 +02:00
Mark Thom
54d4dc6e1e Merge pull request #536 from mthom/revert-517-docker
Revert "Created and Tested Dockerfile"
2020-05-19 15:00:29 -03:00
Mark Thom
e00d864199 Revert "Created and Tested Dockerfile" 2020-05-19 11:59:06 -06:00
Mark Thom
ad6fc89a24 Merge pull request #533 from triska/master
ADDED: Support for SHA-3 algorithms in crypto_data_hash/3
2020-05-19 14:23:12 -03:00
Mark Thom
fc4823ce8e Merge pull request #534 from triska/phrase_from_file_3
ADDED: phrase_from_file/3 in library(pio)
2020-05-19 14:22:59 -03:00
Markus Triska
0bd9831eec ADDED: phrase_from_file/3 in library(pio)
This allows us to specify type(binary), and read from binary files
with DCGs.
2020-05-19 18:52:18 +02:00
Markus Triska
dec2ef70c7 better error handling in crypto_data_hkdf/4
Noted by @notoria in #533. Many thanks!
2020-05-19 18:22:25 +02:00
Markus Triska
d19d8ea770 crypto_data_hkdf/4: do not crash for length > usize::max_value()
For now, we fail silently in such cases.

Noted by @notoria in #533. Many thanks!
2020-05-19 17:31:36 +02:00
Markus Triska
34f7752c0f use more fixnums in cryptographic routines 2020-05-19 17:03:02 +02:00
Markus Triska
da4d061067 correct option processing in crypto_data_decrypt/6 2020-05-19 17:02:33 +02:00
Markus Triska
85155439be use Fixnums for bytes in hashing.
Suggested by @notoria in #533. Many thanks!
2020-05-19 16:43:44 +02:00
Markus Triska
dd32e69061 use matching to select the hashing algorithm
Suggested by @notoria in #533. Many thanks!
2020-05-19 16:37:50 +02:00
Mark Thom
1c0c660c32 Merge pull request #517 from panasenco/docker
Created and Tested Dockerfile
2020-05-19 11:30:08 -03:00
Mark Thom
2eac902c33 correct fixnum overflow on negation (#528) 2020-05-19 10:45:54 -06:00
Markus Triska
9f5322d309 ADDED: Support for BLAKE2 algorithms in crypto_data_hash/3. 2020-05-19 12:44:10 +02:00
Markus Triska
f5c2f6f9e9 ADDED: Support for SHA-3 algorithms in crypto_data_hash/3 2020-05-19 12:10:46 +02:00
Mark Thom
e0e3b180e7 accomodate \0\ in partial strings, print null as \0\ (#267, #526), update prolog parser, version bump 2020-05-18 23:45:34 -06:00
Mark Thom
041dc039d4 add Addr::Lis as case in PartialStringTail (#530) 2020-05-18 12:27:26 -06:00
Mark Thom
ac755b0ada Merge pull request #527 from triska/master
Add type checks to increase robustness of library(crypto)
2020-05-18 11:18:58 -03:00
Mark Thom
c14259060c fix partial_string_tail panic (#530) 2020-05-18 11:14:27 -06:00
Markus Triska
a423eb5323 stronger validation of input lists for cryptographic routines
Example:

    ?- crypto_data_hkdf(Var, 32, Bs, []).
    caught: error(instantiation_error,must_be/2)

Reported by @notoria in #527. Many thanks!
2020-05-18 13:28:52 +02:00
Markus Triska
fd732550d8 crypto_data_hkdf/4: Fail if the length is too long.
Due to the way the counter is constructed in the HKDF specification,
the requested output length can be at most 255 times the size of the
digest algorithm's output.

Reported by @notoria in #527. Many thanks!
2020-05-18 13:21:38 +02:00
Markus Triska
fac7ba70c8 crypto_password_hash/3: fail if the number of iterations is too high
Discussed in #527.
2020-05-18 13:11:39 +02:00
Markus Triska
e9f8b35918 centralize reasoning about encoding 2020-05-18 11:29:35 +02:00
Markus Triska
23034dd4f5 raise instantiation errors for variable encoding
Reported by notoria in #527.

Note that from a declarative perspective, it would indeed be valid to
give answers for both available encodings.
2020-05-18 11:21:38 +02:00
Markus Triska
70ad44adfd type check for length argument in crypto_data_hkdf/4
Reported by @notoria in #527.
2020-05-18 11:12:59 +02:00
Markus Triska
95ca8a2630 throw instantiation error if the list of options contains a variable (#523)
Many thanks to @notoria for the test case!
2020-05-18 09:58:09 +02:00
panasenco
a7fd3c50e5 Updated README with Docker install instructions 2020-05-17 20:50:34 -07:00
panasenco
5639f40994 Managed to create a 77MB scryer-prolog Docker image 2020-05-17 20:50:34 -07:00
panasenco
33a8262334 New Dockerfile based on Fredrik Park's blog post - compilation fails with linker error 2020-05-17 20:50:34 -07:00
panasenco
9b4f7ad696 Created initial working Docker deployment 2020-05-17 20:50:33 -07:00
Mark Thom
eecd809d9a fix atom_codes (#521) 2020-05-17 16:34:52 -06:00
Mark Thom
240d3cb8f1 add Cargo.lock 2020-05-17 15:20:02 -06:00
Mark Thom
5720b7b94c eliminate Addr::CharCode (#519), fix atom_code panic (#521), fix failure involving lists of character codes (#520), bump version number 2020-05-17 15:19:27 -06:00
Markus Triska
3855d7ea02 type test for salt in crypto_password_hash/3 2020-05-17 22:01:22 +02:00
Mark Thom
9f3351469d solve overflow of left arithmetic shift (#518) 2020-05-17 12:20:22 -06:00
Mark Thom
2c4a0cf65b update Cargo.lock 2020-05-16 23:13:57 -06:00
Mark Thom
a8f360c8fd scryer version bump 2020-05-16 23:12:43 -06:00
Mark Thom
b3cff6555f propagate syntax errors from read_term when they're not UnexpectedEOF (#507) 2020-05-16 23:10:38 -06:00
Mark Thom
69706ecab0 fix sign error in shl on fixnum with n >= 63 (#499) 2020-05-16 23:00:37 -06:00
Mark Thom
05d3b97eae correct for second argument when (is)/2 is a tail call 2020-05-16 20:22:17 -06:00
Mark Thom
a38fb41e37 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-16 14:51:19 -06:00
Mark Thom
204ae377e3 restore old clpz.pl 2020-05-16 14:51:04 -06:00
notoria
3e5a652874 Enhanced Travis-CI (#512) 2020-05-16 11:51:53 -06:00
Markus Triska
862ae26631 Authenticated encryption in library(crypto), new encoding/1 option for hashes (#515)
* shorten n_newlines//1

* remove unneeded variable

* ADDED: authenticated encryption and decryption with ChaCha20-Poly1305

* ADDED: encoding/1 option for crypto_data_hash/3 and crypto_data_hkdf/4
2020-05-16 11:51:41 -06:00
Mark Thom
9e0208ec71 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-15 22:51:24 -06:00
Mark Thom
510530973c correct mishandled Addr::CharCode case in eq_test (#505) 2020-05-15 22:51:18 -06:00
Markus Triska
4e69301562 ADDED: Password-based key derivation (PBKDF2) (#509)
The new predicates crypto_password_hash/[2,3] let you store
passwords safely, and easily verify passwords later.
2020-05-15 10:49:23 -06:00
Matthieu Wipliez
df06d4b9a2 Work in progress: add char_utf8bytes (#493)
* Add char_utf8bytes to library

* Improved implementation

* Improve code + add chars predicate

* Update example

* Renamed string_utf8bytes to char_utf8bytes
2020-05-15 10:05:04 -06:00
Mark Thom
b60561c3bb fix existence_error in atom_chars/2, atom_codes/2 (#504, #506) 2020-05-14 22:33:28 -06:00
Mark Thom
fffa503968 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-14 22:25:50 -06:00
Mark Thom
8754157810 implement (div)/2 properly (#435) 2020-05-14 22:25:39 -06:00
Mark Thom
0763686892 Merge pull request #502 from triska/hkdf
ADDED: HMAC-based key derivation (HKDF) via crypto_data_hkdf/4
2020-05-14 15:13:32 -03:00
Markus Triska
50776748a7 ADDED: HMAC-based key derivation (HKDF) via crypto_data_hkdf/4
This is useful to generate keys and initialization vectors
from suitable input keying material, so that future predicates
for symmetric encryption can be used with appropriate parameters.
2020-05-14 20:07:59 +02:00
Mark Thom
c07274a6fa Merge pull request #501 from triska/elliptic_curves
ADDED: Reasoning about elliptic curves in library(crypto).
2020-05-13 20:58:39 -03:00
Markus Triska
4084005ee7 ADDED: Reasoning about elliptic curves in library(crypto).
This is useful to establish shared secrets, using ECDH key exchange.

Note that CLP(ℤ) goal expansion is currently disabled due to #445,
and this slows down the computations considerably for the time being.
2020-05-13 22:44:27 +02:00
Mark Thom
40fce574cf Merge pull request #500 from triska/master
ADDED: ripemd160 digest algorithm
2020-05-13 17:39:24 -03:00
Markus Triska
fd761735d4 ADDED: ripemd160 digest algorithm
This is used for example for Bitcoin address generation.
2020-05-13 22:36:40 +02:00
Mark Thom
9cb98bdcdc Merge pull request #496 from triska/master
ADDED: crypto_data_hash/3, computing cryptographically secure digests
2020-05-13 17:32:46 -03:00
Mark Thom
b5b1f7ff8a Merge pull request #498 from notoria/between
Enhanced between/3
2020-05-13 17:32:31 -03:00
notoria
a86019d53b Enhanced between/3 2020-05-13 21:21:46 +02:00
Markus Triska
8cd7d08573 ADDED: crypto_data_hash/3, computing cryptographically secure digests 2020-05-13 19:23:09 +02:00
Mark Thom
6d6f6ed8fc resolve warning messages (#495) 2020-05-12 20:36:21 -06:00
Mark Thom
c9aed1381f Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-12 20:28:42 -06:00
Mark Thom
49ba5f30c5 throw existence_error on failed put_byte write (#492) 2020-05-12 20:28:39 -06:00
Mark Thom
3c6149fd27 do not unwrap stream write, TcpStream::shutdown results (#492) 2020-05-12 18:51:42 -06:00
Mark Thom
23f804eda3 return true on unmatching partial strings in eq_test to indicate failure (#491) 2020-05-12 18:22:41 -06:00
Mark Thom
4e321db189 Merge pull request #494 from triska/master
ADDED: crypto_n_random_bytes/2, creating cryptographically secure random bytes
2020-05-12 19:44:07 -03:00
Markus Triska
716fde5784 ADDED: crypto_n_random_bytes/2, creating cryptographically secure random bytes
The ring crate is used since it will be needed also for future
predicates in library(crypto).
2020-05-13 00:36:27 +02:00
Mark Thom
c70b873397 reset current input in ReadQueryTerm 2020-05-11 15:29:28 -06:00
Mark Thom
4c0da691b8 record names of variables at root in write_term_to_heap (#487) 2020-05-10 21:48:38 -06:00
Mark Thom
d1d36f9af0 fix at_end_of_stream/1 (#479) 2020-05-10 16:06:15 -06:00
Mark Thom
56efb4ffba change VarNames to VNNames (#476) 2020-05-10 15:54:53 -06:00
Mark Thom
540bc71873 use heap_pstr_iter in AtomChars (#482) 2020-05-10 15:46:51 -06:00
Mark Thom
c1df7ead1a set past end of stream, set Byte to -1, Char and Code to end_of_file, at end of stream (#479) 2020-05-10 14:50:17 -06:00
Mark Thom
d170c807e3 deref addr's in list of atom_codes (#484) 2020-05-10 14:33:56 -06:00
Mark Thom
50c0abc786 correct failed partial string matching (#483) 2020-05-10 14:00:49 -06:00
Mark Thom
c5057127ee eliminate duplicates in term_variables/2, term_attributed_variables/2 (#481) 2020-05-10 13:43:39 -06:00
Mark Thom
ea7b1a9592 fix position property in stream_property/2 (#477) 2020-05-10 13:35:48 -06:00
Mark Thom
26d483f2d7 place cut after infinitely expanding VarList in write_term_to_chars/3 (#476) 2020-05-10 13:30:30 -06:00
Mark Thom
67fce58708 change wrong at_end_of_stream value 'end' to 'at' (#479) 2020-05-10 13:24:45 -06:00
Mark Thom
ea5771c442 detect source_sink domain error in open/4 (#480) 2020-05-10 13:19:14 -06:00
Mark Thom
fa8a1faeb3 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-09 20:08:09 -06:00
Mark Thom
d60a000af6 increase prolog_parser version 2020-05-09 20:07:57 -06:00
Mark Thom
3d68e2b74f Merge pull request #475 from notoria/debug
Debug & warnings
2020-05-09 18:35:16 -03:00
Mark Thom
42f6d48abf Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-09 15:05:09 -06:00
Mark Thom
5587957602 halt on Ctrl-D in toplevel (#473) 2020-05-09 15:04:36 -06:00
notoria
1d313ebf25 Removed the warnings 2020-05-09 22:30:39 +02:00
notoria
cf92349c1d Implemented Debug for the new data structures 2020-05-09 22:28:32 +02:00
Mark Thom
b0ae44bc25 Merge branch 'sockets-develop' 2020-05-09 14:26:29 -06:00
Mark Thom
0c94124fdf Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-09 14:26:22 -06:00
Mark Thom
22298ddb41 update README.md 2020-05-09 14:26:08 -06:00
Mark Thom
6f927b9941 add set_stream_position/2 2020-05-09 14:20:32 -06:00
Mark Thom
dc5626f34d Merge pull request #474 from triska/radix
ADDED: ~Nr and ~NR are now available for radix conversions
2020-05-09 15:09:14 -03:00
Mark Thom
2717ec2759 Merge pull request #471 from triska/master
ADDED: Initial version of library(crypto).
2020-05-09 14:33:58 -03:00
Markus Triska
d75449ea63 ADDED: ~Nr and ~NR are now available for radix conversions 2020-05-09 19:19:25 +02:00
Mark Thom
034f5b16bd add at_end_of_stream/{0,1} 2020-05-09 01:38:23 -06:00
Mark Thom
ff420f1e67 carry past_end_of_stream in WrappedStreamInstance 2020-05-09 01:34:56 -06:00
Mark Thom
5be771842f add stream_property/2 2020-05-09 00:56:17 -06:00
Markus Triska
a131c93a14 ADDED: Initial version of library(crypto). 2020-05-08 22:33:49 +02:00
Mark Thom
3da3546ef8 Merge pull request #468 from notoria/cont
Enhanced shift/1
2020-05-07 14:26:34 -03:00
notoria
47f5223c37 Enhanced shift/1 2020-05-07 19:10:21 +02:00
Mark Thom
b8c50eb0fe add peek_char/{1,2}, peek_byte/{1,2}, peek_code/{1,2} 2020-05-06 01:05:03 -06:00
Mark Thom
fe05082ddc add sockets library, use new type_error function from sockets system calls 2020-05-05 22:57:06 -06:00
Mark Thom
414acda9e0 add put_code/{1,2}, get_code/{1,2}, improve get_* predicates 2020-05-05 22:42:35 -06:00
Mark Thom
47e3a5e75a add put_byte/{1,2}, put_char/{1,2} 2020-05-05 17:42:18 -06:00
Mark Thom
573df892bc cleanup on reading predicates, add get_char/{1,2} 2020-05-05 16:54:40 -06:00
Mark Thom
bfced59949 clean up stream error handling, add get_byte/{1,2} 2020-05-05 16:09:17 -06:00
Mark Thom
9a63b1751b change EOFCode eof_action from end_of_stream to end_of_file, add echo_server.pl example 2020-05-05 14:15:16 -06:00
Mark Thom
53ae8b9bd1 add flush_output/{0,1}, past_end_of_stream 2020-05-05 14:10:49 -06:00
Mark Thom
bf3cc5a367 Merge pull request #460 from notoria/get_single_char
Fixed ctrl-c issue with get_single_char/1
2020-05-05 14:10:24 -03:00
notoria
ac00bc6b70 Fixed ctrl-c issue with get_single_char/1 2020-05-05 18:47:00 +02:00
Mark Thom
ab62603c5a add close/{1,2}, better EOF action handling in read_term 2020-05-05 00:38:21 -06:00
Mark Thom
dd247cd541 adapt write_term family, add handling for EOF actions. 2020-05-04 21:17:06 -06:00
Mark Thom
0d7a9f32d6 add open/3, write_term/3 2020-05-04 14:50:26 -06:00
Mark Thom
0d85ef4404 Merge pull request #453 from triska/master
disable goal expansion until #445 is resolved
2020-05-04 14:32:26 -03:00
Mark Thom
8e9273a96a test 2020-05-04 11:18:13 -06:00
Markus Triska
2dfdaaa4ba disable goal expansion until #445 is resolved 2020-05-04 18:55:52 +02:00
Mark Thom
407094cdcb merge 2020-05-03 23:36:26 -06:00
Mark Thom
0111db6744 improve answer substitutions at top-level 2020-05-03 23:35:21 -06:00
Mark Thom
a49230c0e1 Merge branch 'master' into sockets-develop 2020-05-03 23:09:13 -06:00
Mark Thom
d04abc2021 improve answer substitutions at top-level 2020-05-03 23:08:53 -06:00
Mark Thom
b5368207d6 merge with master 2020-05-03 18:49:15 -06:00
Mark Thom
b8400e0c92 make term{_attributed_}variables/2 order {attributed} variables by left-to-right occurrence 2020-05-03 18:43:23 -06:00
Mark Thom
ef6b6cd279 Merge pull request #450 from triska/master
do not project queue/2 attributes to residual goals
2020-05-03 20:34:47 -03:00
Mark Thom
e5903d8d6e use select/3 in gather_equations for detecting whether variables are distinct. 2020-05-03 20:31:12 -06:00
Mark Thom
e2a3db1b82 use copy_term/3 as source of attribute goals 2020-05-03 19:34:18 -06:00
Mark Thom
9e220e8416 restore previous focus upon character match failure in compare_pstr_to_string (#441) 2020-05-03 17:03:59 -06:00
Markus Triska
605c233753 do not project queue/2 attributes to residual goals 2020-05-04 00:54:43 +02:00
Mark Thom
aafe18c2b5 Merge pull request #449 from notoria/read
Completed read/1, ctrl-d is end_of_file
2020-05-03 15:27:46 -03:00
Mark Thom
262e8af813 version bump for prolog_parser 2020-05-03 13:46:34 -06:00
notoria
75aa4ce8a0 Completed read/1, ctrl-d is end_of_file 2020-05-03 19:54:17 +02:00
Mark Thom
a494cdaf92 use complete strings in FileToChars (#430) 2020-05-03 02:54:49 -06:00
Mark Thom
848425418b Project goals of query variables (#362) 2020-05-02 22:27:32 -06:00
Mark Thom
989bed88fe wrap support code in modules 2020-05-02 21:26:36 -06:00
Mark Thom
99f66200f7 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-02 18:47:53 -06:00
Mark Thom
b642bd2cfd add term_attributed_variables/2 (#422) 2020-05-02 18:46:29 -06:00
Mark Thom
c062b7c9da Merge pull request #443 from notoria/arithmetic
Implemented expmod/4
2020-05-02 12:00:44 -03:00
notoria
7df7901532 Implemented expmod/4 2020-05-02 14:56:07 +02:00
Mark Thom
9dabce819a remove now unnecessary dependencies, correct ordering of ! in (;)/3 2020-05-01 23:38:44 -03:00
Mark Thom
a019109857 Merge pull request #440 from notoria/arithmetic
Enhanced number_to_rational/2 and number_to_rational/3
2020-05-01 21:48:55 -03:00
Mark Thom
46cdf14ecc Merge pull request #439 from notoria/cli2
Enhanced command line?
2020-05-01 21:45:03 -03:00
Mark Thom
fd5ff20b68 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-05-01 21:40:45 -06:00
Mark Thom
81f9666e82 cut after compound check in (;)/2 only after semicolon_compound_selector succeeds 2020-05-01 21:40:36 -06:00
Mark Thom
aa8659d5c7 insert cuts where needed into (;)/3 (#434) 2020-05-01 18:52:01 -06:00
notoria
9df2df0f9f Enhanced number_to_rational/2 and number_to_rational/3 2020-05-02 02:36:23 +02:00
notoria
98d38d763b Added $scryer_prolog_version/1 2020-05-02 02:19:22 +02:00
notoria
319a4622b3 Enhanced command line 2020-05-02 01:02:06 +02:00
Mark Thom
59b4c6dacb Merge pull request #437 from triska/master
use ℤ
2020-05-01 19:08:45 -03:00
Markus Triska
ec6d725587 use ℤ
This is now possible thanks to the great contribution by @matt2xu.

Many thanks!
2020-05-02 00:06:16 +02:00
Mark Thom
6f19649186 Merge pull request #436 from mthom/revert-419-cli
Revert "Enhanced command line"
2020-05-01 18:43:37 -03:00
Mark Thom
6a583b9b5b Revert "Enhanced command line" 2020-05-01 15:43:20 -06:00
Mark Thom
6617b79cd8 Merge pull request #419 from notoria/cli
Enhanced command line
2020-05-01 18:32:02 -03:00
Mark Thom
46b695d093 accept any and all characters in comment chars 2020-05-01 16:39:27 -06:00
notoria
de8a017e80 Enhanced command line #2 2020-05-01 18:52:41 +02:00
Mark Thom
b71ec91f57 Merge pull request #432 from triska/master
correct overeager CLP(ℤ) goal expansion
2020-05-01 13:41:43 -03:00
Mark Thom
1b7c226779 correct failing character match in compare_pstr_to_string (#397) 2020-05-01 10:29:10 -06:00
Markus Triska
ca5a5b4392 correct overeager CLP(ℤ) goal expansion
For instance, consider:

    t(X) :- X #= 1.

We *cannot* expand this to:

    ?- listing(t/1).
    t(A) :-
       (  integer(A) ->
          A=:=A
       ;  (  var(A) ->
             true
          ;  true,
             clpz:clpz_equal(A,A)
          )
       ).

Also, a new binding *must not* be dragged outside of disjunctions,
since the code may look for example like this:

        i(X) :-
            (   X #= 3
            ;   X #= 4
            ).

This commit fixes such issues, and still rewrites CLP(ℤ) expressions
as far as possible already at compilation time.

For example:

    n(X) :- X #= 1+3.

This is now compiled to (note that 1+3 is evaluated to 4):

    ?- listing(n/1).
    n(A) :-
       (  integer(A) ->
          A=:=4
       ;  (  var(A) ->
             A=4
          ;  B=4,
             clpz:clpz_equal(A,B)
          )
       ).

Ideally, it should be compiled to:

    n(4).
2020-05-01 18:29:00 +02:00
notoria
6ae7ae0210 Enhanced version 2020-05-01 16:46:31 +02:00
notoria
b911d2fda4 Enhanced command line 2020-05-01 16:19:06 +02:00
Mark Thom
847a92f580 map single character atoms down to characters in constant_index 2020-05-01 01:34:09 -06:00
Mark Thom
a346493de1 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-30 18:20:51 -06:00
Mark Thom
efd5d6efab use slightly better names in indexing functions 2020-04-30 18:20:42 -06:00
Mark Thom
b6df5a4b7f only add expanded goals to dynamic clause code (#416) 2020-04-30 17:53:26 -06:00
Mark Thom
34ae56e319 correct queue_len += queue_len; to queue_len += queue.len(); (#416) 2020-04-30 15:31:01 -06:00
Mark Thom
5870824d01 Merge pull request #425 from triska/master
enable goal expansion for CLP(ℤ) goals
2020-04-30 18:20:27 -03:00
Markus Triska
1dbadbfc35 enable goal expansion for CLP(ℤ) goals
Example:

    integer_successor(I0, I) :- I #= I0 + 1.

Yielding:

    ?- listing(integer_successor/2).
    integer_successor(A,B) :-
       (  integer(B) ->
          (  integer(A) ->
             B=:=A+1
          ;  C is B,
             clpz:clpz_equal(C,A+1)
          )
       ;  (  integer(A) ->
             (  var(B) ->
                B is A+1
             ;  C is A+1,
                clpz:clpz_equal(B,C)
             )
          ;  clpz:clpz_equal(B,A+1)
          )
       ).

Thus, fast low-level arithmetic is used whenever possible.
2020-04-30 23:09:15 +02:00
Mark Thom
d3f1cd7411 index atoms with operators against the same atom with no operator (#387) 2020-04-30 15:09:05 -06:00
Mark Thom
a821daadd3 Merge pull request #420 from triska/master
correct verify_attributes/3 for variables that have no CLP(ℤ) attribute attached (#373)
2020-04-30 13:32:21 -03:00
Markus Triska
a39f4b4487 correct verify_attributes/3 for variables that have no CLP(ℤ) attribute attached (#373)
Example:

    ?- freeze(B, queen_value_truth(C,N,B)), Q #= N #<==> B.
       clpz:(Q#=N#<==>B), clpz:(B in 0..1), freeze:freeze(B,queen_value_truth(C,N,B))
    ;  false.
2020-04-30 18:10:09 +02:00
Mark Thom
f7b401b9b6 fix user:goal_expansion 2020-04-30 09:28:11 -06:00
Mark Thom
c342d18f92 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-30 00:01:12 -06:00
Mark Thom
e0e52a3090 fix 'drain lower bound was too large', store user-level expansions to modules (#416) 2020-04-30 00:01:00 -06:00
Mark Thom
6f92480315 Merge pull request #418 from notoria/mediants
Documentation for arithmetic.pl
2020-04-29 18:53:00 -03:00
notoria
490d008edf Merge pull request #4 from triska/mediants
include library(arithmetic) in the overview
2020-04-29 23:48:07 +02:00
notoria
ccee17c573 Merge branch 'mediants' into mediants 2020-04-29 23:47:05 +02:00
Mark Thom
dd4832e40b add ordsets.pl to README 2020-04-29 18:42:17 -03:00
Mark Thom
ff5b870a9f Merge pull request #417 from notoria/mediants
Implemented predicate mediants/2 with Stern-Brocot tree
2020-04-29 18:33:35 -03:00
notoria
a371580201 Add rational_numerator_denominator/3, number_to_rational/2 and renamed stern_brocot/3 to number_to_rational/3 2020-04-29 23:30:14 +02:00
Markus Triska
b499c575bc include library(arithmetic) in the overview
Many thanks to @notoria for these very useful predicates!
2020-04-29 22:06:49 +02:00
notoria
f5a6268cef Add rational_numerator_denominator/3, number_to_rational/2 and renamed stern_brocot/3 to number_to_rational/3 2020-04-29 21:52:01 +02:00
Mark Thom
2df4083602 use select to filter variable lists when printing equations of two variables 2020-04-29 11:05:10 -03:00
Mark Thom
2495fb796d select variable names in write_eq based on whether RHS is a variable (#326) 2020-04-29 10:56:17 -03:00
notoria
f7b49740c1 Removed predicate mediants/2 and added stern_brocot/3 2020-04-29 14:18:20 +02:00
Mark Thom
7e765fe726 correct answer substitution order, equating variables to themselves (#326) 2020-04-29 01:45:42 -06:00
notoria
1d339f74d1 Implemented predicate mediants/2 with Stern-Brocot tree 2020-04-29 02:44:13 +02:00
Mark Thom
a3bb288f01 check that lower bound on term expansion drain is below the len of the term expansion vector, queue (#416) 2020-04-28 19:22:20 -06:00
Mark Thom
0e1226573a print rational numbers using the rdiv operator when defined (#413) 2020-04-28 18:03:04 -06:00
Mark Thom
8151b65d12 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-28 17:20:25 -06:00
Mark Thom
eefd36b50d do length check in PartialString::range_from (#412) 2020-04-28 17:20:14 -06:00
Mark Thom
6f4d769187 Merge pull request #414 from triska/master
Small corrections, additions and improvements
2020-04-28 16:54:39 -03:00
Markus Triska
20b76a703a mention portray_clause/1 and listing/1 2020-04-28 18:27:46 +02:00
Markus Triska
dcc09b7bb5 mention backtrackable and non-backtrackable global variables 2020-04-28 18:22:18 +02:00
Markus Triska
4ea0dee90a use new nth0/3 from library(lists) 2020-04-28 17:59:49 +02:00
Markus Triska
e61116d35a use singleton variable, correct a mistake in maplist/8 2020-04-28 17:59:49 +02:00
Markus Triska
f7256c75d5 ADDED: nth0/3, relating indices to list elements 2020-04-28 17:59:49 +02:00
Markus Triska
2696fd1291 small typographic corrections 2020-04-28 17:59:49 +02:00
Markus Triska
b139620fba use new predicates from library(error) to throw type and domain errors 2020-04-28 17:59:49 +02:00
Mark Thom
97115a9c1c Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-28 01:41:11 -06:00
Mark Thom
36134c61b2 erase unnecessary stub from block of FileToChars 2020-04-28 01:40:59 -06:00
Mark Thom
77cf0fd87b don't append lists of attributes when binding attributed variables (#353) 2020-04-28 01:40:11 -06:00
Mark Thom
ab77a1cbc0 modify domain.pl example (#347) 2020-04-28 01:39:34 -06:00
Mark Thom
8490892493 Merge pull request #409 from triska/clp
add more information about Constraint Logic Programming (CLP)
2020-04-27 15:05:15 -03:00
Markus Triska
5f35dffa34 if_ --> if_/3 2020-04-27 19:53:25 +02:00
Markus Triska
89a4b5a6ff add more information about Constraint Logic Programming (CLP) 2020-04-27 19:48:46 +02:00
Mark Thom
931de7e39c Merge pull request #408 from triska/master
Introduce and use new predicates for throwing ISO errors
2020-04-27 14:35:17 -03:00
Markus Triska
ff41d6aef9 include the new library(random) in the overview
Many thanks to @notoria for this contribution!
2020-04-27 18:44:59 +02:00
Markus Triska
8e1ba58551 use new predicates from library(error) 2020-04-27 18:44:59 +02:00
Markus Triska
2b1692a860 ADDED: library(error): instantiation_error/1, domain_error/3, type_error/3
These predicates simplify throwing ISO errors.
2020-04-27 18:44:59 +02:00
Markus Triska
7a2981e21c include usage advice about probabilistic predicates 2020-04-27 18:44:59 +02:00
Mark Thom
f8717359d7 Merge pull request #406 from notoria/random
Created the library random and updated library clpb
2020-04-27 09:14:01 -03:00
Mark Thom
fe395e3a8c publish bimetatrans_ruleml_tests, move both files to own directory 2020-04-26 20:32:16 -06:00
Mark Thom
eb9fe851af Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-26 20:15:27 -06:00
notoria
d61851ad02 Added predicate random_integer and updated clpb 2020-04-27 01:52:19 +02:00
notoria
de7a408903 Created the library random and moved some predicates from iso_ext 2020-04-26 23:37:22 +02:00
Mark Thom
4b0f60fe71 Merge pull request #405 from triska/master
Two small documentation additions
2020-04-26 17:20:58 -03:00
Markus Triska
a167bcff5e add library(cont) to the list 2020-04-26 21:57:37 +02:00
Markus Triska
fb812e6335 add more information about tabling 2020-04-26 21:57:37 +02:00
Mark Thom
3fd557c74a Merge pull request #402 from notoria/pio
Small patch for library pio
2020-04-26 12:17:09 -03:00
notoria
9b1272da51 Small patch for library pio 2020-04-26 14:54:20 +02:00
Mark Thom
ae2402f4a7 Merge pull request #399 from notoria/debug
Implemented the Debug trait for all data structures
2020-04-25 23:35:27 -03:00
notoria
c98e869564 Implemented the Debug trait for all data structures 2020-04-26 02:20:24 +02:00
Mark Thom
e1a019ec56 Merge pull request #398 from triska/master
Several smaller improvements
2020-04-25 17:20:24 -03:00
Mark Thom
2d7fcbf23d use proper module name in bimetatrans_ruleml 2020-04-25 12:55:36 -06:00
Markus Triska
b604177ca1 include library(pio) and library(charsio) in the description 2020-04-25 20:12:54 +02:00
Markus Triska
f27597cab5 update toplevel interaction 2020-04-25 20:12:54 +02:00
Markus Triska
40619c8184 ENHANCED: Throw domain errors in char_type/2 for wrong types
This is especially important because a few of our names diverge from
ctype(3), and we better inform programmers when the type they are
using is not available at all.
2020-04-25 20:12:54 +02:00
Markus Triska
b0a5df2838 use an anonymous variable 2020-04-25 19:59:46 +02:00
Mark Thom
ae9232a2cb Merge pull request #396 from notoria/phrase_from_file
Implemented phrase_from_file/2 and /2
2020-04-25 14:17:24 -03:00
notoria
ad28d0025a No trimming of the buffer 2020-04-25 18:20:20 +02:00
notoria
d6772c5ca5 Implemented phrase_from_file/2 and /2 2020-04-25 18:04:13 +02:00
Mark Thom
a2400767ed Merge pull request #391 from notoria/msb_lsb2
Implemented lsb/2 and msb/2
2020-04-25 12:58:03 -03:00
notoria
1873b655a8 Implemented lsb/2 and msb/2 2020-04-24 23:52:32 +02:00
Mark Thom
e27c2b59c8 Merge pull request #380 from notoria/char_type
Implementation of the predicate char_type for a subset
2020-04-23 21:57:03 -03:00
notoria
4b50608642 Implementation of the predicate char_type for a subset 2020-04-23 16:09:06 +02:00
notoria
e3a7f9eb7a Draft of an implementation of char_type 2020-04-22 12:57:18 +02:00
Mark Thom
c130b3a92e Merge pull request #381 from triska/master
ADDED: library(format) now provides a rudimentary version of listing/1
2020-04-21 21:16:40 -03:00
Markus Triska
20fb6d6669 ADDED: library(format) now provides a rudimentary version of listing/1
Example:

    :- dynamic(a/1).

    a(X) :- X = true, b(X).

Yielding:

    ?- listing(a/1).
    %@ a(A) :-
    %@    A=true,
    %@    b(A).
    %@    true.

listing/1 only works for predicates and DCGs that are declared dynamic/1.
2020-04-22 01:53:20 +02:00
Mark Thom
caf20cd43d Merge pull request #377 from triska/master
portray_clause/1 now correctly tracks variable names (#376)
2020-04-20 19:16:12 -03:00
Markus Triska
608d661355 portray_clause/1 now correctly tracks variable names (#376)
Example:

    ?- portray_clause((A :- B)).
    %@ A :-
    %@    B.
    %@    true
    %@ ;  ...

Also, change the indentation from 8 to 3 at the express request of @UWN.
2020-04-20 22:53:15 +02:00
Mark Thom
31c868818b Merge pull request #375 from notoria/sleep
Changed the error being thrown by sleep/1
2020-04-20 11:52:25 -03:00
Mark Thom
443c4b6cd0 speed unification of pairs of partial strings 2020-04-20 11:37:32 -06:00
Mark Thom
ee425bb7f0 change CPU_now to CpuNow 2020-04-20 10:37:00 -06:00
Mark Thom
9d1c026231 check for num in comparisons, bump num-rug-adapter to 0.1.3 2020-04-20 10:35:30 -06:00
notoria
6d7612ead6 Corrected the error being thrown by sleep/1 2020-04-20 16:36:57 +02:00
notoria
b3e31094ff Changed the error being thrown by sleep/1 2020-04-20 11:27:28 +02:00
Mark Thom
c9750fab2c Merge pull request #371 from notoria/sleep
Added the sleep predicate
2020-04-19 21:41:33 -03:00
Mark Thom
5a1348e4d1 do casts between different arithmetic types for comparison and equality (#372) 2020-04-19 21:34:59 -06:00
Mark Thom
b64d45a74e speed comparisons of partial strings 2020-04-19 20:58:53 -06:00
Mark Thom
ba5a4c3945 use default machine policies in term expansions 2020-04-19 19:54:23 -06:00
Mark Thom
9ba37a932b Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-19 16:43:32 -06:00
Mark Thom
8ce377d033 update toplevel comments, add mutable stack to zipped acyclic iterators 2020-04-19 16:01:35 -06:00
notoria
a7f3dafd81 Undo a workaround 2020-04-19 23:26:16 +02:00
notoria
fb38b4b906 Corrected bound 2020-04-19 23:04:51 +02:00
notoria
f0a1a90b0e Merge pull request #3 from triska/sleep
update comment
2020-04-19 22:44:48 +02:00
notoria
fb331d39a6 Thrown an error if T < 0 or T > 0xfffffffffffffbff in sleep(T) 2020-04-19 22:43:13 +02:00
Markus Triska
7a3e6e19b1 update comment 2020-04-19 22:36:27 +02:00
notoria
5a063c541d Added the sleep predicate 2020-04-19 21:35:49 +02:00
Mark Thom
eef25ec638 Merge pull request #370 from triska/master
ENHANCED: time(Goal) now also reports the time if Goal fails
2020-04-19 16:33:51 -03:00
Markus Triska
7141fb18c1 ENHANCED: time(Goal) now also reports the time if Goal fails 2020-04-19 21:13:15 +02:00
Mark Thom
2c92be5e3d Merge pull request #367 from triska/master
ADDED: library(time), providing time/1 for benchmarking
2020-04-19 14:29:09 -03:00
Mark Thom
cae0733149 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-19 12:58:54 -06:00
Mark Thom
5d6ca7a88e throw '' whenever an interrupt is made (#365, #366) 2020-04-19 12:58:44 -06:00
Markus Triska
23b8a4d364 add entry for time/1 2020-04-19 19:24:22 +02:00
Markus Triska
c0df8cb578 update answer to use the latest toplevel improvements 2020-04-19 19:18:47 +02:00
Markus Triska
4693c23a49 ADDED: library(time), providing time/1 for benchmarking
sleep/1 and predicates for reasoning about time stamps should also
be added to this library.
2020-04-19 19:18:47 +02:00
Mark Thom
86364ff278 Merge pull request #364 from triska/master
Documentation addition, and correction of error term
2020-04-18 22:54:17 -03:00
Markus Triska
60f1f1cb3d Restore the type_error, which was implemented correctly by @notoria.
This corrects f28e87b240:
in_character is a valid type by 7.12.2 Error classification!
2020-04-19 02:15:59 +02:00
Markus Triska
ab3c520006 document ~| format modifier to place a tab stop at this position
This works best when used in tandem with ~N+, since it is currently
equivalent to ~0| and does not take the actual text position into account.
However, when using relative positions, this works as intended.
2020-04-19 01:59:16 +02:00
Mark Thom
3798dcb98d Merge pull request #363 from triska/master
Delay toplevel output until after the goal succeeds
2020-04-18 20:37:32 -03:00
Mark Thom
9daf290432 remove SCCCutPolicy panic, revise (;)/2 so that comma'ed cuts are handled properly (#361) 2020-04-18 20:10:53 -06:00
Mark Thom
3438f88c1e drop $ naming convention inside '' when unnecessary 2020-04-18 20:06:52 -06:00
Mark Thom
2c8858ff2d use correct signs in fixnum remainders 2020-04-18 17:37:54 -06:00
Markus Triska
45ed9405b0 use the most recent improvements 2020-04-19 01:34:13 +02:00
Markus Triska
075ca78dd2 ENHANCED: Delay toplevel output until after the goal succeeds.
This is to accommodate goals that are used for their side-effects,
when we are interested in their output.

Examples:

    ?- portray_clause((a :- a)).
    a :-
            a.
       true
    ;  false.

    ?- format("hello~w~n", [!]).
    hello!
       true
    ;  false.
2020-04-19 01:34:03 +02:00
Mark Thom
1d964ef921 add domain and type errors for compare/3 (#296) 2020-04-18 14:37:14 -06:00
Mark Thom
0c6d9b1d3b Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-18 14:17:13 -06:00
Markus Triska
1713f1222b reintroduce "n" as a synonym for ";" and " " 2020-04-18 14:16:46 -06:00
Markus Triska
450591d5a9 ENHANCED: the toplevel interaction now supports RETURN as a synonym for "."
This is made possible due to the recent improvements by @notoria.
2020-04-18 14:16:46 -06:00
Markus Triska
5c4863dfb1 small simplifications 2020-04-18 14:16:46 -06:00
notoria
c6a82cbc07 Removed a check in get_single_char 2020-04-18 14:16:46 -06:00
notoria
cc8f074d33 Added Space for continuation 2020-04-18 14:16:46 -06:00
notoria
196d74c3a0 Fixed the predicate name when error is thrown 2020-04-18 14:16:46 -06:00
Markus Triska
f28e87b240 instead of a type error, use a domain error
The preceding use of atom_length/2 already ensures that C has the
correct type (i.e., atom). However, its domain may still be wrong,
if its length is greater than 1.
2020-04-18 14:16:46 -06:00
Markus Triska
2d77ef4245 use get_single_char/1 2020-04-18 14:16:46 -06:00
notoria
3f578e24b5 Removed $raw_input_read_char 2020-04-18 14:16:46 -06:00
notoria
fb5ee5e190 get_single_char reads Tab as \t 2020-04-18 14:16:46 -06:00
notoria
63e8378310 get_single_char reads Enter as \n 2020-04-18 14:16:46 -06:00
notoria
c24ebaf506 Moved get_single_char from builtins.pl to charsio.pl 2020-04-18 14:16:46 -06:00
notoria
d3a1f11dfe Added predicate for reading a single character 2020-04-18 14:16:46 -06:00
Mark Thom
f96e694ff8 bracket graphic token chars in toplevel.pl (#357) 2020-04-18 14:16:40 -06:00
Mark Thom
d5d635e50f slight tweaks to bimetatrans 2020-04-18 14:16:40 -06:00
Mark Thom
1ad4ce9822 index Constant::Usize (#355) 2020-04-18 14:16:40 -06:00
Mark Thom
3f971174e4 quote single dots only 2020-04-18 14:16:40 -06:00
Markus Triska
16e257ea32 ADDED: list_to_set/2, using the first occurrence of each element
Example:

    ?- list_to_set([B,a,b,a,B,A,b,A], Ls).
       Ls = [B,a,b,A]
    ;  false.
2020-04-18 14:16:40 -06:00
Mark Thom
37f1f8ac14 allow characters as atoms in Machine::use_module and Machine::use_qualified_module 2020-04-18 14:16:40 -06:00
Mark Thom
474fa9b3ec remove underscores in printed variables produced by write_term_to_chars (#340) 2020-04-18 14:16:40 -06:00
Mark Thom
6d7b14ceb5 don't count the terminator in PStrIter len 2020-04-18 14:16:40 -06:00
Mark Thom
af14832b6c quote dot when quoted(true) (#349) 2020-04-18 14:16:40 -06:00
Mark Thom
9ef185978f privilege new op declarations over old ones (#346) 2020-04-18 14:16:40 -06:00
Mark Thom
38bb44664c interrupt running queries and return to toplevel (#323) 2020-04-18 14:16:40 -06:00
Mark Thom
124d924ff5 write [a,b,c] correctly with write_canonical (#349) 2020-04-18 14:16:40 -06:00
Markus Triska
e8091d8add update the toplevel description, incorporating the latest changes 2020-04-18 14:16:40 -06:00
Mark Thom
500bd53b6a Merge pull request #360 from notoria/master
Add get_single_char predicate.
2020-04-18 14:10:26 -03:00
notoria
6996ca832d Merge pull request #2 from triska/get_single_char
New feature: RET can now be used as a synonym for "." in the interaction
2020-04-18 18:51:37 +02:00
notoria
2e15ab44ab Removed a check in get_single_char 2020-04-18 18:28:26 +02:00
Markus Triska
2ae5472872 reintroduce "n" as a synonym for ";" and " " 2020-04-18 18:09:55 +02:00
Markus Triska
98a32790cd ENHANCED: the toplevel interaction now supports RETURN as a synonym for "."
This is made possible due to the recent improvements by @notoria.
2020-04-18 17:56:37 +02:00
Markus Triska
6dcefcfb71 small simplifications 2020-04-18 17:52:43 +02:00
notoria
988366e37f Added Space for continuation 2020-04-18 16:57:45 +02:00
notoria
98a37905b8 Fixed the predicate name when error is thrown 2020-04-18 15:21:19 +02:00
notoria
bd832d0fbb Merge pull request #1 from triska/get_single_char
use get_single_char/1
2020-04-18 14:50:32 +02:00
Markus Triska
1f7e18f2a9 instead of a type error, use a domain error
The preceding use of atom_length/2 already ensures that C has the
correct type (i.e., atom). However, its domain may still be wrong,
if its length is greater than 1.
2020-04-18 14:39:30 +02:00
Markus Triska
105e9c8e88 use get_single_char/1 2020-04-18 14:33:11 +02:00
notoria
99e1a5f117 Removed $raw_input_read_char 2020-04-18 13:54:18 +02:00
notoria
b35b49f7b3 get_single_char reads Tab as \t 2020-04-18 13:33:42 +02:00
notoria
5d064b18e6 get_single_char reads Enter as \n 2020-04-18 13:30:52 +02:00
notoria
11ea92288d Moved get_single_char from builtins.pl to charsio.pl 2020-04-18 12:52:49 +02:00
notoria
1ea6ae9fd9 Added predicate for reading a single character 2020-04-18 11:49:28 +02:00
Mark Thom
57d739673a index Constant::Usize (#355) 2020-04-15 14:11:45 -06:00
Mark Thom
4d8f76e922 quote single dots only 2020-04-15 13:45:35 -06:00
Mark Thom
fb41d4ab0f Merge pull request #354 from triska/master
ADDED: list_to_set/2, using the first occurrence of each element
2020-04-15 13:19:54 -03:00
Mark Thom
023ee688d3 allow characters as atoms in Machine::use_module and Machine::use_qualified_module 2020-04-15 10:32:23 -06:00
Mark Thom
5f8f0d8573 remove underscores in printed variables produced by write_term_to_chars (#340) 2020-04-15 10:27:20 -06:00
Mark Thom
f56e0a6586 don't count the terminator in PStrIter len 2020-04-15 10:07:44 -06:00
Markus Triska
2c96420bc4 ADDED: list_to_set/2, using the first occurrence of each element
Example:

    ?- list_to_set([B,a,b,a,B,A,b,A], Ls).
       Ls = [B,a,b,A]
    ;  false.
2020-04-15 18:04:01 +02:00
Mark Thom
8d95eb57fa quote dot when quoted(true) (#349) 2020-04-15 00:54:32 -06:00
Mark Thom
a9a5e79e85 privilege new op declarations over old ones (#346) 2020-04-15 00:37:00 -06:00
Mark Thom
2b720b8d0b interrupt running queries and return to toplevel (#323) 2020-04-15 00:08:35 -06:00
Mark Thom
93a0ab7f0a write [a,b,c] correctly with write_canonical (#349) 2020-04-14 23:25:15 -06:00
Mark Thom
18dd55d1f4 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-14 23:15:01 -06:00
Mark Thom
c9074d8d96 properly iterate through UTF-8 strings (#350) 2020-04-14 23:14:47 -06:00
Mark Thom
f6c995157e clean up print_list_like 2020-04-14 14:26:30 -06:00
Mark Thom
a059a9fbdc print lists as strings when possible (#295) 2020-04-14 13:28:51 -06:00
Mark Thom
2ac6596ba9 Merge pull request #348 from triska/master
update the toplevel description, incorporating the latest changes
2020-04-14 14:29:40 -03:00
Markus Triska
2d1f57e839 update the toplevel description, incorporating the latest changes 2020-04-14 19:24:13 +02:00
Mark Thom
7799ed36f0 provide better variable names in write_term_to_chars/3 (#340) 2020-04-14 10:39:10 -06:00
Mark Thom
db5ed345bc improve writeX performance (#290) 2020-04-14 10:25:05 -06:00
Mark Thom
082c6a9e64 copy operator exports to impromptu modules (#307) 2020-04-14 01:03:49 -06:00
Mark Thom
b74a4d5225 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-14 00:40:57 -06:00
Mark Thom
16a572c250 change from xsi to iso in bimetatrans, correct atomic/1 failure (#343) 2020-04-14 00:40:51 -06:00
Mark Thom
6a8a2d6f56 Merge pull request #345 from triska/master
ADDED: group_pairs_by_key/2
2020-04-13 19:24:52 -03:00
Markus Triska
237c855f10 ADDED: group_pairs_by_key/2
Pairs must be keysorted and may also contain variables as keys.

Examples:

    ?-  group_pairs_by_key([1-a,1-b,2-c], Ps).
       Ps = [1-[a,b],2-[c]].

    ?-  group_pairs_by_key([X-a,X-b,2-c], Ps).
       Ps = [X-[a,b],2-[c]].
2020-04-14 00:10:33 +02:00
Mark Thom
15d18484e3 version bump 2020-04-13 11:17:50 -06:00
Mark Thom
378e9b5539 Merge pull request #327 from srenatus/sr/pass-argv-as-partial-strings
use partial strings for passing argv to toplevel.pl
2020-04-13 11:17:08 -03:00
Mark Thom
7a135bd87c Merge pull request #342 from srenatus/sr/fix-cargo-install
main: fix version reporting without git
2020-04-13 11:16:55 -03:00
Stephan Renatus
9e907e36e2 main: fix version reporting without git
Fixes #339.

At least I hope so. I didn't come up with an idea how to test this with
little effort.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-04-13 15:50:33 +02:00
Mark Thom
9ac71f304d Merge pull request #341 from triska/master
the workaround is no longer necessary, since #336 is now corrected
2020-04-13 09:13:17 -03:00
Markus Triska
ab9b604d02 the workaround is no longer necessary, since #336 is now corrected 2020-04-13 11:32:06 +02:00
Stephan Renatus
155645307a use partial strings for passing argv to toplevel.pl
In run_top_level: rename variables, make them partial strings

The rename is mostly cosmetic: all of argv is passed, and if argv
contains flags, goals, etc, it's more than filenames.

Using partial strings instead of atom came from discussions about how to
pass goals in the CLI, and can thus be considered preliminary work for
that.

In toplevel.pl: convert partial string to atom before passing it to
`use_module`.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-04-13 10:10:10 +02:00
Mark Thom
4ca7ac4851 use prolog_parser 0.8.50 (#336) 2020-04-13 00:32:41 -06:00
Mark Thom
02eb24cd57 correct partial string copying by resetting threshold to redirected partial string stubs to 0 2020-04-12 23:33:07 -06:00
Mark Thom
787fbe1bb6 use partial_string/1 in place of the removed string/1 in bimetatrans_ruleml.pl 2020-04-12 22:27:53 -06:00
Mark Thom
7678858bab update Cargo.lock 2020-04-12 22:01:59 -06:00
Mark Thom
bf7a28f07c bump version to 0.8.119 2020-04-12 21:59:22 -06:00
Mark Thom
9e54b1406c Merge pull request #338 from triska/master
also include a newline in portray_clause/1
2020-04-12 20:35:48 -03:00
Markus Triska
f52c9772a7 also include a newline in portray_clause/1 2020-04-13 01:24:15 +02:00
Mark Thom
ea5203d8c3 Merge pull request #337 from triska/master
ADDED: provide a rudimentary version of portray_clause/1
2020-04-12 20:10:21 -03:00
Mark Thom
0fad2f9953 make write_term_to_chars work with variable terms (#335) 2020-04-12 18:10:45 -06:00
Mark Thom
d3a9392421 provide read_term_from_chars/2 (#334) 2020-04-12 17:26:11 -06:00
Markus Triska
208927544d ADDED: provide a rudimentary version of portray_clause/1
At the moment, library(format) seems to be a fitting place.
In the eventual library organization, portray_clause/1 and
related predicates may be moved to their own dedicated library.
2020-04-13 01:04:52 +02:00
Mark Thom
7621155a89 change wording of QueryCannotBePostedAsFact to QueryCannotBeDefinedAsFact, remove old commented code in read.rs 2020-04-12 16:01:53 -06:00
Mark Thom
4ddc4ebf46 Merge pull request #333 from triska/master
incorporate the latest improvements in the description of partial strings
2020-04-12 16:00:01 -03:00
Markus Triska
786f0b5ca2 incorporate the latest improvements in the description of partial strings
As of 6e4b76a3b4, the use of
partial_string/3 can be replaced by (=)/2 in this example.
2020-04-12 20:46:22 +02:00
Mark Thom
b4ff429bfa Merge pull request #332 from triska/master
ENHANCED: ~w now supports compound terms, and ~q is now also available
2020-04-12 15:00:20 -03:00
Mark Thom
f2cf0ec459 move write_term_to_chars/3 to src/prolog/lib/charsio.pl 2020-04-12 14:42:39 -06:00
Mark Thom
0380d70a46 add write_term_to_chars/3 to iso_ext.pl (#288) 2020-04-12 14:29:28 -06:00
Mark Thom
28099b9812 correct misleading error for modules (#300) 2020-04-12 12:51:59 -06:00
Mark Thom
2ce4f602c0 be more judicious with at_cdr in print_string (#295) 2020-04-12 12:18:15 -06:00
Mark Thom
5e81fb4754 throw exception when attempting to post query as goal (#329) 2020-04-12 12:07:41 -06:00
Markus Triska
c9f1a95343 ENHANCED: ~w now supports compound terms, and ~q is now also available 2020-04-12 19:56:01 +02:00
Mark Thom
97d8d07947 recognize empty lists as partial strings (#328) 2020-04-11 23:08:15 -06:00
Mark Thom
4f0adad78e remove string/1, use a more general test for the partial_string/1 type test (#328) 2020-04-11 22:47:52 -06:00
Mark Thom
0499005db5 throw error when trying to use partial lists as DCG terminal-sequence (#286) 2020-04-11 22:40:29 -06:00
Mark Thom
aedffb3cfe remove unnecessary use of partial_string in bimetatrans example 2020-04-11 22:02:17 -06:00
Mark Thom
fff96e69db Merge pull request #310 from triska/bimeta_example
Bimeta example
2020-04-11 22:03:10 -03:00
Mark Thom
abc99c9dd8 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-11 21:59:25 -06:00
Mark Thom
6e4b76a3b4 compile special instructions for partial strings when recognized 2020-04-11 21:53:28 -06:00
Mark Thom
92d8642133 do not accept [X|Xs] patterns as DCG non-terminals (#286) 2020-04-11 21:52:45 -06:00
Mark Thom
184124586b Merge pull request #320 from triska/master
add library(freeze) to make zcompare/3 work
2020-04-09 12:26:31 -03:00
Markus Triska
4d32b6976a add library(freeze) to make zcompare/3 work 2020-04-08 22:09:59 +02:00
Mark Thom
45a99e576d Merge pull request #318 from triska/master
extend description of strings and partial strings
2020-04-08 16:59:13 -03:00
Markus Triska
fac6d54986 extend description of strings and partial strings
Also, explain in more detail what this feature means to Prolog
application programmers, and the strategic direction of Scryer.
2020-04-08 21:07:00 +02:00
Mark Thom
036c35729c Merge pull request #316 from triska/master
clpz_monotonic/0 --> monotonic/0
2020-04-08 13:18:42 -03:00
Markus Triska
e442fddc66 tuples_in/2 now works 2020-04-08 17:49:06 +02:00
Mark Thom
a3c3afba48 fix list index offset bug (#314) 2020-04-06 16:15:36 -06:00
Markus Triska
794ceac440 clpz_monotonic/0 --> monotonic/0 2020-04-06 23:05:57 +02:00
Mark Thom
6299d41cda mark clp(X) item as completed, restore clp(Z) library description 2020-04-05 21:26:27 -03:00
Mark Thom
2e5ce0249e Merge pull request #312 from triska/master
ADDED: CLP(ℤ), Constraint Logic Programming over Integers
2020-04-05 21:14:11 -03:00
Mark Thom
560298655b consolidate Cargo.lock 2020-04-05 20:34:49 -06:00
Mark Thom
4086df27b2 merge with master 2020-04-05 20:33:45 -06:00
Mark Thom
d76ae413c4 use fixnums in place of bignums where possible 2020-04-05 20:32:16 -06:00
Markus Triska
8b1df2e9ca ADDED: CLP(ℤ), Constraint Logic Programming over Integers
library(clpz) implements declarative integer arithmetic.

The most important predicates for reasoning about integers are:

    (#=)/2    equality
    (#\=)/2   disequality
    (#<)/2    less than
    (#>)/2    greater than
    (#=<)/2   less than or equal to
    (#>=)/2   greater than or equal to

In addition, the library provides several global constraints, such as
all_distinct/1 and global_cardinality/2, and reification predicates
that reflect the truth values of constraints into integer variables.

Enumeration predicates such label/1 and labeling/2 can be used to
search for solutions over finite domains.

Almost all Prolog programs also reason about integers. Therefore, I
recommend to add this library to your .scryerrc configuration file so
that declarative integer arithmetic is available in all your programs.

More information about CLP(ℤ):

    https://www.metalevel.at/prolog/clpz

Enjoy!
2020-04-06 01:59:41 +02:00
Mark Thom
c8855f97e8 allocate empty partial strings 2020-04-05 02:55:30 -06:00
Mark Thom
bbf1aa1668 use copy_term/3 to print residual goals (#254) 2020-04-05 02:55:04 -06:00
Mark Thom
141f3bcec3 harmonize partial strings with complete strings (#276), make Addr a copyable type 2020-04-03 10:22:46 -06:00
Mark Thom
8f11fd7c62 Merge pull request #306 from srenatus/sr/version-argument
main: add -v/--version flag
2020-04-03 00:35:51 -03:00
Mark Thom
9f960c25a5 add bimetatrans_ruleml.pl to examples 2020-03-30 20:00:08 -06:00
Markus Triska
11a616917a introduce and use nonterminal list//1
Example:

    ?- phrase(list(Ls), Ls0).
       Ls = [], Ls0 = []
    ;  Ls = [_A], Ls0 = [_A]
    ;  Ls = [_A,_B], Ls0 = [_A,_B]
    ;  Ls = [_A,_B,_C], Ls0 = [_A,_B,_C]
    ;  ...
2020-03-31 01:28:16 +02:00
Markus Triska
a89f03f27d embed literal lists directly in DCGs
Example use of direct embedding:

    ?- phrase("abc", Ls0, Ls).
       Ls0 = [a,b,c|Ls].
2020-03-31 01:24:15 +02:00
Markus Triska
3faf36440c naming: partial_list_ws//1 --> list_ws//1
A DCG describes a list, so "list" is an appropriate name.
2020-03-31 01:23:00 +02:00
Stephan Renatus
45d4f46024 main: skip args[0]
This is a bit pedantic, it's unlikely that the executable would be
called `-v` or `--version`. However, it seems slightly more correct to
disregard argv[0] when checking flags.
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-28 09:07:44 +01:00
Stephan Renatus
896f2aeb74 main: add -v/--version flag
Added a new dependency to take care of pulling in the version from git
at build time.

Args handling is minimalistic, but there wasn't any before, so I figured
this might do for now. (Eventually, some proper `--help` and usage
output might come in handy?)

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-27 19:59:50 +01:00
Mark Thom
7de39611f3 Merge pull request #305 from srenatus/sr/typo
examples/least_time.pl: fix typo
2020-03-27 14:35:17 -03:00
Stephan Renatus
7e6be23287 examples/least_time.pl: fix typo
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-27 18:29:17 +01:00
Mark Thom
cac76d4739 Merge branch 'master' into develop 2020-03-26 22:01:25 -06:00
Mark Thom
194e5dc94e initial commit for merge 2020-03-26 22:01:23 -06:00
Mark Thom
f7629362d7 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-03-19 20:42:37 -06:00
Mark Thom
ea0c396114 add least_time example 2020-03-19 20:42:11 -06:00
Mark Thom
057e2d8056 provide contextual information in the return value of try_in_situ_result 2020-03-19 20:41:58 -06:00
Mark Thom
487fe21e25 #278 2020-03-19 17:49:17 -06:00
Mark Thom
54dce9b60e Merge pull request #294 from triska/format
ENHANCED: format_//2 now supports ~a, ~d, ~Nd, ~D, ~ND, ~Nn, ~i and ~*
2020-03-19 20:00:40 -03:00
Markus Triska
f09a3142a6 ENHANCED: format_//2 now supports ~a, ~d, ~Nd, ~D, ~ND, ~Nn, ~i and ~* 2020-03-19 21:51:53 +01:00
Mark Thom
121c8d8a48 Merge pull request #293 from triska/documentation
update toplevel interaction
2020-03-17 13:55:05 -03:00
Markus Triska
b9561ec8db update toplevel interaction 2020-03-17 17:42:57 +01:00
Mark Thom
b1d8eff019 remove Addr::PStrTail (#276) 2020-03-17 02:03:29 -06:00
Mark Thom
f9c4a40d60 add set_input/1, set_output/1 2020-03-15 23:29:21 -06:00
Mark Thom
8e318f76a7 correct contextual quoting of chars 2020-03-15 21:15:42 -06:00
Mark Thom
7d21ea93a6 Merge pull request #289 from triska/documentation
include a short overview of notable libraries
2020-03-15 12:09:44 -03:00
Mark Thom
8630ba4a2d Merge pull request #291 from triska/toplevel
Two small toplevel features
2020-03-15 12:09:25 -03:00
Markus Triska
17a448e045 support 'h' to print help message during toplevel interaction 2020-03-15 13:42:51 +01:00
Markus Triska
7ff11dce35 support 'p' to reprint answer with max depth, allowing w -> p -> w ... 2020-03-15 13:26:49 +01:00
Markus Triska
e2a4854bcf include a short overview of notable libraries 2020-03-15 11:43:32 +01:00
Mark Thom
bef96e231d use max_depth at toplevel, allowing full printing of terms with the 'w' keypress (#287), put disjunctions on new lines (#278) 2020-03-15 00:35:59 -06:00
Mark Thom
325df8a6e3 add provisional max_depth option to write_term, speed printing of non-cyclic terms 2020-03-15 00:09:20 -06:00
Mark Thom
3620f72b6c output strings more efficiently 2020-03-14 18:17:11 -06:00
Mark Thom
42a90b2d40 don't emit overwriting warnings for term_expansion/2 or goal_expansion/2 2020-03-14 14:18:01 -06:00
Mark Thom
97aab6950c correct DCG descriptions of lists (#286) 2020-03-14 14:14:26 -06:00
Mark Thom
31258247b3 Give new answer variables readable names (#279) 2020-03-14 03:04:11 -06:00
Mark Thom
beed4e8aa8 print strings as strings only in the term expander 2020-03-13 21:05:25 -06:00
Mark Thom
c60a0bc062 print strings as strings (#285) 2020-03-13 18:24:13 -06:00
Mark Thom
733c2d4152 eliminate inner_numbervar_count 2020-03-13 17:12:35 -06:00
Mark Thom
79b5857f72 Merge pull request #284 from triska/master
ADDED: library(format), describing strings with format_//2
2020-03-13 17:06:27 -03:00
Mark Thom
7260eba26a allow module export of nonterminals (#281) 2020-03-13 15:40:03 -06:00
Mark Thom
7e7a1b2caf properly handle '\n' when quoted and not (#283, #280) 2020-03-13 15:32:56 -06:00
Mark Thom
99181e3302 fix -names (#275) 2020-03-13 13:49:12 -06:00
Mark Thom
d57d2b96d6 Revert "fix $VAR-names (#275) and properly print single control chars (#280)"
This reverts commit d3eb31e4c3.
2020-03-13 13:47:58 -06:00
Markus Triska
24bed8c548 ADDED: library(format), describing strings with format_//2
This library provides the nonterminal format_//2 to describe
formatted strings. format/2 is provided for impure output.

Usage:
======

phrase(format_(FormatString, Arguments), Ls)

format_//2 describes a list of characters Ls that are formatted
according to FormatString. FormatString is a string (i.e.,
a list of characters) that specifies the layout of Ls.
The characters in FormatString are used literally, except
for the following tokens with special meaning:

  ~w    use the next available argument from Arguments here,
        which must be atomic (a current limitation)
  ~f    use the next argument here, a floating point number
  ~Nf   where N is an integer: format the float argument
        using N digits after the decimal point
  ~s    use the next argument here, which must be a string
  ~N|   where N is an integer: place a tab stop at text column N
  ~N+   where N is an integer: place a tab stop N characters
        after the previous tab stop (or start of line)
  ~t    distribute spaces evenly between the two closest tabstops
  ~`Ct  like ~t, use character C instead of spaces to fill the space
  ~n    newline
  ~~    the literal ~

The predicate format/2 is like format_//2, except that it outputs
the text on the terminal instead of describing it declaratively.

If at all possible, format_//2 should be used, to stress pure parts
that enable easy testing etc. If necessary, you can emit the list Ls
with maplist(write, Ls).

The entire library only works if the Prolog flag double_quotes
is set to chars, the default value in Scryer Prolog. This should
also stay that way, to encourage a sensible environment.

Example:

?- phrase(format_("~s~n~`.t~w!~12|", ["hello",there]), Cs).
%@ Cs = [h,e,l,l,o,'\n','.','.','.','.','.','.',t,h,e,r,e,!] ;
%@ false.
2020-03-13 20:46:53 +01:00
Mark Thom
6c9e704aa8 sort variables in findall_with_existential before computing set difference (#282), trawl back changes of (#279) 2020-03-13 13:18:47 -06:00
Mark Thom
d3eb31e4c3 fix $VAR-names (#275) and properly print single control chars (#280) 2020-03-13 02:48:40 -06:00
Mark Thom
698b01f85a give new answer variables readable names (#279) 2020-03-13 02:40:06 -06:00
Mark Thom
4c88e97330 add current_output, printing of stream terms 2020-03-11 00:38:01 -06:00
Mark Thom
25babff827 add streams.rs, consume them in place of the old PrologStream 2020-03-09 11:56:16 -06:00
Mark Thom
23e833c69e update README.md 2020-03-08 18:02:06 -06:00
Mark Thom
22bb3fe876 replace termion with crossterm 2020-03-08 18:01:54 -06:00
Mark Thom
eee10d3ee7 fix broken conformity tests, quote left paren 2020-03-08 16:49:47 -06:00
Mark Thom
c7591045af represent the current_dir as an absolute path, not a relative one. (#262) 2020-03-07 16:00:10 -07:00
Mark Thom
6ddfef6383 count single character atoms as characters when generating first argument indices 2020-03-06 21:19:53 -07:00
Mark Thom
9852e30b39 compare characters directly in term comparison tests 2020-03-05 12:50:11 -07:00
Mark Thom
2d3ce32314 switch to representation error for partial strings (#267) 2020-03-01 23:21:35 -07:00
Mark Thom
d8e0bea110 correct handling of strings and partial strings as lists, print bar operator with surrounding spaces (#274) 2020-03-01 00:00:40 -07:00
Mark Thom
b2cf6a6ea8 update README 2020-02-29 15:23:48 -07:00
Mark Thom
2ebcd673c8 add s pointers for strings and partial strings, put_unsafe_value calls store earlier to avoid unnecessary heap writes (#273) 2020-02-28 23:42:40 -07:00
Mark Thom
aa5f186a96 allow set_prolog_flag in declarations 2020-02-28 21:42:22 -07:00
Mark Thom
934f73f696 remove cyclic_term/1 2020-02-27 16:19:48 -07:00
Mark Thom
993c6f0e7b actually do lco, and mark unsafe variables before the goals where they last occur, not just in the last goal 2020-02-27 16:17:20 -07:00
Mark Thom
1d79e22468 mention rustup.rs in README (#261) 2020-02-23 13:22:56 -07:00
Mark Thom
8ba92d8b99 update prolog_parser version, allow ('|') operator in DCGs (#274) 2020-02-23 13:16:14 -07:00
Mark Thom
af23258152 remove setof/3, bagof/3 non-determinism (#270) 2020-02-22 15:13:01 -07:00
Mark Thom
b2e50b42a3 rename non_iso.pl to iso_ext.pl (#265) 2020-02-22 00:58:37 -07:00
Mark Thom
003b4d0218 add comparisons between partial strings and string constants (#263) 2020-02-22 00:51:27 -07:00
Mark Thom
545472f9c4 correct misreported error in toplevel loop (#272) 2020-02-21 21:09:59 -07:00
Mark Thom
8f781c27f9 remove same_length/2 from clpb.pl 2020-02-21 17:21:15 -07:00
Mark Thom
589dc34b99 make partial strings accept characters (#268) 2020-02-21 13:08:03 -07:00
Mark Thom
564622e38b partial_string/3 should accept empty lists (#264) 2020-02-21 12:55:33 -07:00
Mark Thom
d3744d6f66 identify ground partial strings under (==) (#269) 2020-02-21 12:51:23 -07:00
Mark Thom
2613ef0633 adopt compatibility predicates from clpb and clpz into lists and pairs libraries 2020-02-21 12:48:15 -07:00
Mark Thom
be3cdcd71a fix #255 (I think?) 2020-02-21 01:02:52 -07:00
Mark Thom
d48ac09e25 correct PStrLocation offset bug in copier.rs 2020-02-20 10:59:42 -07:00
Mark Thom
e5a0ba7bf3 revert to older between.pl 2020-02-20 10:07:45 -07:00
Mark Thom
eb1980d286 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-02-19 21:44:18 -07:00
Mark Thom
424af312e5 update Cargo.lock and toml version 2020-02-19 21:42:39 -07:00
Mark Thom
a2a4c78c9a update README 2020-02-19 21:38:19 -07:00
Mark Thom
0457b38e41 add redone partial strings (#24, #95) 2020-02-19 21:34:09 -07:00
Mark Thom
617f803355 update between/3 to allow inf as upper bound 2020-02-19 15:55:56 -07:00
Mark Thom
d3da2683cb stop applying (=..)/2 to variables in tabling/trie.pl 2020-02-19 14:43:06 -07:00
Mark Thom
d97c670fcd Merge pull request #258 from aarroyoc/master
add n as an option to get the next solution
2020-02-19 12:10:48 -04:00
Mark Thom
8902bcb5ab use raw_block.rs for the heap backend 2020-02-16 16:30:36 -07:00
Mark Thom
5f51e264f2 change raw_vec to raw_block to avoid clashes with liballoc package 2020-02-13 20:05:46 -07:00
Mark Thom
1c4e2c0ed6 allow the frontier of the RawVec to be offset by a trait function 2020-02-12 23:52:30 -07:00
Mark Thom
5a6333129b move bump allocation logic to its own module 2020-02-12 23:34:05 -07:00
Mark Thom
969bd8f82c remove partial strings, but represent strings as lists when warranted by double_quotes 2020-02-12 22:12:42 -07:00
Adrián Arroyo Calle
a732bc9dc4 add n as an option to get the next solution 2020-02-10 17:51:26 +01:00
Mark Thom
1b5cf493d6 correct improper use of multifile directive in tabling/wrapper.pl 2020-02-06 10:12:57 -07:00
Mark Thom
0be8abd38c print extended characters recently added to alpha char set 2020-02-04 23:39:49 -07:00
Mark Thom
b71e8082d2 prolog_parser version bump 2020-02-04 23:35:03 -07:00
Mark Thom
034af296ff recommit Cargo.lock 2020-02-04 17:49:20 -07:00
Mark Thom
554b08a7d2 version bump, README.md tweak 2020-02-04 17:47:57 -07:00
Mark Thom
00b38549f5 enable cross-query memoization in the tabling library 2020-02-02 22:52:17 -07:00
Mark Thom
62b41ddb93 remove tabling/SLG resolution from nice-to-have list 2020-02-02 22:34:54 -07:00
Mark Thom
d83c5cf5f1 add tabling library, update README, make Cargo.toml non-local 2020-02-02 22:24:48 -07:00
Mark Thom
740bd528c4 add multifile and module scoped predicates 2020-02-02 22:13:14 -07:00
Mark Thom
668c9489c9 update README 2020-01-26 20:19:44 -07:00
Mark Thom
dcf2eadcf2 add preliminary multifile declaration support 2020-01-26 20:17:52 -07:00
Mark Thom
9c1064c1a3 use atom_concat in gensym.pl 2020-01-22 22:08:42 -07:00
Mark Thom
40bf5bc75f don't hold on to popped or frames 2020-01-20 20:59:30 -07:00
Mark Thom
6be2d8ccf2 correct bug in bb_b_put, correct stack truncation bug resulting in erroneous failures (affecting issue #255 and the in-progress tabling library) 2020-01-19 20:56:11 -07:00
Mark Thom
9958ad6f34 add prefixes to gensym keys 2020-01-13 21:01:09 -07:00
Mark Thom
728be8c259 add simple gensym library 2020-01-13 20:30:58 -07:00
Mark Thom
9a80d398e8 add listing sources to modules 2020-01-13 20:17:22 -07:00
Mark Thom
242c47bb92 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-01-03 00:47:56 -07:00
Mark Thom
85e37a9977 implement less defaulty interface in cont.pl 2019-12-23 12:19:18 -07:00
Mark Thom
dded56af78 remove l* languages 2019-12-23 11:49:20 -07:00
Mark Thom
3bf1cbbe6c push of preliminary delimited continuations library cont.pl (#136) 2019-12-20 22:27:49 -07:00
Mark Thom
4ef8ab6e76 merge with master 2019-12-19 20:04:30 -04:00
Mark Thom
837ae4cb17 preliminary cont work 2019-12-19 20:02:10 -04:00
Mark Thom
a4e352ba0d use Addr::StackCell(0,0) to indicate non-live local variables 2019-12-12 20:34:50 -07:00
Mark Thom
02d8b1441d expand goals inside (\+)/1 2019-12-11 21:42:15 -07:00
Mark Thom
196784bd09 change goal and term expansions, change call/N to use goal expansions 2019-12-10 21:36:02 -07:00
Mark Thom
b0fa45cd33 correct odd accidental change to clpb.pl 2019-12-08 11:44:01 -07:00
Mark Thom
923c9d4ad8 remove zeroing out from Stack::truncate 2019-12-08 11:43:22 -07:00
Mark Thom
2be7070e1a revert arithmetic code 2019-12-08 00:17:55 -07:00
Mark Thom
f16c2a6e99 update tests 2019-12-07 19:21:09 -07:00
Mark Thom
d6e75110a5 reconcile latest changes against stack changes 2019-12-07 18:59:03 -07:00
Mark Thom
3d2c4f0801 add backtracking of attributed variable data 2019-12-06 20:52:40 -04:00
Mark Thom
5ccd334555 resolve panic caused by lingering attribute goals (#253) 2019-12-06 15:22:28 -04:00
Mark Thom
90e1c990e5 print equations between variables (#228, #252) 2019-12-06 10:30:16 -04:00
Mark Thom
018b076835 binding attributed variables more eagerly after each implementation of verify_attributes/3 has been called (#248) 2019-12-05 00:33:46 -07:00
Mark Thom
9ae029b04d pop AND stack frames after unwinding the trail (#250) 2019-12-03 23:11:57 -07:00
Mark Thom
43b39538ff correct attributed variables bugs 2019-12-03 22:59:51 -07:00
Mark Thom
738ea59e23 fix copy_term/3 infinite looping on cyclic terms 2019-12-03 22:01:38 -07:00
Mark Thom
33c60d3434 Merge branch 'master' of https://github.com/mthom/rusty-wam 2019-12-02 19:38:15 -07:00
Mark Thom
607673ddcb Merge branch 'master' of https://github.com/mthom/scryer-prolog 2019-12-02 17:06:28 -04:00
Mark Thom
fc8e55c582 correct copying of cyclic lists in copier.rs 2019-12-02 17:06:12 -04:00
Mark Thom
943e5eeb35 correct misprinting of attributed variables done by printer 2019-12-01 21:46:04 -07:00
Mark Thom
52488b875a add predicates to lists.pl 2019-12-01 19:30:40 -07:00
Mark Thom
c362cc6d34 fix list copying 2019-12-01 15:28:47 -07:00
Mark Thom
406d3520f1 delete freeze attribute in freeze::attribute_goals//1 2019-12-01 14:43:27 -07:00
Mark Thom
9b71866b54 properly copy attributed variables (#247)" 2019-12-01 14:42:59 -07:00
Mark Thom
e48f87fcf0 clear ball before setting it (#246) 2019-12-01 03:04:01 -07:00
Mark Thom
77e83a390c add sumlist/2 to lists.pl 2019-11-30 14:26:15 -07:00
Mark Thom
27b659c401 add sumlist/2 to lists.pl 2019-11-30 14:22:59 -07:00
Mark Thom
a4cacaeab2 compress the definition of freeze:attribute_goals//1 2019-11-30 14:12:33 -07:00
Mark Thom
0eb20a5d8e pop AND frames when safe to do so, suspend resizing of AND frames until a proper GC is implemented (#244) 2019-11-30 14:08:02 -07:00
Mark Thom
3e49db1a29 backtrack attributed variable bindings after failure (#242) 2019-11-29 13:47:22 -04:00
Mark Thom
2d719ab6b7 create a list of module-prefixed goals in copy_term/3 2019-11-29 10:59:20 -04:00
Mark Thom
34745f6242 clone attribute goals from copy_term/3, fetch attribute goals should be a move 2019-11-29 00:59:31 -07:00
Mark Thom
9c9c484ee4 add copy_term/3 (#232) 2019-11-29 00:44:23 -07:00
Mark Thom
335202b9d9 reset attributed variable state between toplevel queries (#242) 2019-11-28 19:08:08 -07:00
Mark Thom
f998d6a99f merge latest commit 2019-11-28 21:22:59 -04:00
Mark Thom
5723edd765 unsafe stack transition 2019-11-28 21:22:03 -04:00
Mark Thom
7eb0de7f52 preserve heap contents in between goal expansions (#240, #241) 2019-11-28 00:45:13 -07:00
Mark Thom
9ae901bd0d terms containing attributed variables are not ground (#239) 2019-11-27 14:13:18 -04:00
Mark Thom
1dec482e22 use in situ code directory from metacall if conventional lookup fails (#238) 2019-11-27 00:52:30 -07:00
Mark Thom
0a665b79f2 add (:)/{3..12} to enable metacalls on module-prefixed predicates 2019-11-26 20:51:59 -07:00
Mark Thom
c3c53017f9 add ambiguity check for period printing, remove extraneous space between last goal and period (#237) 2019-11-26 19:38:43 -07:00
Mark Thom
834c57466f add operator exports to module declarations, treat them separately from predicate exports (#230)" 2019-11-25 23:09:49 -07:00
Mark Thom
4e887e3a87 generate module-level expansion code along with rest of module code 2019-11-24 15:47:34 -07:00
Mark Thom
7bf6a230f3 record module-level term_expansion and goal_expansion as inner predicates (#228) 2019-11-24 12:50:53 -07:00
Mark Thom
24ffdc2724 correct bug, dead code in toplevel.pl 2019-11-22 20:38:03 -07:00
Mark Thom
6899f051ac Merge branch 'master' of https://github.com/mthom/rusty-wam 2019-11-21 18:05:09 -07:00
Mark Thom
d9d77b3022 Merge branch 'master' of https://github.com/mthom/scryer-prolog 2019-11-21 16:26:13 -04:00
Mark Thom
b31b23e41c add conditional bracketing to equations printed by toplevel 2019-11-21 16:26:00 -04:00
Mark Thom
16418a47a8 Merge branch 'master' of https://github.com/mthom/rusty-wam 2019-11-20 23:50:54 -07:00
Mark Thom
1139b3b4c1 small test updates 2019-11-20 23:50:51 -07:00
Mark Thom
3277ecd13d Merge pull request #226 from malbarbo/num
Add feature num to use num crate in place of rug.
2019-11-20 23:51:55 -04:00
Marco A L Barbosa
37ff4a821c Add feature num to use num crate in place of rug. 2019-11-20 17:51:08 -03:00
Mark Thom
f82c6f3fed avoid overwriting IndexPtr's for clauses already declared dynamic (#227) 2019-11-20 10:50:33 -04:00
Mark Thom
d3842bb070 Merge pull request #234 from XVilka/patch-2
Fix README formatting
2019-11-19 20:14:00 -04:00
Mark Thom
2ab745016a Merge branch 'master' of https://github.com/mthom/rusty-wam 2019-11-19 20:09:44 -07:00
Mark Thom
5aaba8534f bump prolog_parser to version 0.8.35 2019-11-19 20:09:28 -07:00
Mark Thom
2b625b1094 commit Cargo.lock 2019-11-19 20:08:52 -07:00
Mark Thom
17f9695ab2 remove tests.rs module from main.rs 2019-11-19 10:13:59 -04:00
Anton Kochkov
c0a49b6a66 Fix README formatting 2019-11-19 18:48:46 +08:00
Mark Thom
66bebff01e add setup_call_cleanup tests, expand builtins tests 2019-11-18 23:17:56 -07:00
Mark Thom
6f9477f0bb rollback changes in snapshot handling 2019-11-17 21:07:16 -04:00
Mark Thom
de88fdc4dc correct failure to observe last call position in queries' 2019-11-17 20:18:11 -04:00
Mark Thom
c219d9ad5f Merge branch 'master' of https://github.com/mthom/scryer-prolog 2019-11-16 19:53:29 -04:00
Mark Thom
15927d7054 transition to unsafe and/or stack 2019-11-16 19:51:53 -04:00
475 changed files with 126112 additions and 35242 deletions

6
.dockerignore Normal file
View File

@@ -0,0 +1,6 @@
target
Dockerfile
README.md
.git
.gitignore
.gitmodules

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

2
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,2 @@
# Resolved all lints and formatted the codebase
9444e62df9820d6bfd96dbd8849e177bc5cecc2e

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
*.png binary
*.pl text eol=lf
*.rs text eol=lf diff=rust
*.md text eol=lf diff=markdown

52
.github/actions/setup-rust/action.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: 'Setup Rust'
inputs:
rust-version:
required: true
type: string
targets:
required: true
type: string
components:
required: false
default:
cache-context:
required: true
type: string
runs:
using: "composite"
steps:
- uses: dtolnay/rust-toolchain@master
id: toolchain
with:
toolchain: ${{ inputs.rust-version }}
targets: ${{ inputs.targets }}
components: ${{ inputs.components }}
- name: Install i686 dependencies
if: "contains(inputs.targets,'i686')"
shell: bash
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libssl-dev:i386 gcc-multilib clang -y
echo "CC=clang" >> $GITHUB_ENV
echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ inputs.cache-context }}_${{ inputs.targets }}_rustc-${{ steps.toolchain.outputs.cachekey }}_cargo-${{ hashFiles('**/Cargo.lock') }}
# Remove build artifacts for the current crate, since it will be rebuilt every
# run anyway, but keep dependency artifacts to cache them.
# Must be placed after actions/cache so its post step runs first.
- uses: pyTooling/Actions/with-post-step@v4.1.0
with:
main: bash ./.github/actions/setup-rust/cleanup.sh
post: bash ./.github/actions/setup-rust/cleanup.sh

13
.github/actions/setup-rust/cleanup.sh vendored Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
echo Cleanup workspace build artifacts and extra target output
# clean just the direct members of the current workspace, use cargo metadata to generalize to all rust projects
cargo clean -p `cargo metadata --no-deps --offline --format-version 1 | jq -r '[.workspace_members[]|split(" ")|.[0]]|join(" ")'`
# remove directories in /target/ that are not named `debug` or `release`
before=`du -s target | awk '{print $1}'`
find ./target -maxdepth 1 -type d ! -name debug ! -name release ! -name target -exec rm -r {} \;
after=`du -s target | awk '{print $1}'`
echo Deleted $(($before - $after)) bytes from target directory

238
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,238 @@
name: CI
on:
push:
branches:
- master
- rebis-dev
tags:
- "v**"
pull_request:
schedule:
- cron: '0 0 * * 3' # At 12:00 AM, only on Wednesday
workflow_dispatch:
permissions:
checks: write
jobs:
style:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
rust-version: stable
targets: x86_64-unknown-linux-gnu
components: clippy, rustfmt
cache-context: style
- name: Check formatting
run: cargo fmt --check
- name: Check clippy
run: cargo clippy --no-deps --all-targets
if: ${{ !cancelled() }}
read-msrv:
runs-on: ubuntu-22.04
outputs:
msrv: ${{ steps.read-declared-msrv.outputs.msrv }}
steps:
- uses: actions/checkout@v4
- id: read-declared-msrv
name: Read msrv from Cargo.toml rust_version field
run: echo "msrv=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name = "scryer-prolog") | ."rust_version"')" >> "$GITHUB_OUTPUT"
build-test:
runs-on: ${{ matrix.os }}
needs: [read-msrv]
strategy:
fail-fast: false
matrix:
include:
# operating systems
- { os: windows-latest, rust-version: stable, target: 'x86_64-pc-windows-msvc', publish: true }
- { os: macos-latest, rust-version: stable, target: 'x86_64-apple-darwin', publish: true }
# architectures
- { os: ubuntu-22.04, rust-version: stable, target: 'x86_64-unknown-linux-gnu', publish: true }
- { os: ubuntu-22.04, rust-version: stable, target: 'i686-unknown-linux-gnu', publish: true }
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true }
# Cargo.toml rust-version
- { os: ubuntu-22.04, rust-version: "${{ needs.read-msrv.outputs.msrv }}" , target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- uses: actionhippie/swap-space@v1
if: matrix.use_swap
with:
size: 10G
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
rust-version: ${{ matrix.rust-version }}
targets: ${{ matrix.target }}
cache-context: ${{ matrix.os }}
components: ${{ matrix.components }}
# Build and test.
- name: Build library
run: cargo build --all-targets --target ${{ matrix.target }} ${{ matrix.args }} --verbose
- name: Test
run: cargo test --target ${{ matrix.target }} ${{ matrix.test-args }} --all
- name: Check miri
if: matrix.miri
run: cargo miri test
# On stable rust builds, build a binary and publish as a github actions
# artifact. These binaries could be useful for testing the pipeline but
# are only retained by github for 90 days.
- name: Build release binary
if: matrix.publish
run: |
cargo rustc --target ${{ matrix.target }} ${{ matrix.args }} --verbose --bin scryer-prolog --release
echo "$PWD/target/release" >> $GITHUB_PATH
- name: Install cargo-deb for creating debian packages
if: ${{ matrix.publish && contains(matrix.target, 'linux') }}
run: cargo install cargo-deb --force --locked
- name: Build release debian packages
if: ${{ matrix.publish && contains(matrix.target, 'linux') }}
run: cargo deb --target ${{ matrix.target }}
- name: Publish release binary artifact
if: matrix.publish
uses: actions/upload-artifact@v4
with:
path: |
target/${{ matrix.target }}/release/scryer-prolog*
target/${{ matrix.target }}/debian/scryer-prolog*.deb
name: scryer-prolog_${{ matrix.os }}_${{ matrix.target }}
logtalk-test:
# if: false # uncomment to disable job
runs-on: ubuntu-22.04
needs: [build-test]
steps:
# Download prebuilt ubuntu binary from build-test job, setup logtalk
- uses: actions/download-artifact@v4
with:
name: scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu
- run: |
chmod +x release/scryer-prolog
echo "$PWD/release" >> "$GITHUB_PATH"
- name: Install Logtalk
uses: logtalk-actions/setup-logtalk@master
with:
logtalk-version: "3.70.0"
logtalk-tool-dependencies: false
# Run logtalk tests.
- name: Run Logtalk's prolog compliance test suite
working-directory: ${{ env.LOGTALKUSER }}/tests/prolog/
run: |
pwd
scryerlgt -g '{ack(tester)},halt.'
logtalk_tester -p scryer -g "set_logtalk_flag(clean,off)" -w -t 360 \
-f xunit \
-s "$LOGTALKUSER/tests/prolog" \
|| echo "::warning ::logtalk compliance suite failed"
# -u "https://github.com/LogtalkDotOrg/logtalk3/tree/$LOGTALK_GIT_HASH/tests/prolog/" \
- name: Publish Logtalk test logs
uses: actions/upload-artifact@v4
with:
name: logtalk-test-logs
path: '${{ env.LOGTALKUSER }}/tests/prolog/logtalk_tester_logs'
- name: Publish Logtalk test results artifact
uses: actions/upload-artifact@v4
with:
name: logtalk-test-results
path: '${{ env.LOGTALKUSER }}/tests/prolog/**/*.xml'
- name: Publish Logtalk test summary
uses: EnricoMi/publish-unit-test-result-action/composite@master
with:
check_name: Logtalk test summary
files: '${{ env.LOGTALKUSER }}/tests/prolog/**/*.xml'
fail_on: nothing
comment_mode: off
report:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
rust-version: stable
targets: x86_64-unknown-linux-gnu
cache-context: report
- name: Install CLI tools
run: |
cargo install cargo2junit --force
version=`yq -ptoml -oj -r '.package[] | select(.name == "iai-callgrind") | .version' Cargo.lock`
echo installing iai-callgrind "$version"
cargo install iai-callgrind-runner --force --version "$version"
sudo apt install valgrind -y
- name: Test and report
run: |
RUSTC_BOOTSTRAP=1 cargo test --all -- -Z unstable-options --format json --report-time | cargo2junit > cargo_test_results.xml
- name: Publish cargo test results artifact
uses: actions/upload-artifact@v4
with:
name: cargo-test-results
path: cargo_test_results.xml
- name: Publish cargo test summary
uses: EnricoMi/publish-unit-test-result-action/composite@master
with:
check_name: Cargo test summary
files: cargo_test_results.xml
fail_on: nothing
comment_mode: off
- run: cargo build --all-targets --release
- run: cargo test --bench setup --release
- run: cargo bench --bench run_iai -- --save-summary=json
- run: cargo bench --bench run_criterion
- run: cargo bench --bench run_criterion -- --profile-time 60
- name: Publish benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: |
target/criterion/*
target/iai/*
target/benchmark_inference_counts.json
# Publish binaries when building for a tag
release:
runs-on: ubuntu-20.04
needs: [build-test]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/download-artifact@v4
- name: Zip binaries for release
run: |
zip scryer-prolog_macos-latest.zip ./scryer-prolog_macos-latest_x86_64-apple-darwin/scryer-prolog
zip scryer-prolog_ubuntu-22.04_i686.zip ./scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu/release/scryer-prolog ./scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu/debian/scryer-prolog*.deb
zip scryer-prolog_ubuntu-22.04_x86_64.zip ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/release/scryer-prolog ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/debian/scryer-prolog*.deb
zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-msvc/scryer-prolog.exe
zip scryer-prolog_wasm32.zip ./scryer-prolog_ubuntu-22.04_wasm32-unknown-unknown/scryer-prolog.wasm
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
scryer-prolog_macos-latest.zip
scryer-prolog_ubuntu-22.04_i686.zip
scryer-prolog_ubuntu-22.04_x86_64.zip
scryer-prolog_windows-latest.zip
scryer-prolog_wasm32.zip

61
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Docker Publish
on:
push:
branches:
- 'master'
tags:
- 'v*.*.*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
# https://github.com/docker/setup-buildx-action
uses: docker/setup-buildx-action@v3
# Login against Docker registry
- name: Log into registry
# https://github.com/docker/login-action
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Extract Docker image tag from git tag. E.g. if git tag is "v0.19.1" then use
# Docker image tag "0.19.1". The "latest" tag reflects the most recent build on
# master.
- name: Extract Docker metadata
id: meta
# https://github.com/docker/metadata-action
uses: docker/metadata-action@v5
with:
images: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/scryer-prolog
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
# type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
# Build and push Docker image with Buildx
- name: Build and push Docker image
id: build-and-push
# https://github.com/docker/build-push-action
uses: docker/build-push-action@v6
# v4 adds SLSA Provenance attestation which is
# - unsupported by AWS Lambda
# - limited support by Google Cloud Run
# > If deploying a multi-architecture image, the manifest list must include linux/amd64.
# see https://github.com/docker/build-push-action/releases/tag/v4.0.0
# we might want to disable this if its a problem for someone
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
src/static_atoms.rs
target/ target/
Cargo.lock .direnv/

View File

@@ -1,13 +0,0 @@
language: rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust: nightly
fast_finish: true
script:
- cargo build --verbose --all
- cargo test --verbose --all

4188
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,168 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.116" version = "0.10.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
build = "build.rs" edition = "2021"
repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
readme = "README.md"
repository = "https://github.com/mthom/scryer-prolog"
license = "BSD-3-Clause" license = "BSD-3-Clause"
edition = "2018" keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"]
build = "build/main.rs"
# Remember to check CI
rust-version = "1.85"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["ffi", "repl", "hostname", "tls", "http", "crypto-full"]
ffi = ["dep:libffi"]
repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
hostname = ["dep:hostname"]
tls = ["dep:native-tls"]
http = ["dep:warp", "dep:reqwest"]
crypto-full = []
[lints.rust]
unexpected_cfgs = { level = "deny", check-cfg = [
'cfg(rust_version, values("1.87.0"))',
] }
[build-dependencies] [build-dependencies]
indexmap = "1.0.2" indexmap = "2.3.0"
proc-macro2 = "1.0.86"
quote = "1.0.36"
strum = "0.26"
strum_macros = "0.26"
syn = { version = "2.0.72", features = ['full', 'visit', 'extra-traits'] }
to-syn-value = "0.1.1"
to-syn-value_derive = "0.1.1"
version_check = "0.9.5"
walkdir = "2"
[dependencies] [dependencies]
dirs = "2.0.2" arcu = { version = "0.1.2", features = ["thread_local_counter"] }
downcast = "0.10.0" base64 = "0.22.1"
indexmap = "1.0.2" bit-set = "0.8.0"
lazy_static = "1.4.0" bitvec = "1"
libc = "0.2.62" blake2 = "0.10.6"
nix = "0.15.0" bytes = "1"
ordered-float = "0.5.0" chrono = "0.4.38"
prolog_parser = "0.8.34" cpu-time = "1.0.0"
ref_thread_local = "0.0.0" crrl = "0.9.0"
rug = "1.4.0" dashu = { version = "0.4.2", features = ["rand"] }
rustyline = "5.0.3" derive_more = "0.99.18"
dirs-next = "2.0.0"
divrem = "1.0.0"
futures = "0.3"
fxhash = "0.2.1"
git-version = "0.3.9"
indexmap = "2.3.0"
lazy_static = "1.5.0"
lexical = "7.0.4"
libc = "0.2.155"
libloading = "0.8"
scryer-modular-bitfield = "0.11.4"
num-order = { version = "1.2.0" }
ordered-float = "5.0.0"
phf = { version = "0.11", features = ["macros"] }
puruspe = "0.4.1"
rand = "0.8.5"
ring = { version = "0.17.8", features = ["wasm32_unknown_unknown_js"] }
ripemd = "0.1.3"
roxmltree = "0.20.0"
ryu = "1.0.18"
sha3 = "0.10.8"
smallvec = "1.13.2"
static_assertions = "1.1.0"
[dependencies.termion] scraper = { version = "0.23.1", default-features = false, features = [
version = "1.4.0" "errors",
] }
ego-tree = "0.10.0"
serde_json = "1.0.122"
serde = "1.0.204"
parking_lot = "0.12.4"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
crossterm = { version = "0.28.1", optional = true }
ctrlc = { version = "3.4.4", optional = true }
hostname = { version = "0.4.0", optional = true }
libffi = { version = "4.0.0", optional = true }
native-tls = { version = "0.2.12", optional = true }
# the version requirement of reqwest is kept low for compatibility with old deno versions
# that pin reqwest to 0.11.20
reqwest = { version = "0.11.0", optional = true }
rustyline = { version = "14.0.0", optional = true }
tokio = { version = "1.39.2", features = ["full"] }
warp = { version = "0.3.7", features = ["tls"], optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.15", features = ["js"] }
tokio = { version = "1.39.2", features = [
"sync",
"macros",
"io-util",
"rt",
"time",
] }
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
console_error_panic_hook = "0.1"
wasm-bindgen = "0.2.92"
wasm-bindgen-futures = "0.4"
serde-wasm-bindgen = "0.6"
web-sys = { version = "0.3", features = [
"Document",
"Window",
"Element",
"Performance",
] }
js-sys = "0.3"
ouroboros = "0.18"
[dev-dependencies]
current_platform = "0.2.0"
maplit = "1.0.2"
serial_test = "3.1.1"
[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dev-dependencies]
criterion = "0.5.1"
iai-callgrind = "0.12.1"
trycmd = "0.15.6"
[target.'cfg(not(any(target_os = "windows", all(target_arch = "wasm32", target_os = "unknown"))))'.dev-dependencies]
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
[profile.bench]
lto = true
opt-level = 3
[profile.release]
lto = true
opt-level = 3
debug = 2
[profile.wasm-dev]
inherits = "dev"
opt-level = 1
lto = "off"
[profile.wasm-release]
inherits = "release"
lto = "off"
panic = "abort"
codegen-units = 256
[[bench]]
name = "run_criterion"
harness = false
[[bench]]
name = "run_iai"
harness = false

34
Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
# See https://github.com/LukeMathWalker/cargo-chef
ARG DEBIAN_RELEASE=bookworm
ARG RUST_VERSION=1-${DEBIAN_RELEASE}
FROM rust:${RUST_VERSION} AS planner
WORKDIR /scryer-prolog
RUN cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM rust:${RUST_VERSION} AS cacher
WORKDIR /scryer-prolog
RUN cargo install cargo-chef
COPY --from=planner /scryer-prolog/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
FROM rust:${RUST_VERSION} AS builder
WORKDIR /scryer-prolog
COPY . .
# Copy over the cached dependencies
COPY --from=cacher /scryer-prolog/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME
RUN cargo build --release --bin scryer-prolog
FROM debian:${DEBIAN_RELEASE}-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends openssl \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin
ENV RUST_BACKTRACE=1
# Sanity check the binary: if it can't be executed (e.g. if there are missing libraries)
# then fail the build
RUN scryer-prolog --version
ENTRYPOINT ["/usr/local/bin/scryer-prolog"]

80
INDEX.dj Normal file
View File

@@ -0,0 +1,80 @@
# Scryer Prolog
```
?- append("Hello, ", X, "Hello, Scryer Prolog!").
X = "Scryer Prolog!".
```
![scryer](scryer.png){width=128 style=float:right;} [Scryer Prolog](https://github.com/mthom/scryer-prolog) is a free software ISO Prolog system intended to be an industrial
strength production environment *and* a testbed for bleeding edge research in
logic and constraint programming.
Some of the Scryer Prolog features are:
* ISO standard compliant
* Integrated constraint programming libraries: [clp(B)](/clpb.html), [clp(Z)](/clpz.html).
* [Definite Clause Grammars](/dcgs.html)
* Coroutining support ([`dif/2`](/dif.html), [`freeze/2`](/freeze.html), ...)
* [Tabling and SLG resolution](/tabling.html)
* Compact string representation
* Network libraries ([TCP sockets](/sockets.html), [HTTP server](/http/http_server.html), [HTTP client](/http/http_open.html), ...)
* [Cryptographical predicates](/crypto.html)
* [Foreign Function Interface](/ffi.html)
* WebAssembly support
* Usable as a library
* WAM based engine, cross-platform made in Rust
* _and more..._
Try Scryer Prolog without any installation! Use [Scryer Playground](https://play.scryer.pl), which uses the WASM version of Scryer Prolog.
## What is Prolog?
Prolog is a logic programming language created by [Alain Colmerauer](https://en.wikipedia.org/wiki/Alain_Colmerauer) and [Robert Kowalski](https://en.wikipedia.org/wiki/Robert_Kowalski) in 1972.
The idea behind Prolog is try to express a task in language similar to First Order Logic.
Prolog systems include _unification_ and _non-determinism_ as key concepts upon which we build programs.
A Prolog program is made up of predicates which define a relation between its arguments. A predicate
is made from clauses. A clause can be either a fact or a rule. There's also a toplevel, which we
can use to ask and reason about our task.
It's still to this day one of the best examples and one of the most popular languages in the field
of logic programming. That's because Prolog allows us to elegantly solve many tasks with short and
general programs.
If you want a more detailed description of Prolog, check [A Tour of Prolog](https://www.youtube.com/watch?v=8XUutFBbUrg).
If you want to learn more about Prolog history, check the videos [l'Aventure Prolog](https://www.youtube.com/watch?v=74Ig_QKndvE) and [50 years of Prolog and beyond](https://prologyear.logicprogramming.org/videos/PrologDay_Session_1_talk.mp4).
## Where can I learn Prolog?
There are a lot of classical Prolog books. Those books can teach you the basics of Prolog. Some
examples are: _The Art of Prolog (Shapiro)_, _Programming in Prolog (Clocksin, Mellish)_ and _The Craft
of Prolog (O'Keefe)_. However, most of them are not updated to _modern_ Prolog.
We recommend _[The Power of Prolog (Markus Triska)](https://www.metalevel.at/prolog)_ for modern Prolog. For reference about
the builtin Prolog modules and libraries in Scryer, check the documentation site. It's this!
## Downloads
The latest version of Scryer Prolog is *0.9.4*. And it's already useful for lots of tasks.
| Windows (64 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog_windows-latest_x86_64-pc-windows-msvc.zip) |
| macOS (Intel) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog_macos-11_x86_64-apple-darwin.zip) |
| macOS (ARM) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog-macos-arm.zip) |
| Linux (Ubuntu 20.04, 64 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog_ubuntu-20.04_x86_64-unknown-linux-gnu.zip) |
| Linux (Ubuntu 22.04, 64 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu.zip) |
| Linux (Ubuntu 22.04, 32 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-094/scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu.zip) |
Scryer Prolog can also be compiled from source, instructions are on the [GitHub README](https://github.com/mthom/scryer-prolog). It runs on Linux, macOS and Windows. Other operating systems may work but they're not regularly tested.
If you're in Linux, maybe your distribution already has an Scryer Prolog package.
There's also a [Docker image](https://github.com/mthom/scryer-prolog#docker-install) available.
## Support and discussions
If Scryer Prolog crashes or yields unexpected errors, consider filing
an [issue](https://github.com/mthom/scryer-prolog/issues).
To get in touch with the Scryer Prolog community, participate in
[discussions](https://github.com/mthom/scryer-prolog/discussions)
or visit our #scryer IRC channel on [Libera](https://libera.chat)!

973
README.md

File diff suppressed because it is too large Load Diff

95
benches/README.md Normal file
View File

@@ -0,0 +1,95 @@
# About benches
The `benches` directory contains benchmarks that test scryer-prolog performance.
Benchmarks are run via two harnesses:
* `criterion` - criterion performs statistical analysis of benchmark runs and is
great for benchmarking locally.
* `iai-callgrind` - this runs the benchmark with callgrind, which is able to
precisely track the number of instructions executed during the run. This is
especially helpful in a public CI runner context where neighboring VMs can
cause a very high wall time variance. While instructions executed is only
correlated with the desired metric (wall time), this is a good tradeoff for CI
where that metric is unreliable.
Run benchmarks with the following commands:
```
cargo bench --bench run_criterion
# run a particular criterion benchmark
cargo bench --bench run_criterion -- <benchmark_name>
# run in profiling mode which outputs flamegraphs. Set profile time in seconds:
cargo bench --bench run_criterion -- --profile-time <time>
# to run iai, you need valgrind installed and to install iai-callgrind-runner
# at the same version as is in Cargo.toml:
cargo install iai-callgrind-runner --version 0.7.3
cargo bench --bench run_iai
```
For consistency, both runners -- `run_iai.rs` and `run_criterion.rs` -- import
the same setup code from `setup.rs`.
## Setup
`setup.rs` contains the setup code to run benchmarks. `fn prolog_benches()` at
the top of the file is where the benchmarks are defined.
Benchmarks are organized around running queries against a prolog module file.
Before a benchmark starts, `benchmark.setup()` is called which reads the module
file and initializes a new `scryer_prolog::machine::Machine`.
Each benchmark measurement is done by running a query against the machine. In
the case of criterion each query is run many times, in the case of iai it's run
once.
## Adding benchmarks
This design is meant to suppoort defining lots of benchmarks.
To add a new benchmark:
* Add a new file `benches/[module].pl` that contains setup prolog code. Import
libraries, define predicates, etc.
* Add a new section in `setup.rs::prolog_benchmarks()` that refers to to the
file and write a query to be benchmarked.
* If the query mutates the machine, then use `Strategy::Fresh` so the criterion
benchmark will recreate a new machine for each benchmark run, otherwise use
`Strategy::Reuse` which has lower overhead. (This is not used by the iai
benchmark because it only runs once anyway.)
Some tips:
* The goal of benchmarking is to know if a library or engine change improved
performance or not.
* Once a benchmark is defined and named, avoid changing it's definition. If a
benchmark needs to change to be more useful, give the new definition a new
name instead. This will prevent charts from showing wild changes in
performance just because the definition changed (see previous).
* Aim for queries to execute in less than 0.5s realtime. Longer runtimes make it
easier for humans to see big differences, but benchmarks either run 10x slower
(iai) or execute repeatedly to attain statistical significance (criterion) and
in both cases benchmarking queries that take longer than about 0.5s are
cumbersome to run.
* Consider that the library runtime actually parses the text output of the top
level. So don't use custom outputs or it will fail to parse. Also keep the
output small so it doesn't just benchmark the ouput parsing code.
* DO test the output of the benchmark run, we don't want to count broken
benchmarks.
## CI
Both benchmark harnesses are run in `.github/workflows/ci.yaml` in the `report`
job, and the results are published as build artifacts.
## Todo
- [ ] Currently, the execution time to load a module is not benchmarked. It
would be nice to have at least one benchmark for loading a module (probably a
big one).
- [ ] Write a new action that downloads the test and benchmark results
artifacts, plots them over time, and publishes a report to github pages.

41
benches/csv.pl Normal file

File diff suppressed because one or more lines are too long

130
benches/edges.pl Normal file
View File

@@ -0,0 +1,130 @@
:- use_module(library(clpb)).
:- use_module(library(assoc)).
:- use_module(library(lists)).
:- use_module(library(pairs)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Contiguous United States and DC as they appear in SGB:
http://www-cs-faculty.stanford.edu/~uno/sgb.html
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
edge(al, fl).
edge(al, ga).
edge(al, ms).
edge(al, tn).
edge(ar, la).
edge(ar, mo).
edge(ar, ms).
edge(ar, ok).
edge(ar, tn).
edge(ar, tx).
edge(az, ca).
edge(az, nm).
edge(az, nv).
edge(az, ut).
edge(ca, nv).
edge(ca, or).
edge(co, ks).
edge(co, ne).
edge(co, nm).
edge(co, ok).
edge(co, ut).
edge(co, wy).
edge(ct, ma).
edge(ct, ny).
edge(ct, ri).
edge(dc, md).
edge(dc, va).
edge(de, md).
edge(de, nj).
edge(de, pa).
edge(fl, ga).
edge(ga, nc).
edge(ga, sc).
edge(ga, tn).
edge(ia, il).
edge(ia, mn).
edge(ia, mo).
edge(ia, ne).
edge(ia, sd).
edge(ia, wi).
edge(id, mt).
edge(id, nv).
edge(id, or).
edge(id, ut).
edge(id, wa).
edge(id, wy).
edge(il, in).
edge(il, ky).
edge(il, mo).
edge(il, wi).
edge(in, ky).
edge(in, mi).
edge(in, oh).
edge(ks, mo).
edge(ks, ne).
edge(ks, ok).
edge(ky, mo).
edge(ky, oh).
edge(ky, tn).
edge(ky, va).
edge(ky, wv).
edge(la, ms).
edge(la, tx).
edge(ma, nh).
edge(ma, ny).
edge(ma, ri).
edge(ma, vt).
edge(md, pa).
edge(md, va).
edge(md, wv).
edge(me, nh).
edge(mi, oh).
edge(mi, wi).
edge(mn, nd).
edge(mn, sd).
edge(mn, wi).
edge(mo, ne).
edge(mo, ok).
edge(mo, tn).
edge(ms, tn).
edge(mt, nd).
edge(mt, sd).
edge(mt, wy).
edge(nc, sc).
edge(nc, tn).
edge(nc, va).
edge(nd, sd).
edge(ne, sd).
edge(ne, wy).
edge(nh, vt).
edge(nj, ny).
edge(nj, pa).
edge(nm, ok).
edge(nm, tx).
edge(nv, or).
edge(nv, ut).
edge(ny, pa).
edge(ny, vt).
edge(oh, pa).
edge(oh, wv).
edge(ok, tx).
edge(or, wa).
edge(pa, wv).
edge(sd, wy).
edge(tn, va).
edge(ut, wy).
edge(va, wv).
independent_set(G, *(NBs)) :-
findall(U-V, (edge(U, V),G@<U), Edges),
setof(U, V^(member(U-V, Edges);member(V-U, Edges)), Nodes),
pairs_keys_values(Pairs, Nodes, _),
list_to_assoc(Pairs, Assoc),
maplist(not_both(Assoc), Edges, NBs).
not_both(Assoc, U-V, ~BU + ~BV) :-
get_assoc(U, Assoc, BU),
get_assoc(V, Assoc, BV).
independent_set_count(G, Count) :- independent_set(G, Sat), sat_count(Sat, Count).

2
benches/numlist.pl Normal file
View File

@@ -0,0 +1,2 @@
:- use_module(library(between)).
run_numlist(Upper, Head) :- numlist(1, Upper, L), L = [Head|_].

46
benches/run_criterion.rs Normal file
View File

@@ -0,0 +1,46 @@
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(not(target_os = "windows"))]
use pprof::criterion::{Output, PProfProfiler};
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
mod setup;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
fn bench_criterion(c: &mut Criterion) {
for (&name, bench) in setup::prolog_benches().iter() {
match bench.strategy {
setup::Strategy::Fresh => c.bench_function(name, |b| {
b.iter_batched(|| bench.setup(), |mut r| r(), BatchSize::LargeInput)
}),
setup::Strategy::Reuse => c.bench_function(name, |b| b.iter(bench.setup())),
};
}
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(not(target_os = "windows"))]
fn config() -> Criterion {
Criterion::default()
.sample_size(20)
.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)))
}
#[cfg(target_os = "windows")]
fn config() -> Criterion {
Criterion::default().sample_size(20)
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
criterion_group!(
name = benches;
config = config();
targets = bench_criterion
);
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
criterion_main!(benches);
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
fn main() {}

38
benches/run_iai.rs Normal file
View File

@@ -0,0 +1,38 @@
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
mod setup;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
mod iai {
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use scryer_prolog::LeafAnswer;
use super::setup;
#[library_benchmark]
#[bench::count_edges(setup::prolog_benches()["count_edges"].setup())]
#[bench::numlist(setup::prolog_benches()["numlist"].setup())]
#[bench::csv_codename(setup::prolog_benches()["csv_codename"].setup())]
fn bench(mut run: impl FnMut() -> Vec<LeafAnswer>) -> Vec<LeafAnswer> {
run()
}
library_benchmark_group!(
name = benches;
benchmarks = bench
);
main!(library_benchmark_groups = benches);
pub fn call_main() {
main()
}
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
fn main() {
iai::call_main();
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
fn main() {}

140
benches/setup.rs Normal file
View File

@@ -0,0 +1,140 @@
use std::{collections::BTreeMap, fs, path::Path};
use maplit::btreemap;
use scryer_prolog::{LeafAnswer, Machine, MachineBuilder, Term};
pub fn prolog_benches() -> BTreeMap<&'static str, PrologBenchmark> {
[
(
"count_edges", // name of the benchmark
"benches/edges.pl", // name of the prolog module file to load. use the same file in multiple benchmarks
"independent_set_count(ky, Count).", // query to benchmark in the context of the loaded module. consider making the query adjustable to tune the run time to ~0.1s
Strategy::Reuse,
btreemap! { "Count" => Term::integer(2869176) },
),
(
"numlist",
"benches/numlist.pl",
"run_numlist(1000000, Head).",
Strategy::Reuse,
btreemap! { "Head" => Term::integer(1) },
),
(
"csv_codename",
"benches/csv.pl",
"get_codename(\"0020\",Name).",
Strategy::Reuse,
btreemap! { "Name" => Term::string("SPACE") },
),
]
.map(|b| {
(
b.0,
PrologBenchmark {
name: b.0,
filename: b.1,
query: b.2,
strategy: b.3,
bindings: b.4,
},
)
})
.into()
}
pub enum Strategy {
#[allow(dead_code)]
Fresh,
Reuse,
}
#[allow(dead_code)]
pub struct PrologBenchmark {
pub name: &'static str,
pub filename: &'static str,
pub query: &'static str,
pub strategy: Strategy,
pub bindings: BTreeMap<&'static str, Term>,
}
impl PrologBenchmark {
pub fn make_machine(&self) -> Machine {
let program = fs::read_to_string(self.filename).unwrap();
let module_name = Path::new(self.filename)
.file_stem()
.and_then(|s| s.to_str())
.unwrap();
let mut machine = MachineBuilder::default().build();
machine.load_module_string(module_name, program);
machine
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub fn setup(&self) -> impl FnMut() -> Vec<LeafAnswer> {
let mut machine = self.make_machine();
let query = self.query;
move || {
use criterion::black_box;
black_box(
machine
.run_query(black_box(query))
.collect::<Result<Vec<_>, _>>()
.unwrap(),
)
}
}
}
#[cfg(test)]
mod test {
#[test]
fn validate_benchmarks() {
use super::prolog_benches;
use scryer_prolog::LeafAnswer;
use std::{fmt::Write, fs};
struct BenchResult {
pub name: &'static str,
pub setup_inference_count: u64,
pub query_inference_count: u64,
}
let mut results: Vec<BenchResult> = vec![];
for (_, r) in prolog_benches() {
let mut machine = r.make_machine();
let setup_inference_count = machine.get_inference_count();
let result: Vec<_> = machine
.run_query(r.query)
.collect::<Result<_, _>>()
.unwrap();
let query_inference_count = machine.get_inference_count() - setup_inference_count;
let expected = [LeafAnswer::from_bindings(r.bindings.clone())];
assert_eq!(result, expected, "validating benchmark {}", r.name);
results.push(BenchResult {
name: r.name,
setup_inference_count,
query_inference_count,
})
}
let mut json: String = Default::default();
json.push('[');
for r in results {
json.push('\n');
write!(
json,
r#"{{"name":"{}","setup_inference_count":{},"query_inference_count":{}}},"#,
r.name, r.setup_inference_count, r.query_inference_count
)
.unwrap();
}
json.pop(); // trailing comma
json.push_str("\n]");
fs::write("target/benchmark_inference_counts.json", json).expect("Unable to write file");
}
}

View File

@@ -1,56 +0,0 @@
extern crate indexmap;
use indexmap::IndexSet;
use std::env;
use std::fs::{File, copy, read_dir};
use std::io::Write;
use std::path::Path;
fn main()
{
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("libraries.rs");
let mut libraries = File::create(&dest_path).unwrap();
let mut library_index = IndexSet::new();
let paths = read_dir("./src/prolog/lib").unwrap();
for item in paths {
let item = item.unwrap().path();
if let Some(file_name) = item.file_name() {
if let Some(ext) = item.extension() {
if ext == "pl" {
let file_stem = item.file_stem().unwrap();
let file_str = file_stem.to_string_lossy().to_uppercase();
let dest = Path::new(&out_dir).join(file_name);
match copy(&item, dest) {
Ok(_) => {},
Err(e) => panic!("die: {:?}", e)
};
let include_line = format!("static {}: &str = include_str!(\"{}.pl\");\n",
file_str, file_stem.to_string_lossy());
libraries.write_all(include_line.as_bytes()).unwrap();
library_index.insert(file_stem.to_string_lossy().to_string());
}
}
}
}
libraries.write_all(b"\nref_thread_local! {
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
let mut m = IndexMap::new();\n").unwrap();
for item in library_index {
let line = format!("\n m.insert(\"{}\", {});", item, item.to_uppercase());
libraries.write_all(line.as_bytes()).unwrap();
}
libraries.write_all(b"\n\n m\n };
}").unwrap();
}

File diff suppressed because it is too large Load Diff

123
build/main.rs Normal file
View File

@@ -0,0 +1,123 @@
mod instructions_template;
mod static_string_indexing;
use instructions_template::generate_instructions_rs;
use static_string_indexing::index_static_strings;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR_STR;
use std::process::{Command, Stdio};
fn find_prolog_files(path_prefix: &str, current_dir: &Path) -> Vec<(String, PathBuf)> {
let mut libraries = vec![];
let entries = match current_dir.read_dir() {
Ok(entries) => entries,
Err(_) => return libraries,
};
for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
if entry.is_dir() {
if let Some(file_name) = entry.file_name() {
let file_name = file_name.to_str().unwrap();
let new_path_prefix = format!("{path_prefix}{file_name}/");
let new_libs = find_prolog_files(&new_path_prefix, &entry);
libraries.extend(new_libs);
}
} else if entry.is_file() {
let ext = std::ffi::OsStr::new("pl");
if entry.extension() == Some(ext) {
let name = entry.file_stem().unwrap().to_str().unwrap();
let lib_name = format!("{path_prefix}{name}");
libraries.push((lib_name, entry));
}
}
}
libraries
}
fn main() {
if version_check::is_min_version("1.87.0").unwrap_or(false) {
println!(r#"cargo:rustc-cfg=rust_version="1.87.0""#);
}
let has_rustfmt = Command::new("rustfmt")
.arg("--version")
.stdin(Stdio::inherit())
.status()
.is_ok();
if !has_rustfmt {
println!("Failed to run rustfmt, will skip formatting generated files.")
}
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("libraries.rs");
let mut libraries = File::create(dest_path).unwrap();
let lib_path = Path::new("src").join("lib");
let constants = find_prolog_files("", &lib_path);
let out_dir = std::env::var("OUT_DIR").unwrap();
writeln!(libraries, "{{").unwrap();
for (name, lib_path) in constants {
let path = format!("{}{}", MAIN_SEPARATOR_STR, lib_path.display());
writeln!(
libraries,
"m.insert(\"{name}\", include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), {path:?})));"
)
.unwrap();
}
writeln!(libraries, "}}").unwrap();
let instructions_path = Path::new(&out_dir).join("instructions.rs");
let mut instructions_file = File::create(&instructions_path).unwrap();
let quoted_output = generate_instructions_rs();
instructions_file
.write_all(quoted_output.to_string().as_bytes())
.unwrap();
if has_rustfmt {
format_generated_file(instructions_path.as_path());
}
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
let quoted_output = index_static_strings(&instructions_path);
static_atoms_file
.write_all(quoted_output.to_string().as_bytes())
.unwrap();
if has_rustfmt {
format_generated_file(static_atoms_path.as_path());
}
println!("cargo:rerun-if-changed=src/");
}
fn format_generated_file(path: &Path) {
Command::new("rustfmt")
.arg(path.as_os_str())
.spawn()
.unwrap_or_else(|err| {
panic!(
"{}: rustfmt was detected as available, but failed to format generated file '{}'",
err,
path.display()
);
})
.wait()
.unwrap();
}

View File

@@ -0,0 +1,209 @@
use proc_macro2::TokenStream;
use syn::parse::*;
use syn::visit::*;
use syn::*;
use indexmap::IndexSet;
struct StaticStrVisitor {
static_strs: IndexSet<String>,
}
impl StaticStrVisitor {
fn new() -> Self {
Self {
static_strs: IndexSet::new(),
}
}
}
struct MacroFnArgs {
args: Vec<Expr>,
}
struct ReadHeapCellExprAndArms {
expr: Expr,
arms: Vec<Arm>,
}
impl Parse for ReadHeapCellExprAndArms {
fn parse(input: ParseStream) -> Result<Self> {
let mut arms = vec![];
let expr = input.parse()?;
input.parse::<Token![,]>()?;
arms.push(input.parse()?);
while !input.is_empty() {
let _ = input.parse::<Token![,]>();
arms.push(input.parse()?);
}
Ok(ReadHeapCellExprAndArms { expr, arms })
}
}
impl Parse for MacroFnArgs {
fn parse(input: ParseStream) -> Result<Self> {
let mut args = vec![];
if !input.is_empty() {
args.push(input.parse()?);
}
while !input.is_empty() {
let _ = input.parse::<Token![,]>();
args.push(input.parse()?);
}
Ok(MacroFnArgs { args })
}
}
impl<'ast> Visit<'ast> for StaticStrVisitor {
fn visit_macro(&mut self, m: &'ast Macro) {
let Macro { path, .. } = m;
if path.is_ident("atom") {
if let Ok(Lit::Str(string)) = m.parse_body::<Lit>() {
self.static_strs.insert(string.value());
}
} else if path.is_ident("read_heap_cell") || path.is_ident("match_untyped_arena_ptr") {
if let Ok(m) = m.parse_body::<ReadHeapCellExprAndArms>() {
self.visit_expr(&m.expr);
for e in m.arms {
self.visit_arm(&e);
}
}
} else if let Ok(m) = m.parse_body::<MacroFnArgs>() {
for e in m.args {
self.visit_expr(&e);
}
}
}
}
const INLINED_ATOM_MAX_LEN: usize = 6;
fn static_string_index(string: &str, index: usize) -> u64 {
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
let mut string_buf: [u8; 8] = [0u8; 8];
string_buf[..string.len()].copy_from_slice(string.as_bytes());
(u64::from_le_bytes(string_buf) << 1) | 1
} else {
(index << 1) as u64
}
}
pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
use quote::*;
use std::ffi::OsStr;
use std::fs::File;
use std::io::Read;
use walkdir::WalkDir;
fn filter_rust_files(e: &walkdir::DirEntry) -> bool {
if e.path().is_dir() {
return true;
}
e.path().extension().and_then(OsStr::to_str) == Some("rs")
}
let mut visitor = StaticStrVisitor::new();
fn process_filepath(path: &std::path::Path) -> std::result::Result<syn::File, ()> {
let mut src = String::new();
let mut file = match File::open(path) {
Ok(file) => file,
Err(_) => return Err(()),
};
match file.read_to_string(&mut src) {
Ok(_) => {}
Err(e) => {
panic!("error reading file: {e:?}");
}
}
let syntax = match syn::parse_file(&src) {
Ok(s) => s,
Err(e) => {
println!("cargo::warning=parse error: {e} in file {path:?}");
syn::File {
shebang: None,
attrs: vec![],
items: vec![],
}
}
};
Ok(syntax)
}
for entry in WalkDir::new("src/")
.into_iter()
.filter_entry(filter_rust_files)
{
let entry = entry.unwrap();
if entry.path().is_dir() {
continue;
}
let syntax = match process_filepath(entry.path()) {
Ok(syntax) => syntax,
Err(_) => continue,
};
visitor.visit_file(&syntax);
}
if let Ok(syntax) = process_filepath(instruction_rs_path) {
visitor.visit_file(&syntax)
}
let mut static_str_keys = vec![];
let mut static_strs = vec![];
let mut static_str_indices = vec![];
let indices: Vec<u64> = visitor
.static_strs
.iter()
.map(|string| {
let index = static_string_index(string, static_strs.len());
static_str_keys.push(string);
if index & 1 == 1 {
index
} else {
static_str_indices.push(index);
static_strs.push(string);
index
}
})
.collect();
let static_strs_len = static_strs.len();
quote! {
static STRINGS: [&str; #static_strs_len] = [
#(
#static_strs,
)*
];
macro_rules! atom {
#((#static_str_keys) => { Atom { index: #indices } };)*
($name:literal) => {compile_error!(concat!("unknown static atom ", $name))};
}
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
#(#static_strs => { Atom { index: #static_str_indices } },)*
};
}
}

14
doclog.config.pl Normal file
View File

@@ -0,0 +1,14 @@
project_name("Scryer Prolog").
readme_file("INDEX.dj").
source_lib_folder("src/lib").
websource("https://github.com/mthom/scryer-prolog/tree/master/src/lib").
omit(["ops_and_meta_predicates.pl", "tabling"]).
learn_pages_source_folder("learn").
learn_pages_categories(["First steps", "Tutorials"]).
learn_pages([
page("Let's play Brisca", "Tutorials", "lets-play-brisca.dj"),
page("Test page", "First steps", "test-page.dj")
]).
copy_file("logo/scryer.png", "scryer.png").
copy_file("learn/Spanish_deck_Fournier.jpg", "learn/Spanish_deck_Fournier.jpg").
copy_file("learn/brisca-interactive.png", "learn/brisca-interactive.png").

82
flake.lock generated Normal file
View File

@@ -0,0 +1,82 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1744868846,
"narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1745289264,
"narHash": "sha256-7nt+UJ7qaIUe2J7BdnEEph9n2eKEwxUwKS/QIr091uA=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "3b7171858c20d5293360042936058fb0c4cb93a9",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

85
flake.nix Normal file
View File

@@ -0,0 +1,85 @@
{
description = "A modern Prolog implementation written mostly in Rust";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { nixpkgs, flake-utils, rust-overlay, ... }:
let
meta = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package;
inherit (meta) name version;
overlays = [
(import rust-overlay)
(self: super: {
rustToolchainDev = super.rust-bin.stable.latest.default.override {
extensions = [ "rust-src" "rust-analyzer" ];
};
rustToolchainDevWasm = super.rust-bin.stable.latest.default.override {
extensions = [ "rust-src" "rust-analyzer" ];
targets = [ "wasm32-unknown-unknown" ];
};
rustToolchainNightly = super.rust-bin.selectLatestNightlyWith (toolchain:
toolchain.default.override {
extensions = [ "rust-src" "rust-analyzer" "miri" ];
}
);
})
];
in flake-utils.lib.eachDefaultSystem(system:
let
pkgs = import nixpkgs { inherit system overlays; };
nativeBuildInputs = with pkgs; [ pkg-config ];
buildInputs = with pkgs; [ openssl ] ++
lib.optionals pkgs.stdenv.isDarwin [
pkgs.darwin.apple_sdk.frameworks.SystemConfiguration
];
in
{
devShells = {
default = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
nativeBuildInputs = nativeBuildInputs;
buildInputs = buildInputs ++ (with pkgs; [
rustToolchainDev
]);
};
wasm-js = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
nativeBuildInputs = nativeBuildInputs;
buildInputs = buildInputs ++ (with pkgs; [
wasm-pack
rustToolchainDevWasm
]);
TARGET_CC = "${pkgs.clangMultiStdenv.cc}/bin/clang";
hardeningDisable = [ "all" ];
};
# For use with Miri and stuff like it
nightly = pkgs.mkShell {
nativeBuildInputs = nativeBuildInputs;
buildInputs = buildInputs ++ (with pkgs; [
rustToolchainNightly
]);
};
};
packages = rec {
default = scryer-prolog;
scryer-prolog = pkgs.rustPlatform.buildRustPackage {
pname = name;
inherit version;
src = ./.;
nativeBuildInputs = nativeBuildInputs;
buildInputs = buildInputs;
cargoLock = {
lockFile = ./Cargo.lock;
};
release = true;
};
};
}
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

457
learn/lets-play-brisca.dj Normal file
View File

@@ -0,0 +1,457 @@
# Let's play Brisca
In this article, we'll see how to use modern Prolog to model the game of [Brisca](https://en.wikipedia.org/wiki/Brisca). First things first, what is Brisca?
## Rules of the game
Brisca is a traditional card game from Spain, although similar games both in name and in rules are spread across the Mediterranean. It's also similar to Tute. It is played using the traditional Spanish deck, usually with 40 cards in 4 suites (oros, espadas, bastos, copas). Here you have the famous Castillian pattern by Heraclio Fournier, the one I play in my family with my grandparents.
![Heraclio Fournier Spanish cards](Spanish_deck_Fournier.jpg)
How do you play it? Basically, players play in rounds. Every round each player on the table (usually four), selects one of his own three cards to leave one in the middle, and they do that in order. There are some rules, which I will explain later, and one person wins the round, taking all the cards with him. Players take new cards from the stock. Some cards get you points, some others don't. After there are no more cards in player's hands, we count the points, the players with more points, wins!
The rules for knowing which players takes the round are the following:
- Every game there's a trump suite, which was selected as a random card from the stock at the same time when the players got their three initial cards.
- The first player in a round (the winner of the previous round) can choose whatever card he wants.
- The rest of the players, in order to win the round, they need to improve the card of the first player. They can put a higher card of the same suite as the first player.
- Or they can put a card from the trump suite, which is always better than a card from a non-trump suite.
- But between cards in the trump suite, there's still an order.
- However players are not required to put cards that improve the game if they don't wish to do that, they can just lose the round to discard themselves a bad card.
- The order is the following: As (ace, number 1) -> 3 -> Rey (king, number 12) -> Caballo (horse, but usually it's a knight, number 11) -> Sota (a page, number 10) -> 7 -> 6 -> 5 -> 4 -> 2.
## Modeling cards
First, we need to decide a representation of our cards. Coming from another languages we can think that a good representation might be a class or a struct, with two fields, one for the number and the other for the suite, but Prolog doesn't have objects. We can use a list with two elements. But lists are better when we're dealing with variable length data. We could also use a compound term. This is the right choice if our fields are fixed.
A compound term is defined by an atom, followed by the data itself enclosed by parenthesis and separated by comma. Like this: `card(oros, 4)`. Yes, very similar to predicates. In fact the only difference is how we use them, because they're the same. If we pass a compund term in the first level of a query, or inside a call/N, Prolog will treat it as code instead of data. This is one the the examples of Prolog being a homoiconic language.
We can go further, Prolog is very flexible and we can define custom operators easily if we want. Those are also compound terms, but with a different syntax. There's an operator already defined that is very useful for us: the dash. We can just join two pieces of data with a dash, and they'll be together in the same structure. This is usually called "pair".
So, using pairs we can model cards like this: `oros-4`, `espadas-7`.
We can code a predicate that defines valid cards:
```
card(Suite-Number) :-
member(Suite, [oros, espadas, bastos, copas]),
member(Number, [rey, caballo, sota, 7, 6, 5, 4, 3, 2, as]).
```
## Counting points
We are going to implement a counting predicate. The suite doesn't matter, only the number. First, we define a `card_score/2` predicate which relates a card to a score and viceversa.
```
card_score(_-as, 11).
card_score(_-3, 10).
card_score(_-rey, 4).
card_score(_-caballo, 3).
card_score(_-sota, 2).
card_score(_-X, 0) :- member(X, [7, 6, 5, 4, 2]).
```
Now, if we want to know how many points gives an specific card, we can ask:
```
?- card_score(oros-rey, X).
X = 4
; false.
```
(Remember, to load a file named brisca.pl in Scryer Prolog, we can run `scryer-prolog brisca.pl` in your favourite shell.)
But we can also ask what cards can give you that value:
```
?- card(X), card_score(X, 11).
X = oros-as
; X = espadas-as
; X = bastos-as
; X = copas-as.
```
You have probably noticed that I included the card predicate in the toplevel (which kind of acts like a type restriction), not in the `card_score/2`. However, does it make sense for card_score to work on something that is not a also a card? Both approaches are valid if applied correctly. Some people prefer to set domain restrictions like this externally, as it allows you to write more concise code and it usually performs better. However, having a card predicate in `card_score/2` is more correct since it's not possible to use that predicate in something that is not a card. We can choose either option thanks to Prolog being a dynamic language.
In my case, my final version is going to be a predicate which includes the card restriction and uses a wrapper predicate to have the short and concise code:
```
card_score(X, N) :-
card(X),
card_score_(X, N).
card_score_(_-as, 11).
card_score_(_-3, 10).
card_score_(_-rey, 4).
card_score_(_-caballo, 3).
card_score_(_-sota, 2).
card_score_(_-X, 0) :- member(X, [7, 6, 5, 4, 2]).
```
Now we just need to work with a list of cards instead of a single card. This is a place where we can introduce DCGs. DCGs are the short name for [Definite Clause Grammars](https://www.metalevel.at/prolog/dcg), which is a shorthand notation used to describe sequences. We can use them to parse, generate, complete and check sequences in the form of lists.
We can define a base case. If there are no more elements in the sequence, the score should be zero. If there's a Card, we can calculate its score and sum it together with the rest:
```
cards_score_(0) --> [].
cards_score_(X) -->
[Card],
{ card_score(Card, X0), #X #= #X0 + #X1 },
cards_score_(X1).
```
In DCGs, to match an item of the sequence, we use brackets. We use braces to introduce normal Prolog code. Calling other DCGs (in this case, the same, as it's a recursive one), it's just calling it again. Notice in this code that we are doing the addition of X0 and X1 when we still don't know the value of X1. This would be an error in the traditional arithmethic system of Prolog, but it's valid with clpz. clpz allows us to have a more declarative arithmethic, at least with integers.
Now we can try this code using `phrase/2` which is needed to jump to a DCG.
```
?- phrase(cards_score_(X), [oros-as, oros-rey, oros-7]).
X = 15
; false.
```
It seems to work. However there's a small problem. if we try to do the reverse, generating a sequence of cards that give you a specific amount of points, we'll find trouble. The program won't end. This is basically because be default we are not fair enumerating. This means that it will go deep into the recursion, trying to create an infinite length sequence. We need a way so that it does iterative deepening (starts with sequences of length 1, then length 2, ...). Luckily, if we pass our list first through the `length/2` predicate, it will do exactly that. This is usually done at the outside.
```
cards_score(Cards, Score) :-
phrase(cards_score_(Score), Cards).
cards_score_(0) --> [].
cards_score_(X) -->
[Card],
{ card_score(Card, X0), #X #= #X0 + #X1 },
cards_score_(X1).
```
So now:
```
?- length(X, _), cards_score(X, 15).
X = [oros-rey,oros-as]
; X = [oros-rey,espadas-as]
; X = [oros-rey,bastos-as]
; X = [oros-rey,copas-as]
; X = [oros-as,oros-rey]
; X = [oros-as,espadas-rey]
; X = [oros-as,bastos-rey]
; ...
```
```
?- cards_score(X, Y).
X = [], Y = 0
; X = [oros-rey], Y = 4
; X = [oros-caballo], Y = 3
; X = [oros-sota], Y = 2
; X = [oros-7], Y = 0
; X = [oros-6], Y = 0
; X = [oros-5], Y = 0
; X = [oros-4], Y = 0
; X = [oros-3], Y = 10
; X = [oros-2], Y = 0
; ...
```
## Winner of a round
Now, let's try to model the winner of a round in the game. First, we can model the pseudo-numerical order of the cards in a suite. We can start with a simple idea, if we have a list with the right order, we can take an element and see if the other card is in the higher section of the rest of the list.
```
card_higher_n(N0, N1) :-
Order = [as, 3, rey, caballo, sota, 7, 6, 5, 4, 2],
append(Highers, [N0|_], Order),
member(N1, Highers).
```
This works well, and it can show all of the 'Y is higher than X' relationships:
```
?- card_higher_n(X, Y).
X = 3, Y = as
; X = rey, Y = as
; X = rey, Y = 3
; X = caballo, Y = as
; X = caballo, Y = 3
; ...
```
For some people this might be enough. However, since we're in Scryer Prolog, we can also use reificated predicates. Using this technique, we can show not just the 'Y is higher than X' but also, the complete set of solutions of 'Y is NOT higher than X'. In order to do that we need to add a third argument to our predicate, which will be true or false (the predicate is true for the given X and Y or it's false). And we need to change `member/2` to a reified version of it: `memberd_t/3`.
```
card_higher_n(N0, N1, T) :-
Order = [as, 3, rey, caballo, sota, 7, 6, 5, 4, 2],
append(Highers, [N0|_], Order),
memberd_t(N1, Highers, T).
```
Now, we get for every combination a T truth value and also, in the case of false queries, we get the constraints that need to be held to get that result:
```
?- card_higher_n(X, Y, T).
X = as, T = false
; X = 3, Y = as, T = true
; X = 3, T = false, dif:dif(as,Y)
; X = rey, Y = as, T = true
; X = rey, Y = 3, T = true
; X = rey, T = false, dif:dif(3,Y), dif:dif(as,Y)
; X = caballo, Y = as, T = true
; X = caballo, Y = 3, T = true
; X = caballo, Y = rey, T = true
; X = caballo, T = false, dif:dif(3,Y), dif:dif(as,Y), dif:dif(rey,Y)
```
For example, if X = 3 and Y = as, then Y is higher than X. But if Y is different from as, then it's false.
Using reified predicates can be wise if we want to raise ourselves to a more declarative way of working with Prolog, but it's newer and not applicable form some problems. In this case, it's fine, so we'll use them.
Now, to model the relatioships of whole cards, we need to take into account the suites too. We're going to compare the suites, if they're the same, we just apply the pseudonumerical order. If they're different we check if the suite of the supposedly higher card is the trump suite. We can continue to use reified predicates from `library(reif)` like `if_/3`, which takes a reified predicate as a condition and `=/3` which does reified unification. We also expose our T truth argument in this predicate:
```
card_higher(Trump, Card, Higher, T) :-
card(Card),
card(Higher),
Card = S0-N0,
Higher = S1-N1,
if_(S0 = S1,
card_higher_n(N0, N1, T),
=(S1, Trump, T)
).
```
The code allows us to generate every card combination with every trump value and their truth value:
```
?- card_higher(Trump, X, Y, T).
X = oros-rey, Y = oros-rey, T = false
; X = oros-rey, Y = oros-caballo, T = false
; X = oros-rey, Y = oros-sota, T = false
; X = oros-rey, Y = oros-7, T = false
; X = oros-rey, Y = oros-6, T = false
; X = oros-rey, Y = oros-5, T = false
; X = oros-rey, Y = oros-4, T = false
; X = oros-rey, Y = oros-3, T = true
; X = oros-rey, Y = oros-2, T = false
; X = oros-rey, Y = oros-as, T = true
; Trump = espadas, X = oros-rey, Y = espadas-rey, T = true
; X = oros-rey, Y = espadas-rey, T = false, dif:dif(espadas,Trump)
; Trump = espadas, X = oros-rey, Y = espadas-caballo, T = true
; X = oros-rey, Y = espadas-caballo, T = false, dif:dif(espadas,Trump)
; Trump = espadas, X = oros-rey, Y = espadas-sota, T = true
; X = oros-rey, Y = espadas-sota, T = false, dif:dif(espadas,Trump)
```
For example a espadas-caballo is higher than oros-rey if Trump = espadas, otherwise, it isn't.
Now, let's check for the winner. For every card we need to check if the current one is higher value than the current highest. It's very easy, we just need to to do a fold! Just like in functional programming, we have a fold _predicate_. Actually, it's a fold-left, but for this case we need the right order, so we will need to reverse the list first. The, for our foldl, we're going to use a lambda predicate from `library(lambda)`.
This library, allows us to write unnamed predicates that are very useful in metapredicates like `foldl/4`. The syntax might be a bit confusing if you're coming from other languages as it's a bit unique. You can find the complete description of the syntax in the [documentation page](https://www.scryer.pl/lambda.html).
The code looks like this:
```
round_winner(Cards, Trump, WinnerCard) :-
reverse(Cards, [FirstCard|RestCards]),
foldl(Trump+\X^Y^Z^if_(card_higher(Trump, X, Y), Y = Z, X = Z), RestCards, FirstCard, WinnerCard).
```
```
?- length(Cards, 4), round_winner(Cards, Trump, Winner).
Cards = [oros-rey,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-caballo,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-sota,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-7,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-6,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-5,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-4,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-3,oros-rey,oros-rey,oros-rey], Winner = oros-3
; Cards = [oros-2,oros-rey,oros-rey,oros-rey], Winner = oros-rey
; Cards = [oros-as,oros-rey,oros-rey,oros-rey], Winner = oros-as
; Cards = [espadas-rey,oros-rey,oros-rey,oros-rey], Trump = oros, Winner = oros-rey
; Cards = [espadas-rey,oros-rey,oros-rey,oros-rey], Winner = espadas-rey, dif:dif(oros,Trump)
```
# A complete game
Now we have the basic pieces of the game. But we don't have a complete game. A game starts with someone dealing the first three cards to each player, a trump suite is selected, then we start the rounds: players put one card each, we choose a winner, the winner takes the cards and players get a new card from the stock. This all seems very procedural, but we're using Prolog. What can we do about it?
Let's ask ourselves what is a procedure. It's a sequence. And we have already seen a way to describe sequences in Prolog! The DCGs.
The basic idea however is having _explicit_ states. The predicates that we're going to write will take an state (a view of the world at a certain point) and will give us the next state.
Let's define the state first. In a game of Brisca we have players. Each player has the three cards he can choose to put (less if we're running out of cards) and the cards he has got from winning rounds. Aditionally we have a stock, a trump suite and the order to play, which is usually from the player who won the last round and going to the right. We could store the data in a list, with different compound terms:
```
[players([player(Name, PlayableCards, WonCards), player(Name, PlayableCards, WonCards), ...]), stock(Cards), trump(Trump)]
```
In order to express states using DCGs, we can use [semicontext notation](https://www.metalevel.at/prolog/dcg#semicontext):
```
state(S), [S] --> [S].
state(S0, S), [S] --> [S0].
```
So, for example our predicate to reset the game, and leave all the different cards in the stock would like this:
```
reset -->
state(_, [stock(Cards)]),
{
setof(Card, card(Card), Cards)
}.
```
To shuffle them:
```
shuffle_cards -->
state(S0, S),
{
select(stock(Cards), S0, S1),
shuffle(Cards, ShuffledCards),
S = [stock(ShuffledCards)|S1]
}.
```
Where `shuffle/2` is a predicate that implements the Fisher-Yates algorithm in Prolog:
```
shuffle([], []).
shuffle(Xs0, [Y|Ys]) :-
length(Xs0, N),
random_integer(0, N, R),
nth0(R, Xs0, Y, Xs),
shuffle(Xs, Ys).
```
We can also code more specific state accessors, which could be useful to know which part of the state each predicate can modify:
```
players(P0, P), [S] -->
[S0],
{ select(players(P0), S0, S1), S = [players(P)|S1] }.
```
The whole state management topic in DCGs could be the whole topic for another article.
The final DCG code for an interactive version of Brisca could be as follows:
```
brisca :-
phrase(brisca, [_], [_]).
brisca -->
reset,
shuffle_cards,
set_trump,
create_players([aarroyoc, xijinping, donalddtrump, vonderleyen]),
play_rounds,
show_scores.
reset -->
state(_, [stock(Cards)]),
{
setof(Card, card(Card), Cards)
}.
shuffle_cards -->
state(S0, S),
{
select(stock(Cards), S0, S1),
shuffle(Cards, ShuffledCards),
S = [stock(ShuffledCards)|S1]
}.
set_trump -->
state(S0, S),
{
member(stock(Cards), S0),
length(Cards, N),
nth1(N, Cards, LastCard),
LastCard = Trump-_,
S = [trump(Trump)|S0]
}.
create_players(Names) -->
state(S0, S),
{
same_length(Players, Names),
maplist(\N^X^(X=player(N, [], [])), Names, Players),
S = [players(Players)|S0]
},
deal_one_card_per_player,
deal_one_card_per_player,
deal_one_card_per_player.
deal_one_card_per_player -->
state(S0, S),
{
select(players(Players), S0, S1),
select(stock(Cards), S1, S2),
deal_one_card_per_player(Players, Players1, Cards, Cards1),
S = [players(Players1), stock(Cards1)|S2]
}.
deal_one_card_per_player([], [], Cs, Cs).
deal_one_card_per_player(Ps, Ps, [], []).
deal_one_card_per_player([P|Ps], [P1|Ps1], [C|Cs], Cs1) :-
P = player(N, A0, B0),
P1 = player(N, [C|A0], B0),
deal_one_card_per_player(Ps, Ps1, Cs, Cs1).
play_rounds -->
players(P, P),
{ P = [player(_, X, _)|_], length(X, 0) }.
play_rounds -->
players(P, P),
{ P = [player(_, X, _)|_], length(X, N), N > 0 },
play_round,
play_rounds.
play_round -->
state(S),
players(P0, P2),
{
member(trump(Trump), S),
format("Brisca round~nTrump is: ~a~n~n", [Trump])
},
play_players(P0, Cards),
{
round_winner(Cards, Trump, WinnerCard),
maplist(remove_card, P0, Cards, P1),
nth0(N, Cards, WinnerCard),
nth0(N, P1, WinnerPlayer0),
append(PBefore, [WinnerPlayer0|PAfter], P1),
WinnerPlayer0 = player(WinnerName, C, W0),
format("Winner card is ~w from ~w~n", [WinnerCard, WinnerName]),
append(W0, Cards, W1),
append([player(WinnerName, C, W1)|PAfter], PBefore, P2)
},
deal_one_card_per_player.
remove_card(P0, C, P) :-
P0 = player(N, C0, W),
select(C, C0, C1),
P = player(N, C1, W).
play_players([], []) --> [].
play_players([P|Ps], [C|Cs]) -->
{
P = player(Name, SelectableCards, _),
format("It's ~a's turn!~n", [Name]),
format("Selectable cards: ~w~n", [SelectableCards]),
read(C),
member(C, SelectableCards)
},
play_players(Ps, Cs).
play_players(Ps, Cs) --> play_players(Ps, Cs).
show_scores -->
players(P, P),
{
maplist(\X^(
X=player(N,_,Z),
cards_score(Z, Y),
format("Score of ~w is ~d~n", [N, Y])), P)
}.
```
Now, we can play! Of course, if you substitute interactive choosing (via `read/1`) with another method, you could simulate games, try AI strategies, etc
![Playing a game of Brisca](brisca-interactive.png)

3
learn/test-page.dj Normal file
View File

@@ -0,0 +1,3 @@
# Test page
This is a page about Scryer Prolog

BIN
logo/scryer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

896
logo/scryer.svg Normal file
View File

@@ -0,0 +1,896 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="300.000000pt" height="300.000000pt" viewBox="0 0 300.000000 300.000000"
preserveAspectRatio="xMidYMid meet">
<path fill="#57d3de" d="M0 0 h 300 v 300 h -300 z"/>
<g transform="translate(0.000000,300.000000) scale(0.100000,-0.100000)"
fill="#800080" stroke="none">
<path d="M2388 2423 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M2436 2422 c-3 -5 8 -6 25 -4 16 2 29 6 29 8 0 8 -49 4 -54 -4z"/>
<path d="M2310 2416 c0 -10 28 -13 41 -5 10 6 7 9 -13 9 -16 0 -28 -2 -28 -4z"/>
<path d="M2501 2415 c3 -2 23 -7 45 -9 86 -10 151 -37 181 -75 8 -10 12 -11
13 -4 0 19 -81 69 -130 80 -50 11 -117 16 -109 8z"/>
<path d="M2055 2373 c-60 -13 -126 -27 -145 -30 -19 -3 -38 -11 -42 -17 -6 -8
-10 -7 -17 2 -7 11 -19 12 -62 3 -30 -6 -82 -12 -116 -14 -46 -1 -63 -6 -66
-18 -5 -20 -107 -27 -107 -7 0 9 -3 9 -12 0 -19 -19 -41 -15 -33 6 4 11 3 13
-3 7 -6 -5 -12 -19 -14 -30 -2 -11 -9 -19 -16 -18 -6 2 -9 -4 -6 -12 5 -11 11
-12 24 -5 30 16 34 11 9 -9 -13 -11 -27 -15 -30 -10 -9 16 -39 -2 -39 -23 0
-11 -5 -29 -11 -40 -14 -26 2 -37 45 -32 23 4 27 2 16 -5 -13 -9 -13 -11 3
-12 26 -2 31 -4 44 -12 9 -6 11 -3 7 10 -5 17 -4 16 10 -1 8 -10 17 -23 18
-28 2 -5 19 -1 39 9 22 11 34 23 31 32 -2 8 0 11 6 7 11 -6 22 16 22 42 -1 11
-6 8 -16 -10 -8 -16 -19 -28 -24 -28 -6 0 -10 -7 -10 -15 0 -8 -4 -15 -9 -15
-5 0 -16 -3 -25 -6 -11 -4 -16 -1 -16 10 0 16 -10 20 -42 17 -10 -1 -18 3 -18
8 0 6 -9 11 -19 11 -47 0 -36 35 23 73 51 32 63 33 94 7 19 -16 21 -23 12 -40
-11 -20 -21 -27 -19 -12 4 27 -2 44 -13 35 -7 -5 -26 -10 -43 -11 -64 -4 -47
-40 25 -49 95 -13 99 89 4 107 -37 7 -37 8 -8 9 30 1 88 -21 80 -30 -2 -2 2
-9 9 -16 10 -9 17 -7 31 9 16 18 17 21 2 15 -9 -3 -18 0 -21 6 -4 12 18 17 78
17 20 0 38 10 57 30 15 18 33 28 41 24 8 -3 18 -1 21 5 4 6 16 6 36 -1 23 -7
34 -7 45 2 10 8 15 9 15 2 0 -18 -34 -31 -53 -21 -11 7 -23 6 -34 -1 -17 -11
-17 -11 0 -6 10 3 28 1 39 -5 16 -8 24 -7 41 8 12 11 29 19 37 18 8 0 22 7 31
17 9 10 18 16 20 14 2 -2 23 -1 47 4 25 4 42 4 42 -2 0 -10 42 0 50 12 3 4 25
15 50 23 67 24 14 19 -115 -10z m-415 -83 c0 -5 -4 -10 -10 -10 -5 0 -10 5
-10 10 0 6 5 10 10 10 6 0 10 -4 10 -10z m82 3 c-6 -3 -9 -9 -6 -15 4 -6 1 -9
-6 -6 -23 7 -21 24 2 25 13 0 17 -1 10 -4z"/>
<path d="M2220 2395 c0 -7 30 -13 34 -7 3 4 -4 9 -15 9 -10 1 -19 0 -19 -2z"/>
<path d="M2136 2328 l-21 -17 27 -1 c20 0 26 4 22 15 -5 11 0 15 17 14 13 0
18 -3 11 -6 -19 -7 -4 -23 16 -16 15 5 15 4 2 -10 -8 -9 -26 -18 -40 -21 -14
-2 -34 -8 -44 -12 -14 -5 -17 -4 -12 4 4 7 3 12 -2 12 -6 0 -12 -6 -15 -14 -4
-11 -67 -30 -92 -27 -2 0 -23 -6 -46 -14 -49 -18 -62 -19 -54 -5 4 6 10 8 15
5 4 -3 13 2 20 10 21 25 -6 17 -39 -11 -31 -26 -61 -27 -61 -1 0 7 5 18 12 25
8 8 8 12 1 12 -6 0 -13 -7 -17 -15 -3 -8 -17 -15 -31 -15 -24 0 -30 9 -26 38
1 6 -5 12 -14 12 -18 0 -19 -12 -3 -28 9 -9 8 -12 -7 -12 -10 0 -15 -3 -12 -7
4 -3 1 -13 -5 -22 -9 -11 -5 -10 9 2 20 17 50 16 39 -2 -3 -4 5 -8 16 -8 26
-2 30 -7 23 -26 -7 -16 -44 -29 -67 -24 -7 2 -10 2 -5 0 17 -10 5 -22 -20 -19
-16 2 -22 1 -15 -1 7 -3 10 -9 7 -14 -4 -5 5 -8 19 -7 15 1 26 6 26 11 0 4 5
5 10 2 6 -3 10 -2 10 3 0 13 70 49 110 57 19 4 78 19 130 35 52 15 114 33 137
39 24 6 47 21 53 31 6 11 25 26 43 33 30 13 29 13 -37 13 -51 0 -74 -4 -90
-18z"/>
<path d="M2374 2341 c3 -5 15 -7 26 -4 28 7 25 13 -6 13 -14 0 -23 -4 -20 -9z"/>
<path d="M1445 2329 c-194 -16 -394 -99 -536 -222 -14 -12 -72 -58 -129 -102
-136 -106 -198 -162 -206 -189 -3 -11 -16 -32 -29 -46 -12 -14 -35 -47 -50
-75 -15 -27 -32 -57 -39 -65 -10 -13 -9 -13 6 -1 26 20 22 5 -11 -37 -15 -20
-42 -75 -58 -122 -17 -47 -38 -102 -47 -123 -9 -22 -12 -36 -7 -33 6 4 2 -13
-9 -36 -26 -56 -25 -77 1 -44 11 14 17 30 14 36 -3 5 -1 10 4 10 6 0 11 -8 11
-17 0 -15 2 -15 14 2 9 13 11 27 6 41 -11 29 -8 49 13 72 10 11 17 23 16 28
-3 20 2 35 10 30 11 -7 23 22 15 35 -10 16 6 31 21 19 9 -8 15 -8 20 0 3 5 1
10 -6 10 -8 0 -8 4 1 15 7 8 17 12 24 8 7 -4 6 -1 -1 9 -7 8 -10 18 -6 21 3 4
4 7 0 7 -3 0 -13 -7 -21 -16 -17 -16 -36 -11 -36 9 0 8 3 7 9 -2 7 -11 11 -8
16 10 4 13 16 30 27 37 10 8 15 19 11 25 -4 7 0 6 10 -2 9 -7 17 -12 18 -10 0
2 2 19 4 37 2 19 12 40 22 48 22 16 10 18 -20 2 -12 -6 1 12 30 40 28 29 56
52 62 52 13 0 15 27 2 34 -5 3 -8 -2 -7 -11 0 -9 -5 -18 -12 -20 -8 -3 -10 1
-5 14 10 28 25 44 50 54 13 5 22 14 21 21 -2 6 6 14 17 16 11 2 25 9 30 14 7
8 5 9 -5 4 -8 -4 -4 2 10 13 14 12 35 24 47 27 12 3 29 17 38 31 9 14 23 22
30 19 9 -3 12 0 8 9 -3 9 3 18 13 21 11 4 33 17 51 30 34 26 123 43 123 24 0
-6 5 -8 12 -4 11 7 26 10 83 18 11 2 24 -2 28 -8 6 -7 7 -6 5 4 -3 8 -15 17
-28 20 -20 5 -21 7 -7 18 10 8 17 9 21 3 5 -7 14 -7 29 0 24 11 54 49 38 49
-5 0 -11 -5 -13 -11 -2 -6 -23 -11 -46 -11 -23 0 -42 -4 -42 -9 0 -6 -3 -8 -7
-6 -5 3 -14 -1 -21 -9 -11 -12 -10 -14 5 -14 16 0 16 -2 2 -15 -17 -17 -53
-10 -42 8 4 6 1 7 -7 2 -7 -4 -28 -11 -47 -15 -29 -7 -32 -6 -22 6 7 8 14 12
16 10 3 -3 15 7 28 22 20 24 24 25 41 12 10 -8 15 -10 11 -4 -11 19 21 51 60
59 21 5 44 9 50 11 7 1 20 9 29 18 17 18 28 21 19 6 -3 -5 3 -10 14 -10 11 0
23 5 26 11 4 5 18 14 32 20 13 5 22 13 19 18 -8 12 155 35 203 29 20 -3 47 -2
61 2 39 10 -49 16 -135 9z m-940 -679 c3 -5 -1 -10 -10 -10 -9 0 -13 5 -10 10
3 6 8 10 10 10 2 0 7 -4 10 -10z"/>
<path d="M2490 2321 c-7 -11 -24 -21 -37 -24 -27 -5 -32 9 -5 16 15 4 15 5 -1
6 -11 1 -21 -8 -24 -20 -5 -16 -11 -19 -30 -14 -19 4 -23 3 -17 -7 6 -10 5
-11 -7 -1 -12 10 -19 8 -33 -8 -11 -13 -25 -19 -37 -16 -11 3 -32 -1 -47 -8
-43 -21 -75 -29 -68 -17 4 6 -13 0 -37 -14 -25 -13 -63 -25 -86 -27 -22 -1
-41 -5 -41 -9 0 -5 -9 -8 -20 -8 -52 0 -250 -68 -250 -86 0 -3 5 -2 10 1 6 3
10 2 10 -4 0 -5 -4 -13 -10 -16 -5 -3 -10 -12 -9 -18 0 -9 2 -9 6 1 2 6 13 12
23 12 10 0 22 5 25 10 4 6 11 8 16 5 5 -4 9 -1 9 4 0 6 3 10 8 10 4 -1 26 1
49 6 32 6 40 11 36 23 -4 10 -2 13 5 8 7 -4 12 -3 12 2 0 5 6 9 13 9 38 1 102
15 115 25 13 11 15 10 9 -4 -4 -12 -2 -15 8 -11 8 3 13 8 11 12 -2 3 9 7 25 8
15 1 42 9 59 18 17 9 52 20 78 26 26 5 64 14 84 18 21 5 43 13 50 19 7 6 42
15 78 22 36 6 79 16 96 21 41 12 94 11 94 -2 0 -6 -7 -17 -15 -25 -8 -9 -15
-11 -15 -5 0 6 -7 8 -15 5 -9 -4 -15 0 -15 10 0 9 -5 16 -11 16 -7 0 -10 -12
-7 -30 5 -34 -11 -45 -30 -21 -11 13 -13 13 -9 1 4 -15 -24 -41 -55 -53 -11
-4 -21 0 -27 11 -10 16 -10 16 -11 0 0 -18 7 -21 43 -21 13 0 15 -3 6 -13 -14
-16 -39 -19 -39 -3 0 5 -5 7 -11 3 -8 -4 -7 -9 2 -15 12 -8 11 -11 -1 -19 -8
-5 -20 -10 -27 -10 -6 0 -14 -6 -17 -12 -5 -10 -7 -10 -12 0 -8 18 -24 15 -24
-5 0 -9 -3 -14 -6 -10 -4 3 -22 -5 -41 -18 -20 -13 -44 -22 -54 -20 -11 2 -17
0 -15 -4 3 -4 -14 -19 -37 -32 -23 -13 -54 -30 -69 -39 -103 -58 -157 -92
-170 -107 -8 -10 -25 -45 -37 -78 -12 -33 -33 -74 -47 -92 -14 -18 -22 -33
-18 -33 4 0 -1 -10 -12 -22 -17 -19 -56 -132 -69 -200 -2 -9 -8 -25 -13 -35
-12 -21 -12 -22 -12 -70 0 -28 -3 -34 -10 -23 -8 12 -10 9 -10 -12 0 -14 -3
-34 -7 -44 -5 -13 -3 -16 10 -11 14 5 17 0 17 -28 0 -18 5 -37 10 -40 16 -10
12 -25 -7 -25 -11 0 -14 3 -7 8 8 5 6 12 -5 24 -15 15 -16 14 -15 -19 1 -19
-2 -49 -7 -66 -5 -17 -5 -35 -1 -39 5 -5 14 9 21 31 15 53 31 61 25 14 -3 -21
-6 -57 -8 -81 -1 -23 -8 -48 -15 -55 -10 -10 -12 -8 -9 8 4 24 -33 29 -39 5
-4 -13 -3 -13 6 0 15 22 23 7 31 -57 6 -44 8 -50 9 -23 2 28 4 31 10 15 5 -11
6 -25 4 -31 -2 -7 0 -29 6 -50 5 -22 13 -59 16 -83 3 -23 11 -54 16 -68 17
-45 20 -104 7 -121 -7 -9 -8 -13 -2 -9 7 4 12 -2 12 -18 0 -14 -4 -22 -9 -19
-5 2 -2 -11 6 -30 8 -20 15 -46 15 -59 0 -14 13 -35 30 -50 22 -20 30 -23 30
-12 0 9 -10 20 -22 26 -18 8 -24 20 -26 51 -3 42 -3 42 18 23 20 -19 21 -19
13 1 -4 10 -12 25 -19 31 -7 8 -10 28 -7 52 4 25 -6 84 -26 169 -27 110 -31
147 -29 234 1 57 1 172 -1 256 -2 110 1 157 10 168 6 8 10 17 7 20 -3 3 3 37
13 75 17 63 51 142 110 249 10 19 29 57 41 84 21 44 33 55 124 110 56 34 144
81 195 105 127 59 148 70 219 116 34 22 99 64 146 94 46 29 84 57 84 63 0 5
-5 6 -10 3 -6 -4 -26 -1 -45 5 -19 6 -67 12 -107 13 -40 1 -75 5 -78 9 -3 4
-12 -1 -20 -11z m-697 -236 c-3 -9 -8 -14 -10 -11 -3 3 -2 9 2 15 9 16 15 13
8 -4z"/>
<path d="M2025 2320 c-17 -7 -15 -9 13 -9 17 -1 32 4 32 9 0 12 -17 12 -45 0z"/>
<path d="M1910 2280 c-20 -12 -10 -19 14 -10 11 3 15 9 10 13 -6 3 -16 2 -24
-3z"/>
<path d="M1980 2274 c-29 -16 -8 -19 22 -3 16 8 23 8 30 -2 8 -11 9 -11 5 1
-5 20 -26 21 -57 4z"/>
<path d="M2065 2280 c-3 -5 1 -10 9 -10 9 0 16 5 16 10 0 6 -4 10 -9 10 -6 0
-13 -4 -16 -10z"/>
<path d="M1806 2271 c-12 -5 -15 -10 -9 -14 6 -4 16 0 23 8 14 17 13 17 -14 6z"/>
<path d="M1340 2245 c-14 -8 -37 -14 -51 -15 -14 0 -34 -9 -44 -20 -18 -20
-18 -21 -1 -38 14 -14 16 -14 11 -1 -7 19 20 44 57 53 14 3 34 9 44 13 12 4
15 3 10 -5 -4 -7 -3 -12 3 -12 6 0 15 9 21 20 9 17 8 20 -7 20 -10 -1 -29 -7
-43 -15z"/>
<path d="M1190 2209 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1140 2199 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1330 2201 c0 -5 5 -13 10 -16 6 -3 10 -2 10 4 0 5 -4 13 -10 16 -5
3 -10 2 -10 -4z"/>
<path d="M1786 2184 c-11 -8 -16 -14 -10 -14 13 0 39 18 34 24 -3 2 -14 -2
-24 -10z"/>
<path d="M1294 2168 c6 -37 -36 -64 -48 -31 -3 8 -10 11 -16 8 -5 -3 -10 -1
-10 6 0 7 -3 9 -6 6 -4 -4 -1 -13 5 -21 7 -8 11 -19 8 -23 -3 -4 16 -8 41 -8
34 0 46 -4 44 -13 -1 -8 2 -11 8 -7 6 3 8 11 4 16 -3 6 2 17 12 25 18 14 18
14 -3 5 -29 -15 -32 -14 -26 8 3 11 0 28 -6 38 -10 15 -10 14 -7 -9z"/>
<path d="M2355 2150 c-3 -5 -3 -10 2 -10 4 -1 -3 -7 -16 -14 -14 -8 -31 -12
-38 -9 -8 3 -13 0 -11 -8 2 -7 -9 -15 -27 -19 -25 -5 -27 -7 -11 -13 11 -5 25
-2 35 6 26 22 87 47 115 47 14 0 26 4 26 10 0 6 -15 8 -36 4 -25 -4 -34 -2
-29 5 3 6 4 11 1 11 -3 0 -8 -4 -11 -10z"/>
<path d="M2135 2140 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M1676 2107 c-11 -8 -17 -18 -15 -23 2 -5 14 1 26 14 24 24 17 30 -11
9z"/>
<path d="M2025 2109 c-5 -7 -3 -10 6 -7 8 3 22 1 32 -4 11 -5 17 -5 17 2 0 5
-4 10 -9 10 -5 0 -16 3 -24 6 -8 3 -18 0 -22 -7z"/>
<path d="M2250 2109 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M2200 2099 c0 -5 -5 -7 -12 -3 -6 4 -8 3 -4 -4 3 -6 2 -13 -4 -17 -5
-3 -10 -2 -10 3 0 6 -9 8 -20 5 -11 -3 -20 -9 -20 -14 0 -5 -7 -5 -17 -2 -10
4 -14 2 -9 -5 9 -15 -13 -27 -27 -13 -13 13 -41 15 -33 3 11 -19 -15 -37 -55
-37 -29 0 -44 -5 -46 -15 -4 -13 -3 -13 6 0 9 13 11 13 11 1 0 -12 3 -12 12
-3 14 14 42 16 33 2 -7 -11 23 -3 41 11 6 5 15 5 19 1 5 -4 5 2 1 12 -6 16 -4
17 10 6 13 -12 17 -11 24 0 5 8 12 11 16 7 4 -4 17 -1 28 6 12 7 35 12 52 12
30 -1 31 0 22 27 -10 29 -18 36 -18 17z"/>
<path d="M1967 2093 c-12 -12 -7 -22 8 -17 8 4 15 10 15 15 0 11 -14 12 -23 2z"/>
<path d="M1367 2084 c-4 -4 -7 -17 -7 -28 1 -19 1 -20 11 -3 11 19 8 43 -4 31z"/>
<path d="M1198 2073 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M1326 2065 c-3 -8 -1 -15 4 -15 13 0 22 18 11 24 -5 3 -11 -1 -15 -9z"/>
<path d="M2000 2069 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1065 2055 c-27 -8 -51 -19 -53 -25 -2 -5 -8 -8 -13 -4 -5 3 -14 2
-21 -2 -8 -5 -6 -10 8 -15 12 -4 26 -1 36 8 9 9 37 18 61 20 28 3 44 10 44 19
0 16 3 16 -62 -1z"/>
<path d="M1155 2049 c-23 -9 -21 -10 20 -14 146 -13 178 -14 145 -5 -19 5 -57
12 -85 16 -27 3 -52 8 -55 9 -3 1 -14 -1 -25 -6z"/>
<path d="M1675 2050 c4 -6 1 -17 -5 -26 -11 -12 -9 -14 11 -10 13 2 32 -1 42
-6 13 -6 17 -5 17 7 0 9 -8 18 -17 21 -10 3 -26 10 -37 15 -13 8 -16 7 -11 -1z"/>
<path d="M1800 2046 c0 -2 7 -6 15 -10 8 -3 15 -1 15 4 0 6 -7 10 -15 10 -8 0
-15 -2 -15 -4z"/>
<path d="M903 2029 c3 -9 0 -22 -6 -29 -16 -16 43 10 61 27 11 11 11 13 0 13
-8 0 -20 -6 -26 -12 -10 -10 -15 -10 -23 2 -9 13 -10 13 -6 -1z"/>
<path d="M1860 2030 c0 -13 11 -13 30 0 12 8 11 10 -7 10 -13 0 -23 -4 -23
-10z"/>
<path d="M1780 2017 c0 -10 -6 -14 -14 -11 -7 3 -16 -1 -19 -8 -3 -9 2 -14 14
-14 19 0 37 32 25 43 -3 4 -6 -1 -6 -10z"/>
<path d="M1105 2010 c-3 -5 1 -10 9 -10 9 0 16 5 16 10 0 6 -4 10 -9 10 -6 0
-13 -4 -16 -10z"/>
<path d="M1160 2005 c0 -17 7 -21 40 -22 22 -1 41 1 44 5 2 4 -12 8 -32 9 -19
1 -39 8 -43 15 -6 9 -9 7 -9 -7z"/>
<path d="M1896 2008 c3 -5 10 -6 15 -3 13 9 11 12 -6 12 -8 0 -12 -4 -9 -9z"/>
<path d="M1020 1990 c-11 -11 -22 -20 -25 -19 -3 0 -11 -2 -18 -4 -6 -3 -2 -6
10 -6 12 -1 28 6 36 14 9 8 17 11 20 7 2 -4 2 -1 1 6 -3 8 5 11 24 7 22 -4 24
-4 7 4 -29 14 -33 13 -55 -9z"/>
<path d="M1558 1993 c11 -19 9 -24 -9 -33 -11 -7 -27 -9 -35 -6 -8 3 -13 2 -9
-3 8 -14 -17 -19 -43 -9 -17 6 -23 5 -20 -4 9 -26 68 -20 117 11 26 17 50 31
54 31 3 0 5 -12 4 -27 -2 -18 -11 -32 -26 -39 -39 -20 -41 -29 -6 -29 18 0 31
3 28 8 -2 4 7 7 21 7 16 0 26 6 26 14 0 8 6 17 13 19 6 3 0 6 -15 6 -33 1 -43
15 -22 32 14 11 18 11 28 -1 6 -8 22 -15 36 -16 14 -1 34 -4 45 -8 19 -8 19
-7 -1 11 -12 10 -24 26 -27 36 -4 10 -12 15 -18 11 -8 -4 -7 -9 2 -15 11 -6
10 -9 -3 -14 -9 -4 -27 0 -40 8 -13 8 -36 13 -53 11 -16 -1 -36 2 -44 9 -12
10 -13 9 -3 -10z"/>
<path d="M1501 1989 c-14 -5 -36 -9 -50 -8 -44 3 -71 -1 -71 -10 0 -6 12 -6
29 -1 16 4 32 6 35 3 8 -9 96 7 96 18 0 11 -8 11 -39 -2z"/>
<path d="M815 1980 c-3 -6 1 -7 9 -4 18 7 21 14 7 14 -6 0 -13 -4 -16 -10z"/>
<path d="M866 1972 c-4 -10 -13 -19 -21 -20 -8 -1 -22 -3 -30 -4 -8 -1 -12 -4
-10 -8 2 -4 18 -5 35 -2 18 2 30 0 30 -7 0 -6 -9 -11 -20 -11 -11 0 -20 -5
-20 -11 0 -7 8 -9 23 -4 12 4 46 9 75 12 29 3 55 10 59 16 4 6 -7 7 -31 3 -24
-5 -36 -3 -36 4 0 6 5 8 10 5 6 -3 10 -1 10 4 0 15 -11 13 -34 -4 -25 -19 -38
-10 -30 21 7 28 -2 33 -10 6z"/>
<path d="M1300 1980 c-12 -8 -9 -10 13 -10 15 0 27 5 27 10 0 13 -20 13 -40 0z"/>
<path d="M1803 1980 c2 -8 10 -14 17 -12 7 1 20 -3 29 -10 9 -7 13 -8 9 -4 -4
5 -2 16 5 24 10 13 9 14 -3 7 -20 -12 -43 -12 -53 0 -5 6 -7 4 -4 -5z"/>
<path d="M1160 1948 c0 -4 4 -8 9 -8 6 0 12 4 15 8 3 5 -1 9 -9 9 -8 0 -15 -4
-15 -9z"/>
<path d="M988 1918 c-21 -21 -11 -24 15 -4 10 8 15 16 10 18 -4 3 -16 -3 -25
-14z"/>
<path d="M1080 1927 c0 -11 -50 -27 -125 -42 -27 -6 -135 -58 -135 -67 0 -10
44 3 55 16 13 16 57 32 125 46 30 7 64 17 75 23 28 15 88 20 80 7 -4 -6 6 -10
24 -10 16 0 33 5 36 10 4 7 -3 9 -22 5 -21 -5 -24 -4 -13 4 12 9 9 11 -15 12
-16 1 -42 3 -57 5 -17 2 -28 -2 -28 -9z"/>
<path d="M735 1910 c-26 -28 -15 -31 12 -3 12 13 19 23 14 23 -4 0 -16 -9 -26
-20z"/>
<path d="M1667 1894 c-28 -15 -36 -26 -14 -21 7 1 11 -7 10 -18 -1 -11 3 -23
9 -26 21 -13 -4 -30 -34 -24 -21 5 -28 4 -24 -4 4 -6 12 -9 17 -6 5 4 9 1 9
-4 0 -16 16 -13 34 4 8 8 21 15 28 15 9 1 8 4 -3 10 -17 10 -15 59 4 71 21 14
-10 16 -36 3z"/>
<path d="M1430 1885 c0 -8 2 -15 4 -15 2 0 6 7 10 15 3 8 1 15 -4 15 -6 0 -10
-7 -10 -15z"/>
<path d="M1485 1890 c-3 -5 3 -10 15 -10 12 0 18 5 15 10 -3 6 -10 10 -15 10
-5 0 -12 -4 -15 -10z"/>
<path d="M1255 1880 c3 -5 10 -10 16 -10 5 0 9 5 9 10 0 6 -7 10 -16 10 -8 0
-12 -4 -9 -10z"/>
<path d="M1720 1880 c-12 -8 -10 -10 8 -10 13 0 20 4 17 10 -7 12 -6 12 -25 0z"/>
<path d="M685 1870 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M844 1864 c4 -11 1 -14 -12 -10 -13 4 -32 -7 -62 -34 -24 -22 -41
-43 -38 -46 3 -3 25 13 48 36 22 22 46 38 51 34 13 -7 41 15 33 27 -9 15 -26
10 -20 -7z"/>
<path d="M1088 1866 c-26 -20 -22 -26 12 -16 19 6 32 5 36 -2 4 -7 2 -8 -4 -4
-7 4 -12 2 -12 -3 0 -16 26 -13 40 4 15 19 13 21 -25 29 -18 3 -37 0 -47 -8z"/>
<path d="M1525 1870 c-3 -5 1 -10 10 -10 8 0 24 -6 35 -12 15 -10 22 -10 32 0
9 9 8 12 -5 12 -25 0 -30 1 -49 11 -10 6 -19 5 -23 -1z"/>
<path d="M1315 1849 c-17 -17 -17 -19 -2 -14 20 8 23 -5 5 -23 -21 -21 8 -14
33 8 13 11 20 20 14 19 -24 -3 -34 2 -29 16 8 20 3 18 -21 -6z"/>
<path d="M1030 1851 c0 -8 -8 -11 -20 -8 -11 3 -20 1 -20 -4 0 -5 -3 -8 -7 -7
-5 2 -19 -5 -33 -15 -30 -21 -22 -22 15 -3 15 8 33 12 40 10 14 -6 41 23 31
33 -3 3 -6 1 -6 -6z"/>
<path d="M1477 1842 c5 -12 1 -14 -20 -8 -14 3 -29 2 -32 -4 -3 -5 -14 -10
-24 -10 -10 0 -25 -8 -32 -17 -13 -16 -12 -17 3 -4 10 7 38 14 62 16 24 2 49
6 55 9 16 10 14 1 -9 -36 -11 -18 -20 -29 -20 -24 0 5 -6 4 -12 -1 -7 -6 -23
-13 -35 -16 -18 -4 -23 -1 -23 15 0 10 -5 16 -10 13 -6 -4 -8 -10 -5 -15 3 -4
-6 -10 -18 -14 -13 -3 -36 -17 -52 -30 -16 -14 -31 -24 -34 -24 -10 2 -81 -32
-81 -38 0 -3 12 -3 26 0 17 5 23 3 19 -4 -3 -5 -2 -10 4 -10 6 0 15 -15 20
-32 9 -30 10 -31 16 -11 7 22 31 37 45 28 4 -3 10 2 14 10 3 8 13 15 23 15 14
0 15 2 4 9 -11 7 -6 13 18 26 22 11 31 21 27 31 -3 9 -2 12 5 9 5 -4 27 6 47
22 20 15 38 26 39 23 2 -3 10 6 20 19 12 18 13 26 5 29 -7 2 -10 7 -8 11 2 3
-6 11 -19 17 -19 10 -22 9 -18 -4z m-87 -111 c0 -13 -82 -77 -107 -83 -13 -4
-23 -5 -23 -4 0 12 61 67 69 62 5 -4 15 3 21 14 11 20 40 28 40 11z"/>
<path d="M930 1835 c-14 -8 -20 -14 -14 -15 5 0 19 7 30 15 24 18 16 19 -16 0z"/>
<path d="M1220 1834 c0 -8 5 -12 10 -9 6 3 10 10 10 16 0 5 -4 9 -10 9 -5 0
-10 -7 -10 -16z"/>
<path d="M676 1809 c-21 -11 -41 -29 -43 -40 -3 -10 -9 -17 -12 -14 -4 2 -8
-3 -8 -12 0 -10 12 -2 32 21 17 20 35 36 41 36 6 0 19 7 30 15 28 21 5 18 -40
-6z"/>
<path d="M1085 1817 c-22 -13 -31 -37 -15 -37 6 0 10 5 10 11 0 7 8 18 18 25
21 17 14 17 -13 1z"/>
<path d="M1233 1818 c-13 -6 -23 -15 -23 -20 0 -4 -4 -8 -10 -8 -5 0 -7 7 -4
15 5 13 -13 15 -76 5 -3 0 1 -4 8 -9 12 -7 12 -12 1 -30 -8 -11 -18 -20 -24
-19 -5 1 -28 -8 -50 -20 -26 -15 -31 -20 -15 -16 14 3 29 10 35 15 5 5 17 9
27 9 9 0 21 6 25 14 9 16 43 24 58 14 6 -3 28 9 50 28 40 34 39 42 -2 22z"/>
<path d="M1285 1810 c3 -5 8 -10 11 -10 2 0 4 5 4 10 0 6 -5 10 -11 10 -5 0
-7 -4 -4 -10z"/>
<path d="M955 1774 c-71 -40 -62 -44 21 -9 32 13 53 24 46 25 -7 0 -10 5 -7
10 8 12 11 14 -60 -26z"/>
<path d="M804 1785 c-15 -11 -16 -14 -3 -15 8 0 24 7 35 15 15 11 16 14 3 15
-8 0 -24 -7 -35 -15z"/>
<path d="M1028 1779 c-14 -15 -15 -19 -4 -19 8 0 16 -6 19 -12 2 -7 4 2 5 20
0 17 0 32 -1 31 -1 0 -10 -9 -19 -20z"/>
<path d="M885 1780 c3 -6 -4 -14 -17 -19 -26 -10 -74 -56 -90 -86 -7 -12 5 -5
30 18 23 20 52 37 65 38 13 0 16 3 8 6 -11 4 -9 10 9 23 20 15 20 18 6 23 -10
4 -15 3 -11 -3z"/>
<path d="M1270 1775 c-7 -8 -18 -15 -24 -14 -24 3 -36 -2 -61 -25 -18 -17 -22
-26 -13 -29 7 -3 0 -6 -17 -6 -16 -1 -41 -4 -54 -8 -16 -4 -22 -3 -17 5 4 8
-3 8 -26 1 -35 -10 -89 -59 -65 -59 8 0 22 10 31 23 10 14 14 16 10 5 -7 -20
20 -26 31 -8 3 6 11 10 16 10 6 0 7 -5 3 -12 -5 -8 2 -9 26 -5 27 6 30 5 21
-7 -6 -7 -39 -19 -74 -25 -98 -19 -136 -38 -108 -55 5 -3 20 3 34 14 26 21 57
27 57 11 0 -10 -61 -41 -80 -41 -22 0 -80 -41 -80 -56 0 -12 4 -12 20 -2 11 7
20 18 20 25 0 14 2 15 40 19 14 1 36 6 50 10 24 7 24 7 8 -13 -10 -11 -18 -22
-18 -26 0 -3 8 -4 18 0 9 3 0 -11 -20 -33 -21 -22 -38 -45 -38 -52 0 -6 -9
-16 -20 -22 -11 -6 -18 -15 -15 -21 4 -5 -1 -9 -9 -9 -8 0 -17 4 -21 10 -3 5
-12 7 -20 3 -24 -9 -17 10 20 49 19 21 49 42 67 47 33 9 33 9 5 10 -19 1 -26
5 -21 13 5 7 3 8 -5 4 -7 -5 -10 -10 -8 -13 3 -2 -13 -22 -36 -43 -22 -22 -41
-50 -42 -62 -1 -13 -7 -22 -13 -21 -5 1 -15 -4 -21 -11 -10 -12 -6 -13 26 -5
56 13 73 11 67 -6 -4 -8 1 -17 10 -21 29 -11 13 -89 -32 -151 -16 -23 -19 -31
-8 -27 14 5 53 78 70 127 4 11 11 15 18 11 9 -5 8 -2 -1 10 -8 9 -10 16 -5 14
5 -1 21 10 37 25 15 16 32 25 39 21 7 -4 8 -3 4 4 -4 7 -3 12 2 12 10 0 35 50
28 57 -2 2 -7 -5 -11 -16 -3 -12 -19 -28 -34 -35 -15 -8 -33 -22 -40 -30 -19
-23 -34 -20 -26 5 5 15 4 19 -4 15 -25 -16 -9 27 25 64 37 41 70 51 80 25 4
-8 15 -15 26 -15 10 0 16 5 13 10 -4 6 -11 7 -17 4 -7 -4 -8 -2 -4 5 4 6 10 9
14 7 4 -2 23 4 42 15 19 10 47 24 63 31 15 7 27 16 27 20 0 8 -66 -19 -90 -38
-35 -26 -44 -28 -35 -8 4 10 7 27 7 37 0 9 3 15 9 12 5 -4 12 1 15 9 3 9 10
16 16 16 5 0 6 -4 3 -10 -8 -13 -1 -13 40 4 18 8 39 24 45 36 l11 21 -41 -21
c-57 -29 -73 -20 -25 13 24 16 33 27 23 27 -26 0 -68 -22 -68 -35 0 -7 -20
-29 -45 -49 -25 -21 -45 -45 -46 -54 0 -13 -3 -11 -9 5 -10 24 1 76 21 99 7 8
21 11 35 8 13 -3 24 -2 24 2 0 15 57 74 64 67 3 -3 6 0 6 8 0 19 23 69 32 69
3 0 4 -9 1 -20 -3 -11 0 -20 6 -20 6 0 11 4 11 10 0 5 7 7 15 4 8 -4 15 -1 15
5 0 6 6 11 13 11 6 0 21 8 32 16 20 15 19 16 -5 12 -16 -2 -24 2 -22 10 3 16
-3 15 -18 -3z m-200 -89 c0 -3 -4 -8 -10 -11 -5 -3 -10 -1 -10 4 0 6 5 11 10
11 6 0 10 -2 10 -4z m30 -186 c-6 -11 -18 -20 -27 -20 -14 0 -14 2 2 20 10 11
22 20 27 20 5 0 4 -9 -2 -20z"/>
<path d="M1542 1778 c-16 -16 -15 -25 3 -25 16 0 28 24 16 31 -4 3 -13 0 -19
-6z"/>
<path d="M683 1768 c-10 -18 -13 -39 -3 -33 8 5 21 45 15 45 -2 0 -7 -6 -12
-12z"/>
<path d="M950 1740 c-8 -5 -12 -11 -9 -14 2 -3 11 -1 19 4 8 5 12 11 9 14 -2
3 -11 1 -19 -4z"/>
<path d="M749 1713 l-24 -28 28 24 c25 23 32 31 24 31 -2 0 -14 -12 -28 -27z"/>
<path d="M1656 1725 c-4 -13 -2 -14 14 -5 23 13 26 20 6 20 -8 0 -16 -7 -20
-15z"/>
<path d="M975 1715 c-16 -7 -34 -11 -39 -7 -5 3 -6 0 -2 -6 4 -6 -2 -17 -14
-24 -11 -7 -20 -17 -20 -22 0 -5 11 1 25 14 14 13 28 20 32 15 5 -4 2 -10 -4
-12 -7 -3 -13 -10 -13 -16 0 -6 10 -1 23 11 13 12 30 22 38 22 12 0 12 2 0 9
-11 7 -11 9 0 13 8 3 12 7 9 10 -3 3 -18 -1 -35 -7z"/>
<path d="M1485 1699 c-4 -17 -9 -28 -12 -25 -3 3 -17 -4 -31 -14 -27 -22 -54
-28 -34 -8 7 7 12 16 12 21 0 5 -29 -20 -64 -56 -45 -45 -62 -58 -60 -43 2 12
-5 2 -16 -21 -12 -26 -31 -46 -50 -55 -17 -7 -30 -18 -30 -23 0 -11 -69 -52
-82 -48 -4 2 -5 -3 -2 -10 3 -8 0 -25 -5 -40 -7 -18 -7 -27 2 -30 7 -2 8 -8 4
-13 -13 -13 -27 18 -21 46 5 22 3 22 -17 -8 -13 -19 -27 -31 -35 -28 -8 3 -14
-1 -14 -9 0 -7 -6 -20 -13 -27 -27 -27 -67 -85 -67 -96 0 -7 5 -12 10 -12 6 0
10 4 10 10 0 5 16 32 36 60 29 40 42 50 65 50 40 0 37 -23 -6 -49 -20 -11 -38
-29 -42 -38 -3 -10 -15 -30 -25 -45 -16 -23 -17 -28 -4 -28 8 0 16 -8 19 -18
2 -9 4 0 3 21 0 39 17 61 41 52 7 -2 10 2 7 9 -5 12 63 92 71 84 4 -4 12 -40
14 -62 1 -4 7 -6 15 -3 24 9 39 -19 32 -58 -4 -19 -10 -35 -15 -35 -4 0 -8 -6
-9 -12 -1 -7 -4 -26 -7 -43 -5 -27 -3 -26 14 10 11 22 20 48 20 59 1 14 4 16
15 7 19 -16 5 -82 -29 -131 -16 -23 -32 -43 -37 -46 -4 -3 -8 -14 -8 -25 0
-29 22 -18 31 15 8 29 36 66 50 66 15 0 15 -35 0 -53 -18 -22 -22 -118 -4
-124 10 -4 10 37 -1 72 -2 6 1 19 6 30 8 18 8 18 4 -2 -2 -13 0 -23 6 -23 14
0 31 20 61 71 17 29 34 46 45 45 18 -1 19 2 21 64 1 28 5 40 16 40 15 0 19 15
16 57 -1 11 2 24 7 27 5 3 7 17 5 31 -3 13 -9 22 -14 20 -4 -3 -6 -12 -3 -20
3 -8 -1 -21 -9 -29 -8 -8 -12 -25 -10 -39 3 -14 -2 -29 -12 -37 -15 -12 -16
-8 -14 53 1 36 6 64 11 61 5 -3 6 6 2 20 -4 16 -2 26 4 26 6 0 18 15 27 33 12
25 13 43 6 73 l-9 39 -1 -40 c-2 -56 -11 -85 -28 -85 -8 0 -12 -4 -9 -9 3 -5
-12 -24 -33 -42 -22 -17 -42 -40 -44 -51 -3 -10 -11 -18 -17 -18 -8 0 -10 7
-5 23 4 12 8 36 9 53 1 17 10 43 20 59 18 27 20 28 27 10 6 -17 8 -15 8 8 1
16 7 43 15 60 45 106 49 131 6 42 -16 -33 -30 -53 -30 -45 0 8 -12 -9 -27 -38
-15 -29 -30 -52 -34 -52 -5 0 -6 7 -3 15 4 8 2 15 -4 15 -11 0 -22 -23 -22
-46 0 -8 3 -13 8 -13 20 3 32 -2 26 -12 -3 -6 -8 -32 -10 -58 -2 -37 0 -48 11
-48 8 0 15 5 15 11 0 15 48 66 61 66 7 0 9 -16 6 -42 -3 -22 -1 -55 4 -72 7
-24 6 -34 -7 -43 -10 -7 -11 -13 -5 -18 6 -3 11 -1 11 4 0 6 4 11 8 11 5 0 9
-7 9 -15 0 -8 -6 -15 -13 -15 -8 0 -21 -14 -30 -32 -9 -18 -23 -38 -30 -46 -8
-7 -14 -20 -14 -28 0 -8 -4 -14 -10 -14 -12 0 -12 2 -1 33 8 19 6 27 -5 31 -8
3 -14 10 -14 16 0 6 5 8 11 4 9 -5 10 1 5 20 -4 15 -2 26 4 26 6 0 6 9 -1 26
-5 15 -7 36 -4 48 5 15 4 17 -3 7 -10 -14 -17 -2 -27 51 -3 12 -9 24 -15 26
-5 2 -10 13 -10 25 -1 22 -1 22 -17 2 -15 -19 -15 -18 -9 14 3 19 17 49 31 67
27 36 30 44 15 44 -5 0 -10 -7 -10 -15 0 -8 -6 -15 -14 -15 -8 0 -16 -10 -18
-22 -5 -36 -33 -28 -36 11 -2 21 0 31 7 26 6 -3 11 -1 11 4 0 6 6 11 13 11 7
0 32 16 55 36 23 19 42 32 42 29 0 -4 6 -2 14 4 11 10 15 8 19 -6 3 -10 5 -3
6 15 2 61 111 137 111 77 0 -7 -4 -15 -8 -17 -9 -4 -52 -63 -52 -72 0 -19 23
-1 31 24 6 16 15 28 19 25 5 -3 15 14 22 37 16 47 36 55 54 21 6 -13 14 -20
17 -16 4 3 7 -3 7 -15 0 -14 -5 -20 -13 -16 -14 5 -45 -69 -39 -93 2 -7 -2
-13 -8 -13 -5 0 -10 6 -11 13 -4 58 -18 92 -20 46 0 -13 -2 -34 -3 -46 -4 -31
11 -53 23 -34 5 7 14 10 20 7 7 -5 11 2 11 18 0 31 18 73 45 102 11 12 26 30
34 39 8 10 23 15 37 12 17 -3 28 3 41 22 14 22 14 24 1 13 -9 -7 -25 -15 -37
-17 -18 -3 -20 -1 -11 15 19 35 10 34 -25 -4 -19 -21 -39 -35 -46 -31 -7 5 2
20 25 44 26 27 33 40 26 51 -7 10 -10 11 -10 3 0 -7 -11 -13 -25 -13 -27 0
-34 17 -10 26 8 4 12 10 9 15 -10 17 -22 9 -29 -22z m19 -59 c-15 -16 -31 -27
-36 -24 -12 8 31 54 49 54 8 0 3 -12 -13 -30z m-324 -374 c0 -3 -4 -8 -10 -11
-5 -3 -10 -1 -10 4 0 6 5 11 10 11 6 0 10 -2 10 -4z"/>
<path d="M906 1707 c3 -10 9 -15 12 -12 3 3 0 11 -7 18 -10 9 -11 8 -5 -6z"/>
<path d="M1438 1713 c-20 -5 -24 -23 -5 -23 6 0 21 7 31 15 20 15 11 18 -26 8z"/>
<path d="M620 1689 c-22 -18 -22 -19 -3 -10 12 6 25 16 28 21 9 15 3 12 -25
-11z"/>
<path d="M833 1685 l-28 -26 38 22 c37 21 45 29 28 29 -6 0 -23 -11 -38 -25z"/>
<path d="M712 1645 c-20 -19 -32 -35 -26 -35 5 0 25 16 44 35 44 45 31 45 -18
0z"/>
<path d="M870 1670 c-9 -6 -10 -10 -3 -10 6 0 15 5 18 10 8 12 4 12 -15 0z"/>
<path d="M1645 1640 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M950 1626 c0 -8 -6 -17 -12 -19 -10 -4 -10 -6 -1 -6 7 -1 17 8 23 19
7 14 7 20 0 20 -5 0 -10 -6 -10 -14z"/>
<path d="M719 1613 c-13 -16 -12 -17 4 -4 9 7 17 15 17 17 0 8 -8 3 -21 -13z"/>
<path d="M774 1621 c3 -5 -12 -25 -34 -45 -22 -20 -40 -38 -40 -41 0 -13 20
-2 53 30 36 35 48 65 26 65 -5 0 -8 -4 -5 -9z"/>
<path d="M842 1606 c-15 -17 -19 -25 -10 -28 8 -3 2 -16 -19 -36 -17 -18 -28
-32 -23 -32 5 0 12 5 15 10 4 6 10 8 15 5 11 -7 23 13 26 43 2 13 11 33 20 43
25 28 3 23 -24 -5z"/>
<path d="M555 1609 c-11 -17 1 -21 15 -4 8 9 8 15 2 15 -6 0 -14 -5 -17 -11z"/>
<path d="M900 1610 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0
-4 -4 -4 -10z"/>
<path d="M1627 1579 c-21 -22 -37 -47 -37 -56 0 -8 -9 -26 -20 -40 -15 -19
-17 -30 -10 -44 10 -17 5 -60 -8 -84 -10 -16 -11 -55 -2 -55 4 0 7 10 6 23 -2
12 3 28 10 35 10 9 14 -4 18 -66 2 -42 8 -96 11 -118 4 -26 3 -44 -4 -48 -6
-4 -11 -12 -11 -19 0 -6 11 0 25 15 25 27 33 44 15 33 -5 -3 -7 9 -5 30 4 26
1 35 -10 35 -8 0 -15 8 -14 18 0 10 3 12 6 5 10 -26 25 -13 20 17 -4 16 0 48
8 71 20 56 19 60 -6 20 -25 -42 -37 -34 -14 11 22 42 36 98 24 98 -8 0 -13
-22 -10 -42 0 -5 -3 -8 -9 -8 -5 0 -10 -7 -10 -15 0 -8 -4 -15 -10 -15 -13 0
-13 45 1 93 7 27 15 37 25 33 17 -6 18 -1 4 24 -7 13 -7 21 2 26 7 4 8 3 4 -4
-4 -7 -5 -12 -2 -12 3 0 15 18 26 40 11 22 19 40 17 40 -2 0 -20 -18 -40 -41z"/>
<path d="M1696 1594 c-11 -7 -16 -17 -13 -21 4 -4 15 1 24 10 22 21 14 30 -11
11z"/>
<path d="M1442 1580 c-9 -14 -9 -20 -1 -20 8 0 7 -6 -2 -17 -11 -15 -11 -16 1
-6 7 7 14 24 16 38 3 30 2 31 -14 5z"/>
<path d="M652 1561 c-17 -17 -32 -33 -32 -37 0 -5 17 8 37 27 21 18 40 35 42
37 2 1 0 2 -5 2 -5 0 -24 -13 -42 -29z"/>
<path d="M1765 1581 c-3 -5 -2 -12 3 -15 5 -3 9 1 9 9 0 17 -3 19 -12 6z"/>
<path d="M488 1573 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M1060 1565 c-7 -9 -8 -15 -2 -15 5 0 12 7 16 15 3 8 4 15 2 15 -2 0
-9 -7 -16 -15z"/>
<path d="M1722 1568 c-18 -18 -15 -38 5 -31 11 4 13 8 5 11 -10 3 -10 7 -1 18
14 17 8 19 -9 2z"/>
<path d="M784 1561 c7 -11 -28 -43 -38 -34 -4 4 -4 0 0 -10 3 -9 2 -17 -3 -17
-5 0 -18 -8 -29 -18 -10 -10 -27 -21 -36 -25 -18 -6 -25 -27 -10 -27 12 0 132
118 132 130 0 5 -5 10 -11 10 -5 0 -8 -4 -5 -9z"/>
<path d="M528 1553 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M1544 1524 c3 -9 6 -18 6 -20 0 -3 4 -3 10 1 11 7 2 35 -12 35 -6 0
-7 -7 -4 -16z"/>
<path d="M1650 1510 c-7 -14 -7 -20 0 -20 5 0 10 6 10 14 0 8 6 17 13 19 9 4
9 6 0 6 -7 1 -17 -8 -23 -19z"/>
<path d="M820 1490 c-14 -10 -22 -21 -19 -24 3 -3 16 5 29 19 28 30 24 32 -10
5z"/>
<path d="M1509 1503 c-2 -29 -11 -58 -20 -70 -9 -10 -8 -13 4 -13 13 0 14 -6
6 -36 -6 -19 -7 -48 -4 -64 3 -15 2 -31 -4 -34 -6 -4 -7 -14 -4 -22 5 -13 1
-15 -18 -9 -20 7 -22 5 -13 -6 7 -8 14 -33 18 -56 4 -34 3 -41 -9 -36 -17 6
-20 -14 -5 -37 8 -12 10 -12 10 5 2 44 21 -30 25 -93 1 -35 6 -66 9 -69 3 -4
6 0 6 8 1 8 7 -2 14 -21 8 -19 20 -49 27 -66 11 -28 9 -39 -13 -101 -21 -56
-23 -70 -12 -70 8 0 13 6 10 13 -3 8 5 20 17 29 20 14 21 15 2 16 -19 0 -19 1
-2 8 10 4 18 10 18 14 -1 4 -1 19 -1 33 0 22 2 25 15 14 8 -7 15 -18 15 -24 0
-6 9 -17 21 -24 19 -12 20 -12 13 10 -4 13 -8 42 -9 66 -2 24 -6 46 -9 49 -4
4 -6 -6 -5 -23 4 -74 -17 -69 -27 7 -4 27 -10 52 -14 54 -5 3 -6 -4 -3 -15 10
-37 -8 -20 -29 28 -34 76 -62 282 -39 282 6 0 11 10 11 23 0 13 3 27 6 30 11
10 13 67 3 67 -11 0 -6 45 10 83 9 23 8 31 -4 43 -8 9 -15 12 -16 7z"/>
<path d="M1665 1471 c-12 -40 -8 -102 9 -119 16 -16 16 -15 7 11 -8 21 -8 27
2 26 23 -3 40 1 34 8 -4 3 -2 12 4 20 6 7 8 13 3 13 -5 0 -2 5 6 10 11 7 11
10 2 10 -7 0 -18 -13 -23 -30 -14 -38 -30 -29 -25 14 5 41 -9 69 -19 37z"/>
<path d="M532 1467 c-17 -20 -12 -40 6 -28 8 5 12 16 10 26 -3 17 -4 17 -16 2z"/>
<path d="M638 1473 c6 -2 18 -2 25 0 6 3 1 5 -13 5 -14 0 -19 -2 -12 -5z"/>
<path d="M761 1466 c-13 -7 -19 -16 -14 -19 6 -4 18 2 28 13 21 23 19 24 -14
6z"/>
<path d="M482 1450 c-29 -28 -28 -34 3 -14 14 9 25 20 25 25 0 13 -4 11 -28
-11z"/>
<path d="M588 1449 l-23 -20 25 13 c14 6 31 11 38 10 17 -4 15 5 -3 11 -7 3
-24 -3 -37 -14z"/>
<path d="M701 1430 c-13 -11 -18 -20 -13 -20 6 0 14 5 17 10 4 6 10 8 14 6 4
-3 8 1 8 9 0 8 -1 15 -1 15 -1 -1 -12 -10 -25 -20z"/>
<path d="M815 1440 c-3 -5 3 -10 14 -10 12 0 21 5 21 10 0 6 -6 10 -14 10 -8
0 -18 -4 -21 -10z"/>
<path d="M913 1428 c-4 -7 -8 -20 -10 -28 -1 -10 3 -9 13 4 14 19 18 36 10 36
-3 0 -8 -6 -13 -12z"/>
<path d="M1026 1423 c-6 -14 -5 -15 5 -6 7 7 10 15 7 18 -3 3 -9 -2 -12 -12z"/>
<path d="M1335 1420 c-5 -14 -2 -28 8 -37 13 -13 14 -11 11 18 -5 41 -10 46
-19 19z"/>
<path d="M778 1423 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M545 1400 c-3 -10 -19 -30 -36 -44 -16 -14 -28 -29 -27 -33 2 -5 -7
-21 -18 -36 -16 -19 -27 -25 -40 -21 -17 6 -17 5 0 -8 19 -15 19 -16 -10 -48
-16 -17 -40 -36 -54 -42 -22 -9 -23 -11 -7 -17 16 -6 15 -9 -9 -31 -15 -14
-24 -20 -21 -13 4 6 3 23 -3 38 -8 20 -7 27 4 31 16 6 40 64 27 64 -4 0 -13
-11 -19 -24 -6 -13 -18 -23 -28 -23 -15 2 -17 -6 -15 -49 1 -33 -2 -55 -10
-60 -9 -5 -7 -9 7 -15 15 -6 35 10 102 79 45 47 81 90 79 96 -6 15 50 84 74
91 10 4 17 11 13 16 -4 6 -11 6 -20 -2 -8 -7 -14 -7 -14 -1 0 5 7 15 16 22 21
18 37 50 25 50 -5 0 -12 -9 -16 -20z"/>
<path d="M609 1400 c-21 -17 -21 -19 -4 -13 11 3 29 12 40 20 16 10 16 13 3
13 -9 0 -26 -9 -39 -20z"/>
<path d="M785 1400 c-3 -6 1 -7 9 -4 18 7 21 14 7 14 -6 0 -13 -4 -16 -10z"/>
<path d="M1429 1403 c0 -5 0 -35 1 -68 1 -33 -4 -73 -10 -89 -11 -30 0 -56 24
-56 8 0 8 2 0 8 -6 4 -10 18 -8 32 1 14 3 31 3 39 1 7 7 11 14 8 10 -4 12 7 9
46 -2 29 -9 55 -16 59 -8 6 -7 8 2 8 6 0 12 5 12 10 0 11 -30 14 -31 3z"/>
<path d="M469 1387 c5 -5 17 -5 28 2 16 9 15 10 -9 9 -16 -2 -24 -6 -19 -11z"/>
<path d="M620 1379 c-26 -14 -30 -19 -15 -19 11 0 34 9 50 20 38 25 12 24 -35
-1z"/>
<path d="M710 1375 c-30 -17 -43 -19 -35 -5 3 6 1 10 -5 10 -7 0 -10 -6 -7
-12 5 -14 56 -12 71 3 17 15 2 18 -24 4z"/>
<path d="M733 1347 c-27 -29 -27 -29 -4 -17 14 7 33 20 43 30 14 13 15 17 3
17 -8 0 -27 -14 -42 -30z"/>
<path d="M1402 1345 c0 -16 2 -22 5 -12 2 9 2 23 0 30 -3 6 -5 -1 -5 -18z"/>
<path d="M1300 1340 c0 -11 4 -20 8 -20 4 0 8 9 9 20 1 11 -2 20 -8 20 -5 0
-9 -9 -9 -20z"/>
<path d="M1270 1335 c0 -8 2 -15 4 -15 2 0 6 7 10 15 3 8 1 15 -4 15 -6 0 -10
-7 -10 -15z"/>
<path d="M574 1314 c-5 -21 -11 -25 -30 -21 -19 3 -22 2 -13 -9 9 -11 7 -15
-5 -20 -9 -3 -14 -10 -11 -15 3 -4 -7 -15 -22 -24 -15 -9 -19 -13 -8 -10 11 4
28 10 37 12 10 3 15 10 11 16 -4 6 0 8 10 4 10 -3 17 -2 17 3 0 5 10 19 23 31
12 12 15 18 7 14 -12 -6 -13 -5 -2 6 14 16 16 39 2 39 -5 0 -13 -12 -16 -26z"/>
<path d="M642 1310 c-63 -46 -53 -49 27 -9 20 10 30 18 23 19 -7 0 -10 5 -7
10 10 16 0 12 -43 -20z"/>
<path d="M410 1314 c0 -8 5 -12 10 -9 6 4 8 11 5 16 -9 14 -15 11 -15 -7z"/>
<path d="M803 1313 c-7 -2 -13 -11 -13 -19 0 -8 -7 -14 -16 -14 -10 0 -14 -6
-11 -14 8 -20 -16 -26 -29 -8 -10 14 -12 13 -18 -4 -3 -11 -20 -28 -37 -38
-17 -10 -28 -20 -25 -23 3 -3 16 1 28 9 13 8 32 18 42 21 15 6 17 5 8 -6 -7
-8 -9 -16 -6 -20 3 -3 -7 -13 -23 -23 -15 -10 -30 -19 -32 -20 -1 -2 0 -8 4
-14 9 -14 41 19 81 82 16 27 35 48 42 48 7 0 10 5 7 10 -4 6 -1 9 5 8 7 -2 14
5 15 15 3 17 -1 19 -22 10z"/>
<path d="M900 1309 c0 -19 -52 -129 -61 -129 -5 0 -9 -4 -9 -10 0 -20 28 3 49
41 29 51 42 97 30 104 -5 4 -9 1 -9 -6z"/>
<path d="M1663 1285 c-7 -21 -8 -46 -3 -63 l8 -27 2 30 c1 17 4 45 6 63 5 42
0 41 -13 -3z"/>
<path d="M1710 1301 c0 -5 5 -13 10 -16 6 -3 10 -2 10 4 0 5 -4 13 -10 16 -5
3 -10 2 -10 -4z"/>
<path d="M735 1280 c3 -5 8 -10 11 -10 2 0 4 5 4 10 0 6 -5 10 -11 10 -5 0 -7
-4 -4 -10z"/>
<path d="M655 1264 c-11 -8 -25 -12 -33 -9 -7 2 -10 0 -7 -5 3 -6 -2 -10 -12
-10 -10 -1 -29 -8 -43 -16 -17 -11 -19 -13 -5 -9 25 9 46 13 65 15 17 1 81 50
65 50 -5 -1 -19 -7 -30 -16z"/>
<path d="M1696 1265 c-3 -8 -1 -15 4 -15 6 0 10 7 10 15 0 8 -2 15 -4 15 -2 0
-6 -7 -10 -15z"/>
<path d="M842 1239 c-7 -11 -27 -26 -44 -33 -24 -10 -27 -14 -14 -19 21 -8 63
18 72 45 8 27 1 31 -14 7z"/>
<path d="M1534 1252 c4 -7 2 -12 -5 -12 -8 0 -10 -12 -5 -37 11 -68 17 -97 21
-101 2 -2 -1 -15 -6 -29 -6 -16 -6 -31 1 -41 8 -15 10 -15 10 3 1 11 3 29 5
40 14 84 13 115 -2 115 -11 0 -14 8 -11 30 3 17 0 34 -5 37 -6 3 -7 1 -3 -5z"/>
<path d="M806 1235 c-3 -8 -1 -15 3 -15 5 0 11 7 15 15 3 8 1 15 -3 15 -5 0
-11 -7 -15 -15z"/>
<path d="M1296 1223 c-8 -25 -6 -39 6 -35 6 2 8 -8 6 -23 -3 -14 -1 -25 4 -25
9 0 5 86 -5 96 -3 3 -8 -3 -11 -13z"/>
<path d="M1693 1225 c0 -8 4 -15 9 -15 4 0 8 7 8 15 0 8 -4 15 -8 15 -5 0 -9
-7 -9 -15z"/>
<path d="M1730 1230 c0 -5 5 -10 10 -10 6 0 10 5 10 10 0 6 -4 10 -10 10 -5 0
-10 -4 -10 -10z"/>
<path d="M1151 1207 c-16 -41 -13 -57 5 -24 8 16 13 34 11 40 -3 7 -10 -1 -16
-16z"/>
<path d="M1040 1194 c0 -8 5 -12 10 -9 6 4 8 11 5 16 -9 14 -15 11 -15 -7z"/>
<path d="M1102 1189 c3 -8 -3 -21 -12 -29 -9 -8 -22 -30 -30 -48 -8 -21 -16
-29 -20 -22 -5 9 -9 9 -14 1 -4 -6 -4 -15 -1 -21 3 -5 1 -10 -6 -10 -10 0 -10
-3 -2 -11 13 -13 36 -3 28 12 -4 5 -1 9 4 9 6 0 11 6 11 14 0 8 3 16 8 18 4 2
19 19 33 38 23 31 25 37 11 49 -13 12 -14 12 -10 0z"/>
<path d="M480 1181 c0 -7 -7 -20 -16 -29 -18 -17 -48 -26 -38 -11 3 5 1 9 -4
9 -8 0 -23 -22 -26 -40 -1 -3 -13 -22 -28 -43 -16 -25 -28 -34 -33 -27 -4 6 1
21 11 34 11 12 8 11 -6 -4 -21 -21 -35 -25 -85 -26 -86 -2 -123 -8 -137 -22
-6 -6 -16 -12 -21 -12 -4 0 -28 -14 -53 -30 -29 -21 -44 -38 -44 -52 0 -20 1
-20 13 -5 6 9 28 27 47 41 19 14 45 33 57 41 17 13 26 14 42 5 14 -7 21 -7 21
0 0 5 9 10 19 10 11 0 23 5 26 10 13 20 53 10 79 -21 31 -37 33 -69 6 -94 -13
-12 -18 -25 -14 -38 4 -13 2 -17 -5 -13 -6 4 -11 1 -11 -7 0 -19 -28 -42 -38
-32 -4 4 -1 10 6 12 6 3 12 9 12 15 0 16 -28 -11 -43 -40 -14 -29 -63 -69 -73
-59 -4 3 6 20 20 38 28 33 29 53 1 25 -20 -20 -26 -20 -19 -1 4 9 0 15 -10 15
-9 0 -15 -3 -15 -7 1 -5 1 -15 0 -23 -1 -12 -3 -13 -10 -1 -6 9 -11 10 -15 2
-4 -6 -4 -11 0 -11 4 0 -1 -9 -10 -19 -10 -11 -25 -17 -34 -14 -13 4 -12 2 3
-10 16 -13 17 -17 6 -31 -12 -14 -12 -16 4 -10 13 5 16 4 11 -4 -4 -7 -2 -12
3 -12 6 0 11 7 11 15 0 8 6 15 14 15 8 0 16 5 18 12 3 8 13 2 28 -15 13 -15
30 -27 37 -27 19 0 16 -10 -12 -36 -14 -13 -25 -27 -25 -32 0 -14 -57 -61 -66
-54 -4 4 -4 1 1 -7 4 -8 2 -17 -6 -22 -8 -5 -9 -9 -3 -9 6 0 21 11 34 25 12
13 28 22 34 18 6 -3 8 -3 4 1 -10 12 120 179 133 171 13 -9 21 15 9 30 -9 11
-15 9 -35 -11 -14 -14 -25 -29 -25 -34 0 -11 -3 -12 -39 -14 -40 -2 -33 17 20
53 60 41 104 94 95 117 -4 10 -1 14 6 12 20 -7 21 -38 3 -58 -11 -12 -13 -20
-6 -25 6 -3 11 1 11 9 0 8 5 18 11 22 8 4 9 -1 3 -17 -4 -13 -9 -37 -10 -52
-1 -15 -7 -34 -13 -41 -6 -7 -8 -15 -6 -18 3 -3 1 -17 -4 -32 -9 -23 -9 -25 7
-15 16 10 19 21 25 89 2 30 11 38 22 20 3 -5 14 -9 23 -9 15 1 15 2 -1 6 -9 2
-14 9 -11 15 4 7 2 8 -4 4 -7 -4 -12 -1 -12 8 0 8 10 17 23 19 l22 4 -22 2
c-13 0 -23 4 -24 9 -8 75 -5 102 12 102 6 0 7 -10 3 -22 -6 -20 -4 -20 16 5
12 15 20 31 16 34 -3 4 -6 1 -6 -5 0 -7 -4 -12 -10 -12 -5 0 -10 7 -10 15 0 9
-6 12 -15 9 -8 -4 -15 -2 -15 2 0 12 20 41 20 31 0 -5 8 -1 17 9 13 13 15 18
5 22 -9 3 -6 10 9 23 12 10 17 19 11 19 -14 0 76 84 92 86 24 3 56 17 56 25 0
16 -30 10 -37 -7 -6 -15 -8 -15 -20 2 -7 10 -13 13 -13 5z m-355 -415 c-18
-28 -42 -40 -50 -26 -4 6 0 10 8 10 8 0 22 9 32 20 25 27 29 25 10 -4z"/>
<path d="M922 1156 c-21 -20 -42 -33 -46 -29 -3 3 -6 -1 -6 -10 0 -27 22 -19
64 23 50 51 41 63 -12 16z"/>
<path d="M620 1170 c-12 -8 -10 -10 8 -10 13 0 20 4 17 10 -7 12 -6 12 -25 0z"/>
<path d="M743 1156 c-15 -13 -26 -26 -23 -29 3 -3 21 8 40 24 19 16 29 29 23
29 -7 0 -25 -11 -40 -24z"/>
<path d="M1393 1113 c-11 -38 -26 -67 -32 -65 -6 1 -11 -1 -12 -5 0 -5 -2 -16
-4 -27 -3 -14 -1 -16 8 -7 14 14 30 15 22 1 -3 -5 -1 -10 5 -10 7 0 10 6 7 14
-3 8 0 33 7 56 17 57 31 35 35 -55 2 -38 7 -75 12 -82 7 -7 6 -14 -1 -18 -14
-8 -13 -52 2 -61 6 -4 8 -3 4 4 -3 6 -1 23 6 39 6 15 12 42 13 58 1 17 5 41 8
55 4 14 4 19 1 13 -13 -30 -26 -11 -20 28 4 26 3 38 -4 34 -6 -3 -7 0 -4 9 4
11 0 16 -13 16 -16 0 -18 6 -15 35 6 53 -2 42 -25 -32z"/>
<path d="M1683 1174 c3 -3 1 -17 -4 -31 -6 -16 -6 -31 1 -41 7 -14 9 -11 10
15 0 17 3 38 6 47 4 10 1 16 -7 16 -7 0 -10 -3 -6 -6z"/>
<path d="M749 1120 c-28 -27 -56 -50 -63 -50 -12 0 -66 -39 -54 -40 4 0 24 9
45 19 21 11 45 21 53 23 8 2 27 19 42 38 15 19 32 41 38 48 7 8 7 12 0 12 -5
0 -33 -22 -61 -50z"/>
<path d="M1263 1149 c-2 -17 1 -18 13 -9 17 15 18 30 1 30 -7 0 -13 -9 -14
-21z"/>
<path d="M560 1150 c-13 -9 -13 -10 0 -10 8 0 22 5 30 10 13 9 13 10 0 10 -8
0 -22 -5 -30 -10z"/>
<path d="M1119 1133 c-10 -11 -10 -14 -1 -9 6 4 12 2 12 -3 0 -6 -5 -11 -12
-11 -6 0 -8 -3 -4 -7 9 -9 -54 -73 -73 -74 -9 0 -11 -3 -5 -5 22 -9 87 45 101
84 15 45 15 42 4 42 -5 0 -15 -8 -22 -17z"/>
<path d="M494 1124 c-18 -15 -18 -15 2 -5 12 6 24 7 28 4 3 -3 6 -1 6 5 0 16
-12 15 -36 -4z"/>
<path d="M591 1124 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z"/>
<path d="M610 1131 c0 -5 5 -13 10 -16 6 -3 10 -2 10 4 0 5 -4 13 -10 16 -5 3
-10 2 -10 -4z"/>
<path d="M953 1110 c-9 -11 -20 -15 -23 -10 -3 5 -14 -5 -24 -23 -14 -26 -14
-28 -1 -12 9 11 21 19 27 17 5 -1 16 2 22 8 7 5 15 7 18 5 3 -3 8 3 11 15 7
26 -8 26 -30 0z"/>
<path d="M1280 1115 c-9 -11 -9 -15 -1 -15 7 0 9 -5 5 -12 -4 -7 -3 -10 1 -5
8 6 16 47 10 47 -2 0 -8 -7 -15 -15z"/>
<path d="M790 1095 c-20 -24 -6 -27 20 -5 17 15 19 20 8 20 -9 0 -21 -7 -28
-15z"/>
<path d="M547 1084 c4 -10 10 -11 24 -3 24 13 24 14 -5 15 -17 1 -23 -2 -19
-12z"/>
<path d="M1625 1090 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M864 1082 c3 -5 -4 -19 -15 -30 -11 -12 -16 -22 -11 -22 12 0 42 34
42 48 0 7 -5 12 -11 12 -5 0 -8 -4 -5 -8z"/>
<path d="M1261 1074 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z"/>
<path d="M440 1069 c0 -5 11 -9 25 -9 14 0 25 2 25 4 0 2 -11 6 -25 8 -14 3
-25 1 -25 -3z"/>
<path d="M967 1062 c-24 -27 -21 -36 4 -11 11 11 19 23 16 25 -2 2 -11 -4 -20
-14z"/>
<path d="M580 1055 c0 -8 2 -15 4 -15 2 0 6 7 10 15 3 8 1 15 -4 15 -6 0 -10
-7 -10 -15z"/>
<path d="M1612 1039 c-2 -18 2 -28 8 -24 5 3 8 15 7 25 -5 32 -13 31 -15 -1z"/>
<path d="M1143 1048 c-13 -16 -26 -58 -19 -58 8 0 38 61 33 66 -2 3 -9 -1 -14
-8z"/>
<path d="M694 1035 c-10 -8 -14 -15 -8 -15 6 0 17 7 24 15 16 19 9 19 -16 0z"/>
<path d="M722 1028 c-15 -15 -16 -31 0 -26 6 2 12 12 14 21 3 20 2 21 -14 5z"/>
<path d="M970 1000 c-17 -22 -27 -40 -21 -40 6 0 11 4 11 9 0 5 14 23 31 40
17 17 26 31 21 31 -6 0 -25 -18 -42 -40z"/>
<path d="M1095 1020 c-20 -22 -85 -63 -84 -52 5 30 -3 34 -19 9 -10 -15 -28
-36 -40 -48 -12 -11 -22 -24 -22 -29 0 -12 30 -14 30 -2 0 4 10 18 21 32 17
21 20 22 15 5 -6 -19 -5 -19 8 -2 8 10 17 18 20 18 15 -2 85 52 89 70 6 24 4
24 -18 -1z"/>
<path d="M1664 1015 c7 -36 12 -41 19 -16 3 11 -2 26 -10 32 -12 10 -13 8 -9
-16z"/>
<path d="M1710 1030 c0 -5 5 -10 10 -10 6 0 10 5 10 10 0 6 -4 10 -10 10 -5 0
-10 -4 -10 -10z"/>
<path d="M433 1023 c-7 -2 -13 -9 -13 -15 0 -7 4 -7 13 0 6 5 21 12 32 15 20
5 20 5 0 5 -11 0 -26 -2 -32 -5z"/>
<path d="M591 1013 c-1 -17 16 -25 25 -12 4 7 3 9 -4 5 -5 -3 -13 0 -15 6 -4
9 -6 10 -6 1z"/>
<path d="M790 1005 c-6 -8 -10 -19 -8 -24 4 -14 51 10 54 27 1 7 0 8 -3 2 -3
-8 -9 -8 -18 0 -9 7 -16 6 -25 -5z"/>
<path d="M912 1011 c-11 -6 -10 -10 4 -15 15 -6 13 -11 -14 -37 -18 -17 -32
-36 -32 -41 0 -5 -10 -6 -22 -3 -13 3 -18 3 -13 -2 10 -7 11 -15 6 -40 0 -4
-6 -2 -13 5 -7 7 -17 12 -22 12 -6 0 -1 -7 11 -15 18 -13 26 -13 43 -3 11 7
20 18 20 24 0 6 16 33 35 60 19 27 35 52 35 56 0 10 -22 10 -38 -1z"/>
<path d="M241 994 c0 -12 -18 -43 -40 -70 -36 -46 -37 -49 -16 -49 14 0 21 5
18 13 -7 17 17 44 33 38 8 -3 20 1 28 9 19 20 26 19 27 -2 0 -15 2 -15 8 2 8
21 4 45 -7 43 -24 -3 -41 4 -45 20 -4 13 -5 13 -6 -4z"/>
<path d="M455 994 c-16 -7 -33 -10 -37 -7 -5 2 -8 -3 -8 -13 0 -12 4 -14 13
-7 12 10 58 24 89 28 30 3 30 12 1 12 -16 0 -41 -6 -58 -13z"/>
<path d="M630 980 c-13 -11 -21 -22 -18 -25 3 -3 17 6 32 20 32 30 20 34 -14
5z"/>
<path d="M116 974 c-3 -8 -10 -13 -15 -9 -5 3 -13 -5 -17 -17 -4 -13 -11 -26
-17 -29 -6 -4 -5 -13 2 -25 9 -17 10 -17 11 -1 0 9 6 17 14 17 7 0 16 14 20
31 3 17 10 28 16 24 5 -3 10 -2 10 4 0 17 -18 21 -24 5z"/>
<path d="M1317 965 c-2 -14 -1 -27 2 -29 4 -3 8 -18 9 -35 2 -24 -1 -29 -13
-25 -10 4 -15 0 -15 -12 0 -11 -9 -32 -20 -49 -11 -16 -20 -37 -20 -45 0 -8
11 5 25 29 14 23 25 50 25 59 0 14 2 14 13 -1 11 -15 12 -14 14 10 0 15 6 29
12 31 6 2 10 22 10 45 -2 31 -3 34 -6 14 -2 -15 -8 -25 -13 -22 -4 3 -6 14 -3
24 3 10 0 21 -5 25 -5 3 -12 -6 -15 -19z"/>
<path d="M728 964 c-16 -8 -28 -20 -28 -27 0 -9 2 -9 8 0 4 6 20 15 35 18 15
4 27 11 27 16 0 12 -10 11 -42 -7z"/>
<path d="M475 960 c-3 -5 -14 -10 -25 -10 -10 0 -21 -7 -24 -16 -9 -24 -1 -28
17 -9 17 17 31 20 22 5 -12 -19 26 -23 58 -7 31 16 31 16 5 11 -40 -9 -64 2
-48 21 7 8 10 15 7 15 -3 0 -9 -4 -12 -10z"/>
<path d="M1650 963 c5 -2 8 -9 4 -14 -3 -5 0 -9 6 -9 15 0 7 23 -8 26 -7 1 -8
0 -2 -3z"/>
<path d="M777 930 c3 -11 10 -23 16 -27 6 -4 7 -1 2 7 -6 10 -4 12 9 7 22 -9
11 9 -14 23 -15 8 -17 7 -13 -10z"/>
<path d="M1095 920 c-16 -16 -27 -31 -24 -33 2 -2 17 11 32 30 36 41 31 43 -8
3z"/>
<path d="M1379 928 c0 -13 -2 -33 -3 -46 -2 -13 2 -21 8 -19 13 4 17 87 4 87
-4 0 -8 -10 -9 -22z"/>
<path d="M1605 940 c3 -5 8 -10 11 -10 2 0 4 5 4 10 0 6 -5 10 -11 10 -5 0 -7
-4 -4 -10z"/>
<path d="M668 933 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M1147 927 c-3 -8 1 -14 9 -14 16 0 19 13 5 21 -5 3 -11 0 -14 -7z"/>
<path d="M1269 901 c-14 -15 -33 -32 -42 -37 -11 -7 -13 -14 -7 -24 8 -12 13
-10 32 14 13 16 31 36 41 45 18 16 23 32 10 30 -5 0 -20 -13 -34 -28z"/>
<path d="M1660 894 c0 -19 4 -33 8 -30 8 5 4 66 -4 66 -2 0 -4 -16 -4 -36z"/>
<path d="M395 912 c-18 -13 -14 -28 8 -29 16 -2 18 0 8 6 -7 5 -10 14 -7 20 8
13 5 14 -9 3z"/>
<path d="M574 906 c-10 -8 -17 -17 -14 -19 3 -3 16 3 29 14 27 22 15 26 -15 5z"/>
<path d="M1500 901 c-12 -24 -13 -34 -1 -27 9 6 22 46 15 46 -2 0 -8 -9 -14
-19z"/>
<path d="M26 877 c-10 -22 -15 -44 -13 -50 3 -7 10 2 17 18 l12 30 9 -24 c5
-13 12 -21 16 -17 3 3 1 16 -5 29 -6 12 -13 29 -15 37 -3 10 -11 1 -21 -23z"/>
<path d="M482 891 c-11 -7 -11 -9 1 -14 9 -3 18 1 21 9 6 16 -2 18 -22 5z"/>
<path d="M1173 892 c-6 -4 -14 -21 -17 -37 -6 -28 -6 -29 4 -6 6 14 16 31 22
38 12 15 9 16 -9 5z"/>
<path d="M1013 863 c-36 -34 -49 -63 -27 -63 8 0 13 4 10 9 -3 4 6 19 19 31
14 13 25 18 25 11 0 -7 5 -9 10 -6 12 7 13 45 2 45 -5 0 -22 -12 -39 -27z"/>
<path d="M104 865 c-10 -8 -14 -15 -8 -15 6 0 17 7 24 15 16 19 9 19 -16 0z"/>
<path d="M1095 869 c-4 -6 -5 -12 -2 -15 2 -3 7 2 10 11 7 17 1 20 -8 4z"/>
<path d="M761 854 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z"/>
<path d="M365 850 c3 -5 8 -10 11 -10 2 0 4 5 4 10 0 6 -5 10 -11 10 -5 0 -7
-4 -4 -10z"/>
<path d="M900 849 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M952 848 c-15 -15 -16 -31 0 -26 6 2 12 12 14 21 3 20 2 21 -14 5z"/>
<path d="M1411 853 c-1 -7 8 -17 19 -23 14 -7 20 -7 20 0 0 5 -6 10 -14 10 -8
0 -17 6 -19 13 -4 9 -6 9 -6 0z"/>
<path d="M1469 833 c-18 -47 -26 -58 -38 -59 -6 -1 -14 -2 -18 -3 -4 0 2 -8
13 -17 18 -15 18 -15 0 -10 -17 6 -17 5 -5 -11 9 -11 10 -14 1 -9 -8 5 -15 -2
-22 -18 -5 -14 -16 -26 -25 -26 -8 0 -15 -7 -15 -16 0 -8 -4 -12 -10 -9 -5 3
-10 -1 -10 -9 0 -8 8 -19 17 -24 15 -9 14 -11 -5 -23 -13 -8 -18 -17 -12 -24
12 -14 -12 -61 -29 -57 -7 1 -10 -2 -7 -7 4 -5 0 -12 -6 -14 -7 -3 -8 -6 -3
-6 20 -1 45 27 65 73 24 58 25 64 3 68 -14 3 -9 10 19 28 21 14 36 31 33 38
-2 6 1 12 8 12 13 0 50 74 63 124 8 34 -4 33 -17 -1z"/>
<path d="M679 831 c-13 -11 -22 -22 -19 -24 3 -3 16 5 29 19 28 29 22 31 -10
5z"/>
<path d="M555 821 c-3 -5 -1 -12 4 -15 5 -3 11 1 15 9 6 16 -9 21 -19 6z"/>
<path d="M1110 815 c0 -8 -5 -14 -12 -12 -7 1 -13 -5 -14 -13 0 -8 -2 -21 -2
-28 -1 -7 -8 -12 -14 -11 -27 3 -38 -1 -38 -15 0 -8 4 -17 9 -20 5 -3 8 0 7 7
0 6 4 12 9 12 6 0 9 -4 7 -10 -2 -5 8 4 22 20 29 35 50 85 35 85 -5 0 -9 -7
-9 -15z"/>
<path d="M1166 814 c-4 -9 -4 -19 -1 -22 2 -3 7 3 11 12 4 9 4 19 1 22 -2 3
-7 -3 -11 -12z"/>
<path d="M1200 809 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1 736 c-1 -64 0 -69 12 -46 7 14 10 27 5 31 -4 3 -3 21 2 39 13 45
13 47 -4 47 -9 0 -14 -19 -15 -71z"/>
<path d="M1310 795 c-7 -8 -9 -23 -5 -36 6 -18 4 -21 -10 -15 -15 5 -16 4 -6
-8 9 -11 10 -24 2 -52 -5 -20 -7 -34 -4 -30 8 8 34 75 37 96 1 8 8 25 14 38
11 18 10 22 -1 22 -8 0 -20 -7 -27 -15z"/>
<path d="M624 778 c-11 -13 -30 -28 -44 -35 -20 -9 -21 -12 -6 -12 15 -1 16
-4 6 -16 -9 -10 -9 -15 -1 -15 10 0 15 13 12 33 0 4 6 7 14 7 15 0 51 47 42
56 -2 3 -13 -5 -23 -18z"/>
<path d="M409 788 c-12 -40 23 -62 42 -27 9 18 7 19 -17 13 -19 -5 -25 -4 -20
5 4 6 5 11 2 11 -3 0 -6 -1 -7 -2z"/>
<path d="M935 780 c-3 -5 -2 -10 4 -10 5 0 13 5 16 10 3 6 2 10 -4 10 -5 0
-13 -4 -16 -10z"/>
<path d="M660 770 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0 -4
-4 -4 -10z"/>
<path d="M1222 760 c-8 -13 -8 -20 -2 -20 6 0 13 7 17 15 9 24 -1 27 -15 5z"/>
<path d="M827 763 c-4 -3 -7 -11 -7 -17 0 -6 5 -5 12 2 6 6 9 14 7 17 -3 3 -9
2 -12 -2z"/>
<path d="M1002 765 c5 -5 -1 -14 -12 -22 -11 -8 -20 -22 -19 -31 0 -14 2 -14
6 -2 4 8 15 22 26 31 17 13 18 17 6 24 -8 5 -11 5 -7 0z"/>
<path d="M355 750 c3 -6 1 -10 -5 -10 -6 0 -9 -4 -5 -10 6 -10 35 -2 35 10 0
4 -7 11 -16 14 -8 3 -12 2 -9 -4z"/>
<path d="M1185 730 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M1469 733 c-1 -5 -1 -12 0 -17 1 -4 -6 -14 -16 -22 -16 -13 -16 -13
6 -6 26 9 41 32 21 32 -6 0 -8 5 -5 10 3 6 4 10 1 10 -3 0 -7 -3 -7 -7z"/>
<path d="M1147 701 c-4 -17 -2 -18 13 -8 10 6 16 15 14 19 -9 14 -22 9 -27
-11z"/>
<path d="M780 701 c0 -5 -12 -8 -27 -6 -26 3 -26 2 -8 -12 20 -15 20 -15 0
-11 -15 4 -21 0 -21 -13 0 -11 4 -19 8 -19 4 0 8 5 8 10 0 6 6 10 14 10 8 0
17 7 20 16 3 8 10 12 16 9 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M810 706 c0 -2 7 -7 16 -10 8 -3 12 -2 9 4 -6 10 -25 14 -25 6z"/>
<path d="M1590 696 c7 -7 14 -6 21 1 9 9 7 12 -9 10 -14 -1 -18 -5 -12 -11z"/>
<path d="M89 666 c-17 -19 -37 -32 -43 -30 -6 2 -20 -10 -30 -26 -19 -34 -17
-50 4 -25 7 8 16 15 20 15 4 0 30 23 57 50 28 28 44 50 37 50 -7 0 -27 -15
-45 -34z"/>
<path d="M250 663 c-12 -21 -31 -43 -41 -51 -18 -13 -27 -42 -11 -42 4 0 18
16 32 35 29 39 46 45 35 13 -3 -13 -6 -30 -6 -38 3 -56 0 -83 -8 -99 -14 -26
-21 -71 -11 -71 7 0 20 38 25 70 0 3 4 10 8 16 10 17 17 204 7 204 -4 0 -18
-17 -30 -37z"/>
<path d="M375 690 c-3 -5 1 -10 9 -10 9 0 16 5 16 10 0 6 -4 10 -9 10 -6 0
-13 -4 -16 -10z"/>
<path d="M880 685 c-11 -13 -10 -14 4 -9 9 3 16 10 16 15 0 13 -6 11 -20 -6z"/>
<path d="M923 687 c-3 -6 -1 -7 5 -3 7 4 12 2 12 -4 0 -6 5 -8 10 -5 6 3 10
10 10 14 0 11 -30 9 -37 -2z"/>
<path d="M1063 685 c-3 -9 -3 -19 1 -22 3 -4 6 1 6 10 0 10 4 17 8 17 14 0 32
-23 32 -42 0 -16 3 -16 20 -6 18 12 19 13 2 19 -10 4 -24 14 -31 23 -17 20
-30 20 -38 1z"/>
<path d="M987 676 c-4 -10 0 -14 12 -13 11 1 17 7 14 14 -7 17 -20 17 -26 -1z"/>
<path d="M1576 663 c-6 -14 -5 -15 5 -6 7 7 10 15 7 18 -3 3 -9 -2 -12 -12z"/>
<path d="M1073 655 c-7 -8 -13 -19 -13 -25 0 -5 -4 -10 -10 -10 -5 0 -10 -6
-10 -12 1 -15 50 38 50 53 0 12 -2 11 -17 -6z"/>
<path d="M950 638 c0 -4 7 -8 15 -8 8 0 15 4 15 8 0 5 -7 9 -15 9 -8 0 -15 -4
-15 -9z"/>
<path d="M1215 640 c4 -6 11 -8 16 -5 14 9 11 15 -7 15 -8 0 -12 -5 -9 -10z"/>
<path d="M480 620 c-13 -8 -12 -10 3 -10 9 0 17 5 17 10 0 12 -1 12 -20 0z"/>
<path d="M894 622 c-6 -4 -14 -16 -17 -27 -7 -20 -7 -20 8 -1 8 11 21 23 27
28 7 4 9 8 3 8 -5 0 -15 -4 -21 -8z"/>
<path d="M728 608 c5 -5 16 -8 23 -6 8 3 3 7 -10 11 -17 4 -21 3 -13 -5z"/>
<path d="M1405 610 c-3 -6 1 -7 9 -4 18 7 21 14 7 14 -6 0 -13 -4 -16 -10z"/>
<path d="M1440 599 c0 -23 10 -28 35 -18 18 7 18 8 1 8 -11 1 -16 6 -13 14 3
8 -1 14 -9 14 -8 0 -14 -8 -14 -18z"/>
<path d="M813 595 c0 -8 4 -12 9 -9 5 3 6 10 3 15 -9 13 -12 11 -12 -6z"/>
<path d="M1271 573 c2 -24 2 -25 6 -5 2 12 9 20 14 17 5 -4 9 -1 9 4 0 6 -7
11 -15 11 -10 0 -15 -9 -14 -27z"/>
<path d="M1125 580 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M1163 565 c0 -8 4 -12 9 -9 5 3 6 10 3 15 -9 13 -12 11 -12 -6z"/>
<path d="M1880 573 c0 -5 7 -19 16 -31 8 -12 12 -22 9 -22 -3 0 1 -10 9 -22
20 -28 20 -42 2 -35 -11 4 -11 1 -2 -18 6 -13 14 -21 18 -19 4 3 10 -8 13 -23
4 -15 11 -38 16 -51 7 -17 6 -21 -3 -16 -8 5 -9 2 -4 -12 5 -10 9 -26 10 -34
0 -8 5 -18 9 -21 5 -4 7 -16 5 -29 -3 -22 -3 -22 -25 -2 -13 10 -19 23 -15 27
4 5 1 5 -5 1 -10 -5 -9 -13 3 -32 9 -13 20 -24 25 -24 5 0 9 -12 9 -27 0 -23
-2 -25 -11 -13 -9 12 -10 11 -4 -5 4 -11 9 -53 12 -92 4 -55 10 -73 20 -73 13
0 14 25 10 162 -4 147 -8 172 -35 254 -16 50 -37 104 -46 122 -16 31 -36 50
-36 35z"/>
<path d="M30 548 c-12 -22 -12 -22 6 -6 10 10 15 20 12 24 -4 3 -12 -5 -18
-18z"/>
<path d="M430 559 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1212 550 c-7 -11 -8 -20 -3 -20 9 0 24 30 18 36 -1 2 -8 -6 -15 -16z"/>
<path d="M165 544 c21 -16 19 -37 -6 -52 -12 -8 -18 -19 -15 -28 3 -8 1 -14
-5 -14 -6 0 -8 -9 -4 -19 4 -13 -5 -37 -24 -67 -16 -27 -27 -52 -24 -57 7 -12
47 59 67 121 19 56 38 78 58 66 10 -6 9 -3 -1 9 -8 11 -9 17 -3 17 6 0 16 10
22 23 9 18 9 20 -2 7 -18 -20 -42 -25 -35 -7 4 11 -2 14 -19 13 -20 -1 -22 -3
-9 -12z"/>
<path d="M998 553 c6 -2 9 -10 6 -15 -4 -7 -2 -8 5 -4 13 9 5 26 -12 25 -9 0
-8 -2 1 -6z"/>
<path d="M1463 540 c1 -21 12 -26 22 -10 3 6 1 10 -5 10 -6 0 -8 5 -5 10 3 6
2 10 -4 10 -5 0 -9 -9 -8 -20z"/>
<path d="M1045 518 c-4 -18 -17 -42 -29 -53 -12 -11 -17 -17 -11 -13 7 4 15 5
18 1 4 -3 9 1 13 10 3 9 11 15 17 13 7 -1 9 -1 6 1 -3 2 -4 19 -2 38 4 44 -3
45 -12 3z"/>
<path d="M130 530 c-13 -8 -12 -10 3 -10 9 0 17 5 17 10 0 12 -1 12 -20 0z"/>
<path d="M570 525 c-8 -9 -8 -15 -2 -15 12 0 26 19 19 26 -2 2 -10 -2 -17 -11z"/>
<path d="M712 501 c-16 -17 -33 -27 -36 -23 -4 3 -4 -1 -1 -10 6 -14 12 -11
41 19 19 20 33 37 31 40 -3 2 -18 -10 -35 -26z"/>
<path d="M850 516 c0 -8 4 -17 9 -20 5 -4 7 3 4 14 -6 23 -13 26 -13 6z"/>
<path d="M1436 516 c3 -9 1 -23 -6 -31 -7 -8 -8 -15 -4 -15 5 0 15 9 21 19 10
16 9 22 -3 32 -12 10 -13 9 -8 -5z"/>
<path d="M1260 510 c-8 -5 -10 -10 -5 -10 6 0 17 5 25 10 8 5 11 10 5 10 -5 0
-17 -5 -25 -10z"/>
<path d="M106 499 c10 -17 -56 -72 -71 -59 -8 7 -16 3 -25 -15 -7 -14 -10 -28
-6 -32 4 -4 9 3 13 16 3 14 11 20 20 17 8 -3 32 11 55 32 34 32 38 40 24 45
-11 5 -15 3 -10 -4z"/>
<path d="M1225 500 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M635 474 c-9 -15 -12 -23 -6 -20 6 4 11 2 11 -3 0 -6 5 -11 11 -11 8
0 8 5 -1 15 -7 8 -8 15 -3 15 5 0 10 7 10 15 0 20 -2 19 -22 -11z"/>
<path d="M100 421 c0 -5 -6 -16 -12 -23 -51 -53 -40 -69 11 -17 34 34 39 49
16 49 -8 0 -15 -4 -15 -9z"/>
<path d="M176 388 c0 -23 6 -44 12 -46 14 -4 15 -55 2 -100 -8 -29 -7 -32 5
-22 17 14 30 93 20 117 -15 33 -15 56 -3 71 11 13 10 15 -3 10 -9 -4 -21 -2
-25 2 -6 6 -9 -8 -8 -32z"/>
<path d="M735 420 c-3 -6 1 -7 9 -4 18 7 21 14 7 14 -6 0 -13 -4 -16 -10z"/>
<path d="M1305 380 c-3 -5 1 -10 10 -10 9 0 13 5 10 10 -3 6 -8 10 -10 10 -2
0 -7 -4 -10 -10z"/>
<path d="M825 370 c-3 -5 -21 -10 -38 -10 -21 0 -28 -3 -19 -9 8 -4 13 -11 13
-15 -4 -29 13 -37 22 -12 4 11 1 13 -11 9 -14 -5 -15 -3 -5 7 9 10 15 10 26 1
15 -11 22 -7 41 27 9 14 -20 17 -29 2z"/>
<path d="M11 323 c-10 -26 -10 -27 4 -9 8 11 15 23 15 28 0 15 -7 8 -19 -19z"/>
<path d="M483 335 c-3 -9 -3 -18 -1 -21 3 -3 8 4 11 16 6 23 -1 27 -10 5z"/>
<path d="M1840 340 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0
-4 -4 -4 -10z"/>
<path d="M570 320 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0 -4
-4 -4 -10z"/>
<path d="M873 317 c0 -8 6 -14 14 -14 9 0 10 4 2 14 -6 7 -12 13 -14 13 -1 0
-2 -6 -2 -13z"/>
<path d="M1356 317 c3 -10 9 -15 12 -12 3 3 0 11 -7 18 -10 9 -11 8 -5 -6z"/>
<path d="M166 297 c3 -10 9 -15 12 -12 3 3 0 11 -7 18 -10 9 -11 8 -5 -6z"/>
<path d="M94 285 c-10 -8 -15 -15 -10 -15 5 0 4 -6 -1 -12 -5 -7 -10 -29 -11
-48 0 -33 0 -32 13 13 7 26 19 54 25 62 16 19 9 19 -16 0z"/>
<path d="M492 284 c-12 -8 -28 -12 -35 -8 -6 4 -5 -1 4 -11 13 -13 21 -15 37
-6 20 11 38 41 24 41 -4 0 -18 -7 -30 -16z"/>
<path d="M590 291 c0 -6 5 -11 11 -11 5 0 7 -4 4 -10 -3 -5 -1 -10 4 -10 16 0
13 16 -4 30 -10 9 -15 9 -15 1z"/>
<path d="M747 293 c-4 -3 -7 -13 -7 -22 1 -13 3 -13 11 2 11 19 8 33 -4 20z"/>
<path d="M127 283 c-11 -18 -4 -63 9 -63 16 0 19 16 4 25 -6 4 -8 15 -5 26 6
19 1 26 -8 12z"/>
<path d="M627 256 c-3 -8 5 -22 19 -33 13 -10 22 -24 19 -30 -9 -26 11 -12 28
19 13 23 21 28 26 19 7 -10 9 -9 14 2 3 9 -1 18 -9 21 -8 3 -17 0 -20 -7 -7
-19 -44 -14 -59 7 -11 14 -14 14 -18 2z"/>
<path d="M1075 250 c-10 -11 -14 -20 -9 -20 5 0 17 9 27 20 9 11 13 20 8 20
-4 0 -16 -9 -26 -20z"/>
<path d="M1155 261 c-3 -5 -2 -12 3 -15 5 -3 9 1 9 9 0 17 -3 19 -12 6z"/>
<path d="M1450 245 c-7 -8 -16 -12 -21 -9 -5 3 -9 -2 -9 -10 0 -9 7 -16 15
-16 8 0 15 7 15 15 0 7 8 19 18 24 9 6 12 11 6 11 -6 0 -17 -7 -24 -15z"/>
<path d="M1516 233 c10 -40 15 -42 12 -5 -1 18 -6 32 -10 32 -5 0 -5 -12 -2
-27z"/>
<path d="M40 219 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10 -5
-10 -11z"/>
<path d="M1010 189 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M1136 192 c-3 -5 1 -9 9 -9 8 0 12 4 9 9 -3 4 -7 8 -9 8 -2 0 -6 -4
-9 -8z"/>
<path d="M583 175 c-7 -8 -13 -18 -13 -22 0 -4 -11 -21 -25 -37 -30 -35 -31
-40 -5 -24 10 7 27 27 37 45 9 17 20 30 25 27 4 -3 5 2 2 10 -7 19 -6 19 -21
1z"/>
<path d="M920 181 c0 -6 4 -13 10 -16 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M1531 170 c0 -8 4 -24 9 -35 9 -20 9 -20 9 0 0 11 -4 27 -9 35 -9 13
-10 13 -9 0z"/>
<path d="M1418 156 c-10 -7 -18 -19 -18 -26 0 -7 9 -3 20 10 28 33 27 39 -2
16z"/>
<path d="M520 145 c0 -8 2 -15 4 -15 2 0 6 7 10 15 3 8 1 15 -4 15 -6 0 -10
-7 -10 -15z"/>
<path d="M1602 140 c0 -14 2 -19 5 -12 2 6 2 18 0 25 -3 6 -5 1 -5 -13z"/>
<path d="M730 129 c0 -10 5 -21 12 -25 7 -4 8 -3 4 5 -4 6 -3 18 3 25 8 9 7
13 -4 13 -8 0 -15 -8 -15 -18z"/>
<path d="M666 131 c-4 -7 -5 -15 -2 -18 9 -9 19 4 14 18 -4 11 -6 11 -12 0z"/>
<path d="M496 121 c-5 -7 -18 -16 -30 -21 -20 -8 -20 -9 -1 -9 27 -1 48 14 43
30 -3 10 -6 10 -12 0z"/>
<path d="M923 114 c-15 -16 -16 -24 -4 -24 8 0 24 30 19 35 -2 2 -9 -3 -15
-11z"/>
<path d="M1497 103 c-3 -16 -3 -30 -1 -33 7 -7 24 23 24 43 0 27 -17 20 -23
-10z"/>
<path d="M832 105 c3 -3 -5 -18 -17 -31 -13 -14 -21 -32 -18 -40 6 -16 26 -8
20 9 -2 6 7 21 20 33 21 20 22 22 6 28 -10 4 -15 4 -11 1z"/>
<path d="M380 75 c-7 -9 -10 -18 -6 -22 3 -3 6 -1 6 6 0 7 3 10 8 8 4 -3 13 1
20 9 10 11 10 14 -1 14 -8 0 -20 -7 -27 -15z"/>
<path d="M1026 73 c-6 -14 -5 -15 5 -6 7 7 10 15 7 18 -3 3 -9 -2 -12 -12z"/>
<path d="M450 65 c-7 -8 -8 -15 -2 -15 5 0 15 7 22 15 7 8 8 15 2 15 -5 0 -15
-7 -22 -15z"/>
<path d="M1920 71 c0 -6 5 -13 11 -16 6 -4 8 -14 4 -22 -4 -13 -3 -14 9 -4 13
11 13 15 -2 32 -19 21 -22 23 -22 10z"/>
<path d="M66 61 c-6 -9 9 -61 18 -61 2 0 6 8 8 18 6 21 -17 58 -26 43z"/>
<path d="M1391 63 c-1 -17 16 -25 25 -12 4 7 3 9 -4 5 -5 -3 -13 0 -15 6 -4 9
-6 10 -6 1z"/>
<path d="M280 50 c-8 -5 -12 -11 -9 -14 2 -3 11 -1 19 4 8 5 12 11 9 14 -2 3
-11 1 -19 -4z"/>
<path d="M1252 40 c0 -14 2 -19 5 -12 2 6 2 18 0 25 -3 6 -5 1 -5 -13z"/>
<path d="M1465 50 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M1626 48 c-7 -21 -3 -48 5 -43 4 3 6 13 5 23 -2 9 4 20 13 24 14 6
14 7 -2 7 -10 1 -19 -5 -21 -11z"/>
<path d="M7 25 c-4 -26 -4 -26 14 -6 23 24 24 31 5 31 -7 0 -16 -11 -19 -25z"/>
<path d="M1520 38 c0 -9 -8 -22 -17 -27 -16 -9 -16 -10 -2 -11 24 0 40 23 29
40 -8 13 -10 12 -10 -2z"/>
<path d="M930 31 c0 -6 4 -13 10 -16 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M735 20 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0 -8
-4 -11 -10z"/>
</g>
<path d="M0 0 h 300 v 15 h -300 z"/>
<path d="M0 285 h 300 v 15 h -300 z"/>
<path d="M0 0 v 300 h 15 v -300 z"/>
<path d="M285 0 v 300 h 15 v -300 z"/>
</svg>

After

Width:  |  Height:  |  Size: 54 KiB

28
scryer-prolog.wxs Normal file
View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Name="Scryer Prolog" Manufacturer="Scryer Prolog contributors" Id="*" UpgradeCode="cfb2dee4-5dd5-4d7d-b426-cd7340810559" Language="1033" Codepage="1252" Version="0.9.0">
<Package Description="An open source industrial strength production environment for ISO Prolog that is also a testbed for bleeding edge research in logic and constraint programming, which is itself written in a high-level language." Platform="x64" Keywords="prolog" Id="*" Compressed="yes" InstallScope="perMachine" InstallerVersion="300" Languages="1033" SummaryCodepage="1252" Manufacturer="Scryer Prolog contributors"/>
<Property Id="APPHELPLINK" Value="https://github.com/mthom/scryer-prolog"/>
<Media Id="1" Cabinet="scryer.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="INSTALLDIR" Name="Scryer Prolog">
<Component Id="MainExecutable" Guid="1b41ceda-ba18-47f9-911b-ee41b4f20921">
<File Id="ScryerPrologEXE" Name="scryer-prolog.exe" DiskId="1" Source="target/release/scryer-prolog.exe" KeyPath="yes" Checksum="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Component Id="ApplicationShortcut" Guid="8c9b14a3-e7b1-4d30-a892-61d7371dcae2">
<Shortcut Id="ApplicationStarMenuShortcut" Name="Scryer Prolog" Description="Launch Scryer Prolog" Target="[#ScryerPrologEXE]" WorkingDirectory="INSTALLDIR"/>
<RemoveFolder Id="ApplicationShortcut" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\ScryerProlog" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Feature Id="Complete" Level="1" Display="expand" ConfigurableDirectory="INSTALLDIR">
<ComponentRef Id="MainExecutable"/>
<ComponentRef Id="ApplicationShortcut"/>
</Feature>
</Product>
</Wix>

57
src/allocator.rs Normal file
View File

@@ -0,0 +1,57 @@
use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
use crate::targets::*;
use std::cell::Cell;
pub(crate) trait Allocator {
fn new() -> Self;
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
context: GenContext,
code: &mut CodeDeque,
) -> RegType;
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
context: GenContext,
cell: &'a Cell<RegType>,
code: &mut CodeDeque,
);
#[allow(clippy::too_many_arguments)]
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
);
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
cell: &Cell<VarReg>,
context: GenContext,
code: &mut CodeDeque,
);
fn reset(&mut self);
fn reset_arg(&mut self, arg_num: usize);
fn reset_at_head(&mut self, args: &[Term]);
fn reset_contents(&mut self);
fn advance_arg(&mut self);
fn max_reg_allocated(&self) -> usize;
}

889
src/arena.rs Normal file
View File

@@ -0,0 +1,889 @@
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
#[cfg(feature = "http")]
use crate::http::{HttpListener, HttpResponse};
use crate::machine::loader::LiveLoadState;
use crate::machine::streams::*;
use crate::offset_table::*;
use crate::read::*;
use crate::types::UntypedArenaPtr;
use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::mem;
use std::mem::ManuallyDrop;
use std::net::TcpListener;
use std::ops::{Deref, DerefMut};
use std::process::Child;
use std::ptr;
use std::ptr::addr_of_mut;
use std::ptr::NonNull;
use crate::machine::streams::{PipeReader, PipeWriter};
macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{
let result = $e;
$crate::arena::AllocateInArena::arena_allocate(result, $arena)
}};
}
macro_rules! float_alloc {
($e:expr, $arena:expr) => {{
$arena.f64_tbl.build_with(OrderedFloat($e))
}};
}
pub fn header_offset_from_payload<T: ?Sized + ArenaAllocated>() -> usize
where
T::Payload: Sized,
{
let payload_offset = mem::offset_of!(TypedAllocSlab<T>, payload);
let slab_offset = mem::offset_of!(TypedAllocSlab<T>, slab);
let header_offset = slab_offset + mem::offset_of!(AllocSlab, header);
debug_assert!(payload_offset > header_offset);
payload_offset - header_offset
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
#[bits = 7]
pub enum ArenaHeaderTag {
Integer = 0b10,
Rational = 0b11,
LiveLoadState = 0b0001000,
InactiveLoadState = 0b1011000,
InputFileStream = 0b10000,
OutputFileStream = 0b10100,
NamedTcpStream = 0b011100,
NamedTlsStream = 0b100000,
HttpReadStream = 0b100001,
HttpWriteStream = 0b100010,
ReadlineStream = 0b110000,
StaticStringStream = 0b110100,
ByteStream = 0b111000,
CallbackStream = 0b111001,
InputChannelStream = 0b111010,
StandardOutputStream = 0b1100,
StandardErrorStream = 0b11000,
NullStream = 0b111100,
TcpListener = 0b1000000,
HttpListener = 0b1000001,
HttpResponse = 0b1000010,
PipeWriter = 0b1000011,
Dropped = 0b1000100,
PipeReader = 0b1001001,
ChildProcess = 0b1001010,
}
#[bitfield]
#[repr(align(8))]
#[derive(Copy, Clone, Debug)]
pub struct ArenaHeader {
#[allow(dead_code)]
size: B56,
m: bool,
tag: ArenaHeaderTag,
}
const_assert!(mem::size_of::<ArenaHeader>() == 8);
impl ArenaHeader {
#[inline]
pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
ArenaHeader::new()
.with_size(size)
.with_tag(tag)
.with_m(false)
}
#[inline]
pub fn get_tag(self) -> ArenaHeaderTag {
self.tag()
}
}
#[derive(Debug)]
pub struct TypedArenaPtr<T: ?Sized + ArenaAllocated>(ptr::NonNull<T::Payload>);
impl<T: ?Sized + ArenaAllocated> PartialOrd for TypedArenaPtr<T>
where
T::Payload: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: ?Sized + ArenaAllocated> PartialEq for TypedArenaPtr<T>
where
T::Payload: PartialEq,
{
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
std::ptr::addr_eq(self.0.as_ptr(), other.0.as_ptr()) || **self == **other
}
}
impl<T: ?Sized + ArenaAllocated> Eq for TypedArenaPtr<T> where T::Payload: Eq {}
impl<T: ?Sized + ArenaAllocated> Ord for TypedArenaPtr<T>
where
T::Payload: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + ArenaAllocated> Hash for TypedArenaPtr<T>
where
T::Payload: Hash,
{
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
(self as &T::Payload).hash(hasher)
}
}
impl<T: ?Sized + ArenaAllocated> Clone for TypedArenaPtr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + ArenaAllocated> Copy for TypedArenaPtr<T> {}
impl<T: ?Sized + ArenaAllocated> Deref for TypedArenaPtr<T> {
type Target = T::Payload;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl<T: ?Sized + ArenaAllocated> DerefMut for TypedArenaPtr<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl<T: ArenaAllocated> fmt::Display for TypedArenaPtr<T>
where
T::Payload: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", (self as &T::Payload))
}
}
impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
#[inline]
pub fn as_ptr(&self) -> *mut T::Payload {
self.0.as_ptr()
}
}
impl<P, T: ?Sized + ArenaAllocated<Payload = ManuallyDrop<P>>> TypedArenaPtr<T> {
pub fn drop_payload(&mut self) {
if self.get_tag() != ArenaHeaderTag::Dropped {
self.set_tag(ArenaHeaderTag::Dropped);
unsafe { ManuallyDrop::drop(&mut *self.as_ptr()) }
}
}
}
impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T>
where
T::Payload: Sized,
{
#[inline]
pub fn header_ptr(&self) -> *const ArenaHeader {
unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *const _ }
}
#[inline]
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *mut _ }
}
#[inline]
pub fn get_mark_bit(&self) -> bool {
unsafe { (*self.header_ptr()).m() }
}
#[inline]
pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
unsafe {
(*self.header_ptr_mut()).set_tag(tag);
}
}
#[inline]
pub fn get_tag(&self) -> ArenaHeaderTag {
unsafe { (*self.header_ptr()).get_tag() }
}
#[inline]
pub fn mark(&mut self) {
unsafe {
(*self.header_ptr_mut()).set_m(true);
}
}
#[inline]
pub fn unmark(&mut self) {
unsafe {
(*self.header_ptr_mut()).set_m(false);
}
}
}
pub trait AllocateInArena<AllocFor>
where
AllocFor: ArenaAllocated,
{
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<AllocFor>;
}
impl<P, T: ArenaAllocated<Payload = P>> AllocateInArena<T> for P {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<T> {
T::alloc(arena, self)
}
}
/* this isn't allowed due to https://github.com/rust-lang/rust/issues/20400 I think,
though P == ManuallyDrop<P> might also be a problem event though that shouldn't be possible
impl<P, T: ArenaAllocated<Payload = ManuallyDrop<P>>> AllocateInArena<T> for P {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<T> {
T::alloc(arena, ManuallyDrop::new(self))
}
}
*/
pub trait ArenaAllocated {
type Payload: ?Sized;
fn tag() -> ArenaHeaderTag;
fn header_offset_from_payload() -> usize
where
Self::Payload: Sized,
{
header_offset_from_payload::<Self>()
}
/// # Safety
/// - the caller must guarantee that the pointee type of UntypedArenaPtr is Self
/// - the pointer must be non-null
unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr<Self>
where
Self::Payload: Sized,
{
TypedArenaPtr(NonNull::new_unchecked(
ptr.payload_offset().cast_mut().cast::<Self::Payload>(),
))
}
#[allow(clippy::missing_safety_doc)]
fn alloc(arena: &mut Arena, value: Self::Payload) -> TypedArenaPtr<Self>
where
Self::Payload: Sized,
{
let size = mem::size_of::<TypedAllocSlab<Self>>();
let slab = Box::new(TypedAllocSlab {
slab: AllocSlab {
next: arena.base.take(),
header: ArenaHeader::build_with(size as u64, Self::tag()),
},
payload: value,
});
let (allocated_ptr, untyped_slab) = slab.to_untyped();
arena.base = Some(untyped_slab);
allocated_ptr
}
/// # Safety
/// - ptr points to an allocated slab of the correct kind
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
drop(unsafe { Box::from_raw(ptr.as_ptr()) });
}
}
impl ArenaAllocated for Integer {
type Payload = Self;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Integer
}
}
impl ArenaAllocated for Rational {
type Payload = Self;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Rational
}
}
impl AllocateInArena<LiveLoadState> for LiveLoadState {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<LiveLoadState> {
LiveLoadState::alloc(arena, ManuallyDrop::new(self))
}
}
impl ArenaAllocated for LiveLoadState {
type Payload = ManuallyDrop<Self>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::LiveLoadState
}
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) };
match slab.tag() {
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
unsafe { ManuallyDrop::drop(&mut slab.payload) };
}
ArenaHeaderTag::Dropped => {}
_ => {
unreachable!()
}
}
drop(slab);
}
}
impl AllocateInArena<TcpListener> for TcpListener {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<TcpListener> {
TcpListener::alloc(arena, ManuallyDrop::new(self))
}
}
impl ArenaAllocated for TcpListener {
type Payload = ManuallyDrop<Self>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::TcpListener
}
}
#[cfg(feature = "http")]
impl ArenaAllocated for HttpListener {
type Payload = Self;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpListener
}
}
#[cfg(feature = "http")]
impl ArenaAllocated for HttpResponse {
type Payload = Self;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpResponse
}
}
impl ArenaAllocated for Child {
type Payload = ManuallyDrop<Self>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::ChildProcess
}
}
impl AllocateInArena<Child> for Child {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<Child> {
Child::alloc(arena, ManuallyDrop::new(self))
}
}
#[repr(C)]
#[derive(Debug)]
pub struct AllocSlab {
next: Option<UntypedArenaSlab>,
header: ArenaHeader,
}
const _: () = {
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
panic!("alignment of AllocSlab is too low");
}
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
panic!("alignment of header not a multiple of pointers alignment");
}
};
#[repr(C)]
#[derive(Debug)]
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
slab: AllocSlab,
payload: T::Payload,
}
impl<T: ?Sized + ArenaAllocated> TypedAllocSlab<T> {
pub fn tag(&self) -> ArenaHeaderTag {
self.slab.header.tag()
}
pub fn payload(&mut self) -> &mut T::Payload {
&mut self.payload
}
#[inline]
pub fn to_untyped(self: Box<Self>) -> (TypedArenaPtr<T>, UntypedArenaSlab) {
let raw_box = Box::into_raw(self);
// safety: the pointer from Box::into_raw fullfills addr_of_mut's saftey requirements
let payload_ptr = unsafe { addr_of_mut!((*raw_box).payload) };
(
TypedArenaPtr(unsafe {
// safety: the pointer points into a valid allocation so it is non null
ptr::NonNull::new_unchecked(payload_ptr)
}),
UntypedArenaSlab {
// safety: pointer from Box::into_raw is never null
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
tag: T::tag(),
},
)
}
}
#[derive(Debug)]
pub struct UntypedArenaSlab {
slab: NonNull<AllocSlab>,
tag: ArenaHeaderTag,
}
impl Drop for UntypedArenaSlab {
fn drop(&mut self) {
unsafe { drop_slab_in_place(self.slab, self.tag) };
}
}
#[derive(Debug)]
pub struct Arena {
base: Option<UntypedArenaSlab>,
pub f64_tbl: F64Table,
pub code_index_tbl: CodeIndexTable,
}
unsafe impl Send for Arena {}
unsafe impl Sync for Arena {}
#[allow(clippy::new_without_default)]
impl Arena {
#[inline]
pub fn new() -> Self {
Arena {
base: None,
f64_tbl: F64Table::new(),
code_index_tbl: CodeIndexTable::new(),
}
}
}
unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
macro_rules! drop_typed_slab_in_place {
($payload: ty, $value: expr) => {
<$payload as ArenaAllocated>::dealloc($value.cast::<TypedAllocSlab<$payload>>())
};
}
match tag {
ArenaHeaderTag::Integer => {
drop_typed_slab_in_place!(Integer, value);
}
ArenaHeaderTag::Rational => {
drop_typed_slab_in_place!(Rational, value);
}
ArenaHeaderTag::InputFileStream => {
drop_typed_slab_in_place!(InputFileStream, value);
}
ArenaHeaderTag::OutputFileStream => {
drop_typed_slab_in_place!(OutputFileStream, value);
}
ArenaHeaderTag::NamedTcpStream => {
drop_typed_slab_in_place!(NamedTcpStream, value);
}
ArenaHeaderTag::NamedTlsStream => {
#[cfg(feature = "tls")]
drop_typed_slab_in_place!(NamedTlsStream, value);
}
ArenaHeaderTag::HttpReadStream => {
#[cfg(feature = "http")]
drop_typed_slab_in_place!(HttpReadStream, value);
}
ArenaHeaderTag::HttpWriteStream => {
#[cfg(feature = "http")]
drop_typed_slab_in_place!(HttpWriteStream, value);
}
ArenaHeaderTag::ReadlineStream => {
drop_typed_slab_in_place!(ReadlineStream, value);
}
ArenaHeaderTag::StaticStringStream => {
drop_typed_slab_in_place!(StaticStringStream, value);
}
ArenaHeaderTag::ByteStream => {
drop_typed_slab_in_place!(ByteStream, value);
}
ArenaHeaderTag::CallbackStream => {
drop_typed_slab_in_place!(CallbackStream, value);
}
ArenaHeaderTag::InputChannelStream => {
drop_typed_slab_in_place!(InputChannelStream, value);
}
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
drop_typed_slab_in_place!(LiveLoadState, value);
}
ArenaHeaderTag::Dropped => {}
ArenaHeaderTag::TcpListener => {
drop_typed_slab_in_place!(TcpListener, value);
}
ArenaHeaderTag::HttpListener => {
#[cfg(feature = "http")]
drop_typed_slab_in_place!(HttpListener, value);
}
ArenaHeaderTag::HttpResponse => {
#[cfg(feature = "http")]
drop_typed_slab_in_place!(HttpResponse, value);
}
ArenaHeaderTag::StandardOutputStream => {
drop_typed_slab_in_place!(StandardOutputStream, value);
}
ArenaHeaderTag::StandardErrorStream => {
drop_typed_slab_in_place!(StandardErrorStream, value);
}
ArenaHeaderTag::PipeReader => {
drop_typed_slab_in_place!(PipeReader, value);
}
ArenaHeaderTag::PipeWriter => {
drop_typed_slab_in_place!(PipeWriter, value);
}
ArenaHeaderTag::ChildProcess => {
drop_typed_slab_in_place!(Child, value);
}
ArenaHeaderTag::NullStream => {
unreachable!("NullStream is never arena allocated!");
}
}
}
impl Drop for Arena {
fn drop(&mut self) {
// we un-nest UntypedArenaSlab to prevent stackoverflow due to the recursive drop
let mut ptr = self.base.take();
while let Some(mut slab) = ptr {
ptr = unsafe { slab.slab.as_mut() }.next.take();
drop(slab);
}
}
}
const_assert!(mem::size_of::<AllocSlab>() <= 24);
const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
#[cfg(test)]
mod tests {
use crate::arena::*;
use crate::atom_table::*;
use crate::machine::mock_wam::*;
use crate::types::*;
use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
#[test]
fn float_ptr_cast() {
let mut wam = MockWAM::new();
let f = 0f64;
let fp = float_alloc!(f, wam.machine_st.arena);
let mut cell = HeapCellValue::from(fp);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
assert!(!cell.get_mark_bit());
assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f));
cell.set_mark_bit(true);
assert!(cell.get_mark_bit());
read_heap_cell!(cell,
(HeapCellValueTag::F64Offset, offset) => {
let fp = wam.machine_st.arena.f64_tbl.get_entry(offset);
assert_eq!(fp, OrderedFloat(0f64))
}
_ => { unreachable!() }
);
}
#[test]
fn heap_cell_value_const_cast() {
let mut wam = MockWAM::new();
#[cfg(target_pointer_width = "32")]
let const_value = HeapCellValue::from(ConsPtr::build_with(
std::ptr::without_provenance(0x0000_0431),
ConsPtrMaskTag::Cons,
));
#[cfg(target_pointer_width = "64")]
let const_value = HeapCellValue::from(ConsPtr::build_with(
std::ptr::without_provenance(0x0000_5555_ff00_0431),
ConsPtrMaskTag::Cons,
));
match const_value.to_untyped_arena_ptr() {
Some(arena_ptr) => {
assert_eq!(
arena_ptr.into_bytes(),
const_value.to_untyped_arena_ptr_bytes()
);
}
None => {
unreachable!();
}
}
let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
let stream_cell =
HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
match stream_cell.to_untyped_arena_ptr() {
Some(arena_ptr) => {
assert_eq!(
arena_ptr.into_bytes(),
stream_cell.to_untyped_arena_ptr_bytes()
);
}
None => {
unreachable!();
}
}
}
#[test]
fn heap_put_literal_tests() {
let mut wam = MockWAM::new();
// integer
let big_int: Integer = 2 * Integer::from(1u64 << 63);
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
assert!(!big_int_ptr.as_ptr().is_null());
let cell = HeapCellValue::from(big_int_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
Some(ptr) => ptr,
None => {
unreachable!()
}
};
match_untyped_arena_ptr!(untyped_arena_ptr,
(ArenaHeaderTag::Integer, n) => {
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
}
_ => unreachable!()
);
read_heap_cell!(cell,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => {
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
}
_ => { unreachable!() }
)
}
_ => { unreachable!() }
);
// rational
let big_rat = Rational::from(2) * Rational::from(1u64 << 63);
let big_rat_ptr: TypedArenaPtr<Rational> = arena_alloc!(big_rat, &mut wam.machine_st.arena);
assert!(!big_rat_ptr.as_ptr().is_null());
let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
match rat_cell.to_untyped_arena_ptr() {
Some(untyped_arena_ptr) => {
assert_eq!(
Some(big_rat_ptr.header_ptr()),
Some(untyped_arena_ptr.into()),
);
}
None => {
unreachable!();
}
}
// assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons);
read_heap_cell!(rat_cell,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Rational, n) => {
assert_eq!(&*n, &(Rational::from(2) * Rational::from(1u64 << 63)));
}
_ => unreachable!()
)
}
_ => { unreachable!() }
);
// atom
let f_atom = atom!("f");
let g_atom = atom!("g");
assert_eq!(&*f_atom.as_str(), "f");
assert_eq!(&*g_atom.as_str(), "g");
let f_atom_cell = atom_as_cell!(f_atom);
let g_atom_cell = atom_as_cell!(g_atom);
assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom);
match f_atom_cell.to_atom() {
Some(atom) => {
assert_eq!(f_atom, atom);
assert_eq!(&*atom.as_str(), "f");
}
None => {
unreachable!();
}
}
read_heap_cell!(f_atom_cell,
(HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(f_atom, atom);
assert_eq!(arity, 0);
assert_eq!(&*atom.as_str(), "f");
}
_ => { unreachable!() }
);
read_heap_cell!(g_atom_cell,
(HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(g_atom, atom);
assert_eq!(arity, 0);
assert_eq!(&*atom.as_str(), "g");
}
_ => { unreachable!() }
);
// fixnum
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum);
match fixnum_cell.to_fixnum() {
Some(n) => assert_eq!(n.get_num(), 3),
None => unreachable!(),
}
read_heap_cell!(fixnum_cell,
(HeapCellValueTag::Fixnum, n) => {
assert_eq!(n.get_num(), 3);
}
_ => { unreachable!() }
);
let fixnum_b_cell = fixnum_as_cell!(
Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
);
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
match fixnum_b_cell.to_fixnum() {
Some(n) => assert_eq!(n.get_num(), 1 << 54),
None => unreachable!(),
}
Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
assert_eq!(
Fixnum::build_with_checked(-1i64)
.expect("-1 fits in fixnum")
.get_num(),
-1
);
Fixnum::build_with_checked((1i64 << 55) - 1)
.expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
Fixnum::build_with_checked(-(1i64 << 55))
.expect("-(1 << 55) is the smallest value that fits in fixnum");
Fixnum::build_with_checked(-(1i64 << 55) - 1)
.expect_err("-(1<<55) - 1 is too small for Fixnum");
assert_eq!(
-Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
Fixnum::build_with(1)
);
// float
let float = std::f64::consts::PI;
let float_ptr = float_alloc!(float, wam.machine_st.arena);
let cell = HeapCellValue::from(float_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
// char
let c = 'c';
let char_cell = char_as_cell!(c);
read_heap_cell!(char_cell,
(HeapCellValueTag::Atom, (c, _arity)) => {
assert_eq!(&*c.as_str(), "c");
}
_ => { unreachable!() }
);
let c = 'Ћ';
let cyrillic_char_cell = char_as_cell!(c);
read_heap_cell!(cyrillic_char_cell,
(HeapCellValueTag::Atom, (c, _arity)) => {
assert_eq!(&*c.as_str(), "Ћ");
}
_ => { unreachable!() }
);
// empty list
let cell = empty_list_as_cell!();
read_heap_cell!(cell,
(HeapCellValueTag::Atom, (el, _arity)) => {
assert_eq!(el.flat_index(), empty_list_as_cell!().get_value());
assert_eq!(&*el.as_str(), "[]");
}
_ => { unreachable!() }
);
}
}

710
src/arithmetic.rs Normal file
View File

@@ -0,0 +1,710 @@
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
use crate::allocator::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::offset_table::*;
use crate::targets::QueryInstruction;
use crate::types::*;
use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational};
use crate::machine::machine_errors::*;
use dashu::base::Abs;
use dashu::base::BitTest;
use num_order::NumOrd;
use ordered_float::{Float, OrderedFloat};
use std::cell::Cell;
use std::cmp::{max, min, Ordering};
use std::convert::TryFrom;
use std::f64;
use std::num::FpCategory;
use std::ops::Div;
use std::vec::Vec;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ArithmeticTerm {
Reg(RegType),
Interm(usize),
Number(Number),
}
impl ArithmeticTerm {
pub(crate) fn interm_or(&self, interm: usize) -> usize {
if let &ArithmeticTerm::Interm(interm) = self {
interm
} else {
interm
}
}
}
impl Default for ArithmeticTerm {
fn default() -> Self {
ArithmeticTerm::Number(Number::default())
}
}
#[derive(Debug)]
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
impl<'a> ArithInstructionIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack
.push(TermIterState::subterm_to_state(lvl, term));
}
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
let state = match term {
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
Term::Clause(cell, name, terms) => {
TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
}
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
return Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")),
2,
))
}
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
};
Ok(ArithInstructionIterator {
state_stack: vec![state],
})
}
}
#[derive(Debug)]
pub(crate) enum ArithTermRef<'a> {
Literal(Literal),
Op(Atom, usize), // name, arity.
Var(Level, &'a Cell<VarReg>, VarPtr),
}
impl<'a> Iterator for ArithInstructionIterator<'a> {
type Item = Result<ArithTermRef<'a>, ArithmeticError>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
let arity = subterms.len();
if child_num == arity {
return Some(Ok(ArithTermRef::Op(name, arity)));
} else {
self.state_stack.push(TermIterState::Clause(
lvl,
child_num + 1,
cell,
name,
subterms,
));
self.push_subterm(lvl.child_level(), &subterms[child_num]);
}
}
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))),
TermIterState::Var(lvl, cell, var_ptr) => {
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
}
_ => {
return Some(Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")),
2,
)));
}
};
}
None
}
}
#[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a> {
marker: &'a mut DebrayAllocator,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
}
pub(crate) trait ArithmeticTermIter<'a> {
type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
fn iter(self) -> Result<Self::Iter, ArithmeticError>;
}
impl<'a> ArithmeticTermIter<'a> for &'a Term {
type Iter = ArithInstructionIterator<'a>;
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
ArithInstructionIterator::from(self)
}
}
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
match c {
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
&Literal::F64(_offset, n) => {
interm.push(ArithmeticTerm::Number(Number::Float(n)));
}
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::E)),
)),
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::PI)),
)),
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(f64::EPSILON)),
)),
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
}
Ok(())
}
impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
ArithmeticEvaluator {
marker,
interm: Vec::new(),
interm_c: target_int,
}
}
fn get_unary_instr(
&self,
name: Atom,
a1: ArithmeticTerm,
t: usize,
) -> Result<Instruction, ArithmeticError> {
match name {
atom!("abs") => Ok(Instruction::Abs(a1, t)),
atom!("-") => Ok(Instruction::Neg(a1, t)),
atom!("+") => Ok(Instruction::Plus(a1, t)),
atom!("cos") => Ok(Instruction::Cos(a1, t)),
atom!("sin") => Ok(Instruction::Sin(a1, t)),
atom!("tan") => Ok(Instruction::Tan(a1, t)),
atom!("log") => Ok(Instruction::Log(a1, t)),
atom!("exp") => Ok(Instruction::Exp(a1, t)),
atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
atom!("acos") => Ok(Instruction::ACos(a1, t)),
atom!("asin") => Ok(Instruction::ASin(a1, t)),
atom!("atan") => Ok(Instruction::ATan(a1, t)),
atom!("float") => Ok(Instruction::Float(a1, t)),
atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
atom!("round") => Ok(Instruction::Round(a1, t)),
atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
atom!("floor") => Ok(Instruction::Floor(a1, t)),
atom!("float_integer_part") => Ok(Instruction::FloatIntegerPart(a1, t)),
atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
atom!("sign") => Ok(Instruction::Sign(a1, t)),
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
}
}
fn get_binary_instr(
&self,
name: Atom,
a1: ArithmeticTerm,
a2: ArithmeticTerm,
t: usize,
) -> Result<Instruction, ArithmeticError> {
match name {
atom!("+") => Ok(Instruction::Add(a1, a2, t)),
atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
atom!("/") => Ok(Instruction::Div(a1, a2, t)),
atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
atom!("max") => Ok(Instruction::Max(a1, a2, t)),
atom!("min") => Ok(Instruction::Min(a1, a2, t)),
atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
}
}
fn incr_interm(&mut self) -> usize {
let temp = self.interm_c;
self.interm.push(ArithmeticTerm::Interm(temp));
self.interm_c += 1;
temp
}
fn instr_from_clause(
&mut self,
name: Atom,
arity: usize,
) -> Result<Instruction, ArithmeticError> {
match arity {
1 => {
let a1 = self.interm.pop().unwrap();
let ninterm = if a1.interm_or(0) == 0 {
self.incr_interm()
} else {
self.interm.push(a1);
a1.interm_or(0)
};
self.get_unary_instr(name, a1, ninterm)
}
2 => {
let a2 = self.interm.pop().unwrap();
let a1 = self.interm.pop().unwrap();
let min_interm = min(a1.interm_or(0), a2.interm_or(0));
let ninterm = if min_interm == 0 {
let max_interm = max(a1.interm_or(0), a2.interm_or(0));
if max_interm == 0 {
self.incr_interm()
} else {
self.interm.push(ArithmeticTerm::Interm(max_interm));
self.interm_c = max_interm + 1;
max_interm
}
} else {
self.interm.push(ArithmeticTerm::Interm(min_interm));
self.interm_c = min_interm + 1;
min_interm
};
self.get_binary_instr(name, a1, a2, ninterm)
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(name),
arity,
)),
}
}
pub(crate) fn compile_is(
&mut self,
src: &'a Term,
term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut code = CodeDeque::new();
for term_ref in src.iter()? {
match term_ref? {
ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?,
ArithTermRef::Var(lvl, cell, name) => {
let var_num = name.to_var_num().unwrap();
let r = if lvl == Level::Shallow {
self.marker
.mark_non_callable(var_num, arg, term_loc, cell, &mut code)
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
let r = self.marker.get_binding(var_num);
if r.reg_num() == 0 {
self.marker.mark_var::<QueryInstruction>(
var_num, lvl, cell, term_loc, &mut code,
);
cell.get().norm()
} else {
self.marker.increment_running_count(var_num);
r
}
} else {
self.marker.increment_running_count(var_num);
cell.get().norm()
};
self.interm.push(ArithmeticTerm::Reg(r));
}
ArithTermRef::Op(name, arity) => {
code.push_back(self.instr_from_clause(name, arity)?);
}
}
}
Ok((code, self.interm.pop()))
}
}
// integer division rounding function -- 9.1.3.1.
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
match n {
&Number::Integer(i) => {
if let Ok(value) = Fixnum::build_with_checked(&*i) {
Ok(Number::Fixnum(value))
} else {
Ok(*n)
}
}
Number::Fixnum(_) => Ok(*n),
&Number::Float(f) => {
let f = f.floor();
const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
Ok(Number::Fixnum(
// Safety: We checked that the value is in range
unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
))
} else {
Ok(Number::Integer(arena_alloc!(
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
unreachable!();
}),
arena
)))
}
}
Number::Rational(ref r) => {
let floor = r.floor();
if let Ok(value) = Fixnum::build_with_checked(&floor) {
Ok(Number::Fixnum(value))
} else {
Ok(Number::Integer(arena_alloc!(floor, arena)))
}
}
}
}
impl From<Fixnum> for Integer {
#[inline]
fn from(n: Fixnum) -> Integer {
Integer::from(n.get_num())
}
}
// floating point rounding function -- 9.1.4.1.
pub(crate) fn rnd_f(n: &Number) -> f64 {
match n {
&Number::Fixnum(n) => n.get_num() as f64,
Number::Integer(ref n) => n.to_f64().value(),
&Number::Float(OrderedFloat(f)) => f,
Number::Rational(ref r) => r.to_f64().value(),
}
}
// floating point result function -- 9.1.4.2.
pub(crate) fn result_f(n: &Number) -> Result<f64, EvalError> {
classify_float(rnd_f(n))
}
fn classify_float(f: f64) -> Result<f64, EvalError> {
match f.classify() {
FpCategory::Normal | FpCategory::Zero => Ok(f),
FpCategory::Infinite => {
if OrderedFloat(f) == OrderedFloat(f64::MAX) {
Ok(f)
} else {
Err(EvalError::FloatOverflow)
}
}
FpCategory::Nan => Err(EvalError::Undefined),
_ => Ok(f),
}
}
#[inline]
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
classify_float(n as f64)
}
#[inline]
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
classify_float(n.to_f64().value())
}
#[inline]
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
classify_float(r.to_f64().value())
}
#[inline]
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 + f2)?))
}
#[inline]
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2)?))
}
#[inline]
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
if FpCategory::Zero == f2.classify() {
Err(EvalError::ZeroDivisor)
} else {
Ok(OrderedFloat(classify_float(f1 / f2)?))
}
}
impl Div<Number> for Number {
type Output = Result<Number, EvalError>;
fn div(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1.get_num())?,
float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1.get_num())?,
float_i_to_f(&n2)?,
)?)),
(Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
float_fn_to_f(n1.get_num())?,
float_r_to_f(&n2)?,
)?)),
(Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
float_r_to_f(&n1)?,
float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?))
}
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?))
}
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_i_to_f(&n2)?,
)?)),
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
}
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_r_to_f(&n2)?,
)?)),
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f(
float_r_to_f(&n2)?,
float_i_to_f(&n1)?,
)?)),
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
Ok(Number::Float(div_f(n2, float_r_to_f(&n1)?)?))
}
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(div_f(f1, f2)?))
}
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Float(div_f(
float_r_to_f(&r1)?,
float_r_to_f(&r2)?,
)?)),
}
}
}
impl PartialEq for Number {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
(&Number::Fixnum(n1), Number::Integer(ref n2)) => n1.get_num().num_eq(&**n2),
(Number::Integer(ref n1), &Number::Fixnum(n2)) => n1.num_eq(&n2.get_num()),
(&Number::Fixnum(n1), Number::Rational(ref n2)) => {
Integer::from(n1.get_num()).num_eq(&**n2)
}
(Number::Rational(ref n1), &Number::Fixnum(n2)) => {
n1.num_eq(&Integer::from(n2.get_num()))
}
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)),
(Number::Integer(ref n1), Number::Integer(ref n2)) => n1.eq(n2),
(Number::Integer(ref n1), Number::Float(n2)) => {
OrderedFloat(n1.to_f64().value()).eq(n2)
}
(&Number::Float(n1), Number::Integer(ref n2)) => {
n1.eq(&OrderedFloat(n2.to_f64().value()))
}
(Number::Integer(ref n1), Number::Rational(ref n2)) => n1.num_eq(&**n2),
(Number::Rational(ref n1), Number::Integer(ref n2)) => n1.num_eq(&**n2),
(Number::Rational(ref n1), &Number::Float(n2)) => {
OrderedFloat(n1.to_f64().value()).eq(&n2)
}
(&Number::Float(n1), Number::Rational(ref n2)) => {
n1.eq(&OrderedFloat(n2.to_f64().value()))
}
(&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
(Number::Rational(ref r1), Number::Rational(ref r2)) => r1.eq(r2),
}
}
}
impl Eq for Number {}
impl PartialOrd<usize> for Number {
#[inline]
fn partial_cmp(&self, rhs: &usize) -> Option<Ordering> {
match self {
Number::Fixnum(n) => {
let n = n.get_num();
if n < 0i64 {
Some(Ordering::Less)
} else {
(n as usize).partial_cmp(rhs)
}
}
Number::Integer(n) => Some((n).num_cmp(rhs)),
Number::Rational(r) => Some((r).num_cmp(&Integer::from(*rhs))),
Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
}
}
}
impl PartialEq<usize> for Number {
#[inline]
fn eq(&self, rhs: &usize) -> bool {
match self {
Number::Fixnum(n) => {
let n = n.get_num();
if n < 0i64 {
false
} else {
(n as usize).eq(rhs)
}
}
Number::Integer(n) => (n).num_eq(rhs),
Number::Rational(r) => (r).num_eq(&Integer::from(*rhs)),
Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
}
}
}
impl PartialOrd for Number {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Ord for Number {
fn cmp(&self, rhs: &Number) -> Ordering {
match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(n2),
(Number::Integer(n1), &Number::Fixnum(n2)) => (**n1).cmp(&Integer::from(n2.get_num())),
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(n2),
(Number::Rational(n1), &Number::Fixnum(n2)) => {
(**n1).cmp(&Rational::from(n2.get_num()))
}
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2),
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)),
(&Number::Integer(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2),
(&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).cmp(n2),
(&Number::Float(n1), Number::Integer(ref n2)) => {
n1.cmp(&OrderedFloat(n2.to_f64().value()))
}
(&Number::Integer(n1), &Number::Rational(n2)) => {
(*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
(&Number::Rational(n1), &Number::Integer(n2)) => {
(*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
(&Number::Rational(n1), &Number::Float(n2)) => {
OrderedFloat(n1.to_f64().value()).cmp(&n2)
}
(&Number::Float(n1), &Number::Rational(n2)) => {
n1.cmp(&OrderedFloat(n2.to_f64().value()))
}
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
(&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
}
}
}
impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number {
type Error = ();
#[inline]
fn try_from((value, f64_tbl): (HeapCellValue, &F64Table)) -> Result<Number, Self::Error> {
read_heap_cell!(value,
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, n) => {
Ok(Number::Integer(n))
}
(ArenaHeaderTag::Rational, n) => {
Ok(Number::Rational(n))
}
_ => {
Err(())
}
)
}
(HeapCellValueTag::F64Offset, offset) => {
let n = f64_tbl.get_entry(offset);
Ok(Number::Float(n))
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
Ok(Number::Fixnum(n))
}
_ => {
Err(())
}
)
}
}
// Computes n ^ power. Ignores the sign of power.
pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
let mut power = power.abs();
if power.is_zero() {
return Integer::ONE;
}
let mut oddand = Integer::ONE;
while power.num_gt(&1) {
if power.bit(0) {
oddand *= &n;
}
n = n.pow(2);
power >>= 1;
}
n * oddand
}

546
src/atom_table.rs Normal file
View File

@@ -0,0 +1,546 @@
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
use crate::parser::ast::MAX_ARITY;
use crate::raw_block::*;
use crate::types::*;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::str;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use std::sync::Weak;
use arcu::atomic::Arcu;
use arcu::epoch_counters::GlobalEpochCounterPool;
use arcu::rcu_ref::RcuRef;
use arcu::Rcu;
use indexmap::IndexSet;
use scryer_modular_bitfield::prelude::*;
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub struct AtomCell {
name: B48,
arity: B8,
#[allow(unused)]
f: bool,
#[allow(unused)]
m: bool,
#[allow(unused)]
is_inlined: bool,
#[allow(unused)]
tag: B5,
}
const INLINED_ATOM_MAX_LEN: usize = 6;
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<AtomCell>());
const_assert!(mem::size_of::<AtomCell>() == 8);
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<Atom>());
const_assert!(mem::size_of::<Atom>() == 8);
impl AtomCell {
#[inline]
fn new_static(index: u64) -> Self {
// upper 23 bits of index must be 0
debug_assert_eq!(index & !((1 << 49) - 1), 0);
AtomCell::new()
.with_name(index)
.with_arity(0u8)
.with_m(false)
.with_f(false)
.with_is_inlined(false)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
fn new_inlined(string: &str, arity: u8) -> Self {
debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN);
let mut string_buf: [u8; 8] = [0u8; 8];
string_buf[..string.len()].copy_from_slice(string.as_bytes());
let encoding = u64::from_le_bytes(string_buf);
AtomCell::new()
.with_name(encoding)
.with_arity(arity)
.with_m(false)
.with_f(false)
.with_is_inlined(true)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn new_char_inlined(c: char) -> Self {
if c == '\u{0}' {
return Self::new_static(NULL_ATOM.flat_index());
}
let mut char_buf = [0u8; 8];
c.encode_utf8(&mut char_buf);
let encoding = u64::from_le_bytes(char_buf);
AtomCell::new()
.with_name(encoding)
.with_arity(0u8)
.with_m(false)
.with_f(false)
.with_is_inlined(true)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn build_with(atom_index: u64, arity: u8) -> Self {
debug_assert!((arity as usize) <= MAX_ARITY);
AtomCell::new()
.with_name(atom_index >> 1)
.with_arity(arity)
.with_f(false)
.with_m(false)
.with_is_inlined(atom_index & 1 == 1)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn get_name(self) -> Atom {
Atom {
index: (self.name() << 1) | self.is_inlined() as u64,
}
}
#[inline]
pub fn get_arity(self) -> usize {
self.arity() as usize
}
#[inline]
pub fn get_name_and_arity(self) -> (Atom, usize) {
(self.get_name(), self.get_arity())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Atom {
pub index: u64,
}
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
// populate these in STRINGS so they can be used from build_functor
const _: Atom = atom!(".");
const _: Atom = atom!("[]");
const NULL_ATOM: Atom = atom!("\0");
impl<'a> From<&'a Atom> for Atom {
#[inline]
fn from(atom: &'a Atom) -> Self {
*atom
}
}
impl indexmap::Equivalent<Atom> for str {
fn equivalent(&self, key: &Atom) -> bool {
&*key.as_str() == self
}
}
impl PartialEq<str> for Atom {
fn eq(&self, other: &str) -> bool {
self.as_str().deref() == other
}
}
impl PartialEq<&str> for Atom {
fn eq(&self, &other: &&str) -> bool {
self.as_str().deref() == other
}
}
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
const ATOM_TABLE_ALIGN: usize = 8;
#[inline(always)]
fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {
static GLOBAL_ATOM_TABLE: RwLock<Weak<AtomTable>> = RwLock::new(Weak::new());
&GLOBAL_ATOM_TABLE
}
#[inline(always)]
fn arc_atom_table() -> Option<Arc<AtomTable>> {
global_atom_table().read().unwrap().upgrade()
}
impl RawBlockTraits for AtomTable {
#[inline]
fn init_size() -> usize {
ATOM_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
ATOM_TABLE_ALIGN
}
}
#[bitfield]
#[derive(Copy, Clone, Debug)]
struct AtomHeader {
#[allow(unused)]
m: bool,
len: B50,
#[allow(unused)]
padding: B13,
}
#[repr(C)]
pub struct AtomData {
header: AtomHeader,
data: str,
}
impl AtomHeader {
fn build_with(len: u64) -> Self {
AtomHeader::new().with_len(len).with_m(false)
}
}
impl Hash for Atom {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_str().hash(hasher)
}
}
pub enum AtomString<'a> {
Static(&'a str),
Inlined([u8; 8]),
Dynamic(AtomTableRef<str>),
}
#[inline(always)]
fn inlined_to_str(bytes: &[u8; 8]) -> &str {
let slice_len = bytes
.iter()
.position(|&b| b == 0u8)
.unwrap_or(INLINED_ATOM_MAX_LEN);
unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) }
}
impl std::fmt::Debug for AtomString<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(self.deref(), f)
}
}
impl std::fmt::Display for AtomString<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.deref(), f)
}
}
impl std::ops::Deref for AtomString<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
match self {
Self::Static(reference) => reference,
Self::Inlined(inlined) => inlined_to_str(inlined),
Self::Dynamic(guard) => guard.deref(),
}
}
}
#[cfg(feature = "repl")]
impl rustyline::completion::Candidate for AtomString<'_> {
fn display(&self) -> &str {
self.deref()
}
fn replacement(&self) -> &str {
self.deref()
}
}
impl Atom {
#[inline]
fn new_inlined(string: &str) -> Self {
AtomCell::new_inlined(string, 0).get_name()
}
#[inline(always)]
fn is_static(self) -> bool {
if self.is_inlined() {
true
} else {
(self.flat_index() as usize) < STRINGS.len()
}
}
#[inline]
pub(crate) fn flat_index(self) -> u64 {
self.index >> 1
}
#[inline(always)]
pub(crate) fn is_inlined(self) -> bool {
self.index & 1 == 1
}
#[inline(always)]
fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
if self.is_static() {
None
} else {
let atom_table =
arc_atom_table().expect("We should only have an Atom while there is an AtomTable");
AtomTableRef::try_map(atom_table.inner.read(), |buf| unsafe {
let ptr = buf
.block
.base
.add(self.flat_index() as usize - STRINGS.len());
// TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513
let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
let len = atom_data.header.len();
Some(&*(std::ptr::slice_from_raw_parts(ptr, len as usize) as *const AtomData))
})
}
}
#[inline(always)]
pub fn from(index: u64) -> Self {
Self { index }
}
#[inline(always)]
pub fn len(self) -> usize {
if let Some(s) = self.inlined_str() {
s.len()
} else if self.is_static() {
let index = self.flat_index();
STRINGS[index as usize].len()
} else {
let len: u64 = self.as_ptr().unwrap().header.len();
len as usize
}
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
pub fn as_char(self) -> Option<char> {
let s = self.as_str();
let mut it = s.chars();
let c1 = it.next();
let c2 = it.next();
if c2.is_none() {
c1
} else {
None
}
}
#[inline]
fn inlined_str<'a>(&self) -> Option<AtomString<'a>> {
if self.is_inlined() {
Some(AtomString::Inlined(self.flat_index().to_le_bytes()))
} else {
None
}
}
#[inline]
pub fn as_str(&self) -> AtomString<'static> {
if let Some(s) = self.inlined_str() {
s
} else if self.is_static() {
let index = self.flat_index() as usize;
AtomString::Static(STRINGS[index])
} else if let Some(ptr) = self.as_ptr() {
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
} else {
AtomString::Static(STRINGS[(self.index >> 1) as usize])
}
}
pub fn defrock_brackets(&self, atom_tbl: &AtomTable) -> Self {
let s = self.as_str();
let sub_str = if s.starts_with('(') && s.ends_with(')') {
&s['('.len_utf8()..s.len() - ')'.len_utf8()]
} else {
return *self;
};
AtomTable::build_with(atom_tbl, sub_str)
}
}
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
let str_ptr = ptr.add(mem::size_of::<AtomHeader>());
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr, string.len());
}
impl PartialOrd for Atom {
#[inline]
fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Atom {
#[inline]
fn cmp(&self, other: &Atom) -> Ordering {
self.as_str().cmp(&*other.as_str())
}
}
#[derive(Debug)]
pub struct InnerAtomTable {
block: RawBlock<AtomTable>,
pub table: Arcu<IndexSet<Atom>, GlobalEpochCounterPool>,
}
#[derive(Debug)]
pub struct AtomTable {
inner: Arcu<InnerAtomTable, GlobalEpochCounterPool>,
// this lock is taking during resizing
update: Mutex<()>,
}
pub type AtomTableRef<M> = arcu::rcu_ref::RcuRef<InnerAtomTable, M>;
impl InnerAtomTable {
#[inline(always)]
fn lookup_str(self: &InnerAtomTable, string: &str) -> Option<Atom> {
STATIC_ATOMS_MAP
.get(string)
.cloned()
.or_else(|| self.table.read().get(string).cloned())
}
}
impl AtomTable {
#[inline]
pub fn new() -> Arc<Self> {
let upgraded = global_atom_table().read().unwrap().upgrade();
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
if let Some(atom_table) = upgraded {
atom_table
} else {
let mut guard = global_atom_table().write().unwrap();
// try to upgrade again in case we lost the race on the write lock
if let Some(atom_table) = guard.upgrade() {
atom_table
} else {
let atom_table = Arc::new(Self {
inner: Arcu::new(
InnerAtomTable {
block: RawBlock::new(),
table: Arcu::new(IndexSet::new(), GlobalEpochCounterPool),
},
GlobalEpochCounterPool,
),
update: Mutex::new(()),
});
*guard = Arc::downgrade(&atom_table);
atom_table
}
}
}
pub fn active_table(&self) -> RcuRef<IndexSet<Atom>, IndexSet<Atom>> {
self.inner.read().table.read()
}
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
return Atom::new_inlined(string);
}
loop {
let mut block_epoch = atom_table.inner.read();
let mut table_epoch = block_epoch.table.read();
if let Some(atom) = block_epoch.lookup_str(string) {
return atom;
}
// take a lock to prevent concurrent updates
let update_guard = atom_table.update.lock().unwrap();
let is_same_allocation = RcuRef::same_epoch(&block_epoch, &atom_table.inner.read());
let is_same_atom_list = RcuRef::same_epoch(&table_epoch, &block_epoch.table.read());
if !(is_same_allocation && is_same_atom_list) {
// some other thread raced us between our lookup and
// us aquring the update lock,
// try again
continue;
}
let size = mem::size_of::<AtomHeader>() + string.len();
let size = size.next_multiple_of(AtomTable::align());
unsafe {
let len_ptr = loop {
let ptr = block_epoch.block.alloc(size);
if ptr.is_null() {
// garbage collection would go here
let new_block = block_epoch.block.grow_new().unwrap();
let new_table = Arcu::new(table_epoch.clone(), GlobalEpochCounterPool);
let new_alloc = InnerAtomTable {
block: new_block,
table: new_table,
};
atom_table.inner.replace(new_alloc);
block_epoch = atom_table.inner.read();
table_epoch = block_epoch.table.read();
} else {
break ptr;
}
};
let ptr_base = block_epoch.block.base.addr();
write_to_ptr(string, len_ptr);
let atom = AtomCell::new()
.with_name((STRINGS.len() + len_ptr.addr() - ptr_base) as u64)
.with_arity(0)
.with_f(false)
.with_m(false)
.with_is_inlined(false)
.with_tag(HeapCellValueTag::Atom as u8)
.get_name();
let mut table = table_epoch.clone();
table.insert(atom);
block_epoch.table.replace(table);
// expicit drop to ensure we don't accidentally drop it early
drop(update_guard);
return atom;
}
}
}
}
unsafe impl Send for AtomTable {}
unsafe impl Sync for AtomTable {}

7
src/bin/scryer-prolog.rs Normal file
View File

@@ -0,0 +1,7 @@
fn main() -> std::process::ExitCode {
#[cfg(target_arch = "wasm32")]
return std::process::ExitCode::SUCCESS;
#[cfg(not(target_arch = "wasm32"))]
return scryer_prolog::run_binary();
}

1316
src/codegen.rs Normal file

File diff suppressed because it is too large Load Diff

915
src/debray_allocator.rs Normal file
View File

@@ -0,0 +1,915 @@
use crate::allocator::*;
use crate::codegen::SubsumedBranchHits;
use crate::forms::{GenContext, Level};
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
use crate::parser::ast::*;
use crate::targets::*;
use crate::variable_records::*;
use bit_set::*;
use bitvec::prelude::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use std::cell::Cell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
pub type BranchHits = IndexMap<usize, BitVec, FxBuildHasher>; // key: var_num, value: branch arm occurrences.
#[derive(Debug, Default)]
pub struct BranchOccurrences {
pub hits: BranchHits,
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
pub deep_safety: BitSet<usize>,
pub num_branches: usize,
pub current_branch: usize,
pub subsumed_hits: SubsumedBranchHits,
}
impl BranchOccurrences {
fn new(num_branches: usize) -> Self {
Self {
hits: BranchHits::with_hasher(FxBuildHasher::default()),
shallow_safety: BitSet::default(),
deep_safety: BitSet::default(),
num_branches,
current_branch: 0,
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
}
}
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
debug_assert!(self.current_branch < self.num_branches);
let num_branches = self.num_branches;
let entry = self
.hits
.entry(var_num)
.or_insert_with(|| BitVec::repeat(false, num_branches));
entry.set(self.current_branch, true);
self.subsumed_hits.insert(var_num);
}
}
#[derive(Debug)]
pub(crate) struct BranchStack {
stack: Vec<BranchOccurrences>,
}
impl Deref for BranchStack {
type Target = Vec<BranchOccurrences>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.stack
}
}
impl DerefMut for BranchStack {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stack
}
}
impl BranchStack {
fn branch_subsumes(&self, branch: &BranchDesignator, sub_branch: &BranchDesignator) -> bool {
if branch.branch_stack_num < sub_branch.branch_stack_num {
if branch.branch_stack_num == 0 {
true
} else {
let idx = branch.branch_stack_num - 1;
self[idx].current_branch == branch.branch_num
}
} else {
branch == sub_branch
}
}
fn safety_unneeded_in_branch(
&self,
safety: &VarSafetyStatus,
branch: &BranchDesignator,
) -> bool {
match safety {
VarSafetyStatus::Needed => false,
VarSafetyStatus::LocallyUnneeded(planter_branch) => {
self.branch_subsumes(planter_branch, branch)
}
VarSafetyStatus::GloballyUnneeded => true,
}
}
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
if let Some(occurrences) = self.last_mut() {
occurrences.add_branch_occurrence(var_num);
}
}
pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
self.push(BranchOccurrences::new(num_branches));
}
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
let branch_stack_num = self.len();
let branch_num = self
.last()
.map(|occurrences| occurrences.current_branch)
.unwrap_or(0);
BranchDesignator {
branch_stack_num,
branch_num,
}
}
#[inline]
pub(crate) fn incr_current_branch(&mut self) {
let branch_occurrences = self.last_mut().unwrap();
branch_occurrences.current_branch += 1;
}
#[inline]
pub(crate) fn drain_branches(
&mut self,
depth: usize,
) -> std::vec::Drain<'_, BranchOccurrences> {
let start_idx = self.len() - depth;
self.drain(start_idx..)
}
}
#[derive(Debug)]
pub(crate) struct DebrayAllocator {
pub(crate) var_data: VarData, // var_data replaces bindings.
pub(crate) branch_stack: BranchStack,
pub(crate) in_tail_position: bool,
arg_c: usize,
temp_lb: usize,
perm_lb: usize,
arity: usize, // 0 if not at head.
shallow_temp_mappings: IndexMap<usize, usize, FxBuildHasher>,
in_use: BitSet<usize>, // deep and non-var allocations
temp_free_list: Vec<usize>,
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
}
impl DebrayAllocator {
pub(crate) fn add_branch(&mut self) {
let branch_designator = self.branch_stack.current_branch_designator();
let subsumed_hits = {
let branch_occurrences = self.branch_stack.last_mut().unwrap();
std::mem::replace(
&mut branch_occurrences.subsumed_hits,
SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
)
};
for var_num in subsumed_hits {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, ref mut allocation) => {
if let PermVarAllocation::Done {
shallow_safety,
deep_safety,
..
} = allocation
{
if !self
.branch_stack
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
{
let branch_occurrences = self.branch_stack.last_mut().unwrap();
branch_occurrences.shallow_safety.insert(var_num);
}
if !self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
{
let branch_occurrences = self.branch_stack.last_mut().unwrap();
branch_occurrences.deep_safety.insert(var_num);
}
}
*allocation = PermVarAllocation::Pending;
}
_ => unreachable!(),
}
}
}
pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) {
let removed_branches = self.branch_stack.drain_branches(depth);
let (deep_safety, shallow_safety) = removed_branches.into_iter().fold(
(BitSet::default(), BitSet::default()),
|(mut deep_safety, mut shallow_safety), branch_occurrences| {
deep_safety.union_with(&branch_occurrences.deep_safety);
shallow_safety.union_with(&branch_occurrences.shallow_safety);
(deep_safety, shallow_safety)
},
);
let branch_designator = self.branch_stack.current_branch_designator();
let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() {
Some(latest_branch) => {
latest_branch.deep_safety.union_with(&deep_safety);
latest_branch.shallow_safety.union_with(&shallow_safety);
(&latest_branch.deep_safety, &latest_branch.shallow_safety)
}
None => (&deep_safety, &shallow_safety),
};
for var_num in subsumed_hits.iter().cloned() {
let running_count = self.var_data.records[var_num].running_count;
let num_occurrences = self.var_data.records[var_num].num_occurrences;
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, allocation) => {
let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num),
branch_designator,
);
let deep_safety = VarSafetyStatus::needed_if(
deep_safety.contains(var_num),
branch_designator,
);
if running_count < num_occurrences {
*allocation = PermVarAllocation::Done {
shallow_safety,
deep_safety,
};
}
}
_ => unreachable!(),
}
}
if !self.branch_stack.is_empty() {
for var_num in subsumed_hits {
self.branch_stack.add_branch_occurrence(var_num);
}
}
}
fn is_curr_arg_distinct_from(&self, var_num: usize) -> bool {
match self.shallow_temp_mappings.get(&self.arg_c).cloned() {
Some(t_var) => t_var != var_num,
_ => false,
}
}
fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool {
match &self.var_data.records[var_num].allocation {
VarAlloc::Temp {
temp_var_data,
term_loc: GenContext::Head,
..
} => temp_var_data.use_set.contains(&(GenContext::Head, r)),
_ => false,
}
}
#[inline]
fn is_in_use(&self, r: usize) -> bool {
let in_use_range = r <= self.arity && r >= self.arg_c;
in_use_range || self.in_use.contains(r)
}
fn alloc_with_cr(&self, var_num: usize) -> usize {
match &self.var_data.records[var_num].allocation {
VarAlloc::Temp { temp_var_data, .. } => {
for &(_, reg) in temp_var_data.use_set.iter() {
if !self.is_in_use(reg) {
return reg;
}
}
let mut result = 0;
for reg in self.temp_lb.. {
if !self.is_in_use(reg) && !temp_var_data.no_use_set.contains(reg) {
result = reg;
break;
}
}
result
}
_ => 0,
}
}
fn alloc_with_ca(&self, var_num: usize) -> usize {
match &self.var_data.records[var_num].allocation {
VarAlloc::Temp { temp_var_data, .. } => {
for &(_, reg) in temp_var_data.use_set.iter() {
if !self.is_in_use(reg) {
return reg;
}
}
let mut result = 0;
for reg in self.temp_lb.. {
if !self.is_in_use(reg)
&& !temp_var_data.no_use_set.contains(reg)
&& !temp_var_data.conflict_set.contains(reg)
{
result = reg;
break;
}
}
result
}
_ => 0,
}
}
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(usize, usize)> {
// we want to allocate a register to the k^{th} parameter, par_k.
// par_k may not be a temporary variable.
let k = self.arg_c;
match self.shallow_temp_mappings.get(&k).cloned() {
Some(t_var) => {
// suppose this branch fires. then t_var is a
// temp. var. belonging to the current chunk.
// consider its use set. T == par_k iff
// (GenContext::Last(_), k) is in t_var.use_set.
if let VarAlloc::Temp { temp_var_data, .. } =
&self.var_data.records[t_var].allocation
{
if !temp_var_data
.use_set
.contains(&(GenContext::Last(chunk_num), k))
{
return Some((t_var, self.alloc_with_ca(t_var)));
}
}
None
}
_ => None,
}
}
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
&mut self,
chunk_num: usize,
code: &mut CodeDeque,
) {
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
let k = self.arg_c;
if r != k {
let r = RegType::Temp(r);
code.push_back(Target::move_to_register(r, k));
self.shallow_temp_mappings.swap_remove(&k);
self.shallow_temp_mappings.insert(r.reg_num(), var_num);
self.var_data.records[var_num]
.allocation
.set_register(r.reg_num());
self.in_use.insert(r.reg_num());
}
};
}
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
term_loc: GenContext,
target: &mut CodeDeque,
) -> usize {
match term_loc {
GenContext::Head => {
if let Level::Shallow = lvl {
self.evacuate_arg::<Target>(0, target);
self.alloc_with_cr(var_num)
} else {
self.alloc_with_ca(var_num)
}
}
GenContext::Mid(_) => self.alloc_with_ca(var_num),
GenContext::Last(chunk_num) => {
if let Level::Shallow = lvl {
self.evacuate_arg::<Target>(chunk_num, target);
self.alloc_with_cr(var_num)
} else {
self.alloc_with_ca(var_num)
}
}
}
}
fn alloc_reg_to_non_var(&mut self) -> usize {
let mut final_index = 0;
while let Some(r) = self.temp_free_list.pop() {
if !self.is_in_use(r) {
self.in_use.insert(r);
return r;
}
}
for index in self.temp_lb.. {
if !self.in_use.contains(index) {
final_index = index;
self.in_use.insert(final_index);
break;
}
}
self.temp_lb = final_index + 1;
final_index
}
fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool {
match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match &self.var_data.records[var_num].allocation {
&VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k => temp_reg == k,
_ => false,
},
}
}
fn alloc_perm_var(&mut self, var_num: usize, chunk_num: usize) -> usize {
let p = if let Some(p) = self.pop_free_perm(chunk_num) {
p
} else {
let p = self.perm_lb;
self.perm_lb += 1;
p
};
self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
p
}
pub(crate) fn add_reg_to_free_list(&mut self, r: RegType) {
if let RegType::Temp(r) = r {
self.in_use.remove(r);
self.temp_free_list.push(r);
}
}
pub fn reset_free_list(&mut self) {
self.temp_free_list.clear();
}
#[inline(always)]
pub fn get_binding(&self, var_num: usize) -> RegType {
self.var_data.records[var_num].allocation.as_reg_type()
}
pub fn num_perm_vars(&self) -> usize {
self.perm_lb - 1
}
pub fn increment_running_count(&mut self, var_num: usize) {
self.var_data.records[var_num].running_count += 1;
}
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation {
self.perm_free_list.push_back((chunk_num, var_num));
}
}
fn pop_free_perm(&mut self, chunk_num: usize) -> Option<usize> {
while let Some((perm_chunk_num, var_num)) = self.perm_free_list.front().cloned() {
if chunk_num > perm_chunk_num {
self.perm_free_list.pop_front();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
return Some(std::mem::replace(p, 0));
}
_ => {}
}
} else {
return None;
}
}
None
}
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
*allocation = PermVarAllocation::Pending;
self.add_perm_to_free_list(chunk_num, var_num);
}
}
pub(crate) fn mark_safe_var_unconditionally(&mut self, var_num: usize) {
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(
_,
PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
) => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
}
VarAlloc::Temp { safety, .. } => {
*safety = VarSafetyStatus::unneeded(branch_designator);
}
_ => {
unreachable!()
}
}
}
fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) {
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(
_,
PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
) => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
} else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
} else if let Some(&temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c) {
match &mut self.var_data.records[temp_var_num].allocation {
VarAlloc::Temp {
ref mut to_perm_var_num,
..
} => {
*to_perm_var_num = Some(var_num);
}
_ => unreachable!(),
}
}
}
VarAlloc::Temp { ref mut safety, .. } => {
*safety = VarSafetyStatus::GloballyUnneeded;
}
_ => {
unreachable!()
}
}
}
fn argument_to_value<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
r: RegType,
arg_c: usize,
) -> Instruction {
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(
_,
PermVarAllocation::Done {
ref mut shallow_safety,
..
},
) => {
if !self.in_tail_position
|| self
.branch_stack
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
{
Target::argument_to_value(r, arg_c)
} else {
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_argument_to_value(r, arg_c)
}
}
VarAlloc::Temp { .. } => {
debug_assert!(matches!(r, RegType::Temp(_)));
Target::argument_to_value(r, arg_c)
}
_ => {
unreachable!()
}
}
}
fn subterm_to_value<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
r: RegType,
) -> Instruction {
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(
_,
PermVarAllocation::Done {
ref mut deep_safety,
..
},
) => {
if self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
{
Target::subterm_to_value(r)
} else {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_subterm_to_value(r)
}
}
VarAlloc::Temp { ref mut safety, .. } => {
if self
.branch_stack
.safety_unneeded_in_branch(safety, &branch_designator)
{
Target::subterm_to_value(r)
} else {
*safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_subterm_to_value(r)
}
}
_ => {
unreachable!()
}
}
}
}
impl Allocator for DebrayAllocator {
fn new() -> DebrayAllocator {
Self {
var_data: VarData::default(),
in_tail_position: false,
arity: 0,
arg_c: 1,
temp_lb: 1,
perm_lb: 1,
shallow_temp_mappings: IndexMap::with_hasher(FxBuildHasher::default()),
in_use: BitSet::default(),
temp_free_list: vec![],
perm_free_list: VecDeque::new(),
branch_stack: BranchStack { stack: vec![] },
}
}
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
term_loc: GenContext,
code: &mut CodeDeque,
) -> RegType {
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
Level::Deep => code.push_back(Target::subterm_to_variable(r)),
Level::Root | Level::Shallow => {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
code.push_back(Target::argument_to_variable(r, k));
}
};
r
}
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
term_loc: GenContext,
cell: &'a Cell<RegType>,
code: &mut CodeDeque,
) {
let r = cell.get();
let r = match lvl {
Level::Shallow => {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
RegType::Temp(k)
}
_ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
_ => {
self.in_use.insert(r.reg_num());
r
}
};
cell.set(r);
}
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque,
) {
let (r, is_new_var) = match self.get_binding(var_num) {
RegType::Temp(0) => {
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true)
}
RegType::Perm(0) => {
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
cell.set(VarReg::Norm(RegType::Perm(p)));
(RegType::Perm(p), true)
}
r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, allocation) => {
if allocation.pending() {
*allocation = PermVarAllocation::done();
true
} else {
false
}
}
_ => unreachable!(),
};
(r, is_new_var)
}
r => (r, false),
};
self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
}
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
) {
match lvl {
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(var_num) {
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
}
cell.set(VarReg::ArgAndNorm(r, k));
if !self.in_place(var_num, term_loc, r, k) {
if is_new_var {
self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::argument_to_variable(r, k));
} else {
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
}
}
self.arg_c += 1;
}
Level::Deep if is_new_var => {
if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
code.push_back(self.subterm_to_value::<Target>(var_num, r));
} else {
self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
}
} else {
self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
}
}
Level::Deep => code.push_back(self.subterm_to_value::<Target>(var_num, r)),
}
let o = r.reg_num();
if !r.is_perm() {
self.shallow_temp_mappings.insert(o, var_num);
} else if r.is_perm() && is_new_var {
self.branch_stack.add_branch_occurrence(var_num);
}
let record = &mut self.var_data.records[var_num];
record.allocation.set_register(o);
if record.running_count < record.num_occurrences {
record.running_count += 1;
} else {
self.free_var(term_loc.chunk_num(), var_num);
}
self.in_use.insert(o);
}
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
match self.get_binding(var_num) {
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
RegType::Temp(0) => {
let t = self.alloc_reg_to_non_var();
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Temp {
temp_reg, safety, ..
} => {
*temp_reg = t;
*safety = VarSafetyStatus::GloballyUnneeded;
}
_ => unreachable!(),
};
RegType::Temp(t)
}
r => r,
}
}
fn reset(&mut self) {
self.perm_lb = 1;
self.shallow_temp_mappings.clear();
self.in_use.clear();
self.temp_free_list.clear();
}
fn reset_contents(&mut self) {
self.in_use.clear();
self.shallow_temp_mappings.clear();
self.temp_free_list.clear();
}
fn advance_arg(&mut self) {
self.arg_c += 1;
}
fn reset_at_head(&mut self, args: &[Term]) {
self.reset_arg(args.len());
self.arity = args.len();
for (idx, arg) in args.iter().enumerate() {
if let Term::Var(_, ref var) = arg {
let var_num = var.to_var_num().unwrap();
let r = self.get_binding(var_num);
if !r.is_perm() && r.reg_num() == 0 {
self.in_use.insert(idx + 1);
self.shallow_temp_mappings.insert(idx + 1, var_num);
self.var_data.records[var_num]
.allocation
.set_register(idx + 1);
}
}
}
}
fn reset_arg(&mut self, arity: usize) {
self.arity = 0;
self.arg_c = 1;
self.temp_lb = arity + 1;
}
#[inline(always)]
fn max_reg_allocated(&self) -> usize {
std::cmp::max(self.temp_lb, self.arg_c)
}
}

View File

@@ -0,0 +1,219 @@
### BiMetaTrans 1.0
BiMetaTrans(Prolog, RuleML) is a bidirectional translator capable of
parsing and generating a well-formed sublanguage of RuleML/XML to/from
a metalogical encoding of our own design called Prolog/'$V'. For later
ease of reference:
* Prolog/'$V' stands for "Metalogic Prolog with variable-as-'$V'-term encoding"
* RuleML/XML stands for "RuleML in XML with any kind of rendering"
* RuleML/xmL stands for "RuleML in minified XML"
* RuleML/Xml stands for "RuleML in indented XML"
"Minified XML" refers to XML with only necessary whitespace, between
element names and attributes, and pairs of attributes, with all
indentation stripped out. "Indented XML" contains indentation and
newlines, and is usually formatted for human readers.
The specification of Prolog/'$V', and of the NafHornlogEq sublanguage
of RuleML/XML targeted by BiMetaTrans, is contained in the preprint
[Invertible Bidirectional Metalogical Translation Between Prolog and
RuleML/XML for Knowledge Representation and
Querying](http://ruleml.org/papers/RuleMLXMLBiDirTransScryer.pdf) and
its accompanying talk
[slides](http://ruleml.org/talks/RuleMLXMLBiDirTransScryer-talk.pdf). The
preprint and talk also describe the implementation of BiMetaTrans
found here, and outlines a strategy for proving the invertibility of
BiMetaTrans.
BiMetaTrans exports a single public predicate subsuming its user
API, `parse_ruleml/3`. It has two modes, each corresponding to a single
direction of translation:
```
parse_ruleml(+AssertItems, +QueryItems, ?XML) (Prolog->RuleML)
parse_ruleml(?AssertItems, ?QueryItems, +XML) (RuleML->Prolog)
```
The modes constrain the inputs to fit one of two patterns, the
first where AssertItems and QueryItems are instantiated and XML is
possibly a variable, and conversely for the second. Instantiated
inputs are expected to be ground, meaning they should not contain
free variables.
We explore several examples of its use in Scryer Prolog.
Loading BiMetaTrans from the Scryer REPL:
```
?- use_module('src/examples/bimetatrans/bimetatrans').
```
Using `write/1` to print the string to standard output, capturing the
`Prolog->RuleML` direction (`write/1` is used because it does not
print strings with escape characters, ie., `\"` for double quote):
```
?- parse_ruleml([people('Alex',male),people('Alex',female),people('Siri',female)], [], XML),
write(XML).
"<Assert mapClosure="universal"><Atom><Rel>people</Rel><Ind>Alex</Ind><Data iso:type="symbol">male</Data></Atom><Atom><Rel>people</Rel><Ind>Alex</Ind><Data iso:type="symbol">female</Data></Atom><Atom><Rel>people</Rel><Ind>Siri</Ind><Data iso:type="symbol">female</Data></Atom></Assert>" XML = "<Assert mapClosure= ...".
```
Note that the XML input can contain extraneous whitespace and
indentation while generated XML never does (ie., the XML generated by
BiMetaTrans is always Ruleml/xmL). `\` is used to continue ISO Prolog
strings to the next line but is never stored to the string by the
Prolog reader.
Performing the inverse translation of the previous example
(`RuleML->Prolog`), in RuleML/Xml:
```
?- parse_ruleml(AssertItems, QueryItems,
"<Assert mapClosure=\"universal\">\
<Atom>\
<Rel>people</Rel>\
<Ind>Alex</Ind>\
<Data iso:type=\"symbol\">male</Data>\
</Atom>\
<Atom>\
<Rel>people</Rel>\
<Ind>Alex</Ind>\
<Data iso:type=\"symbol\">female</Data>\
</Atom>\
<Atom>\
<Rel>people</Rel>\
<Ind>Siri</Ind>\
<Data iso:type=\"symbol\">female</Data>\
</Atom>\
</Assert>").
AssertItems = [people('Alex',male),people('Alex',female),people('Siri',female)], QueryItems = [].
```
Double quote characters within strings must be escaped as in
`\"`. Non-empty AssertItems and QueryItems lists generated to
RuleML/xmL simultaneously:
```
?- parse_ruleml([a(item), b(item), c(item)], [(?- p, q, r(1), s(-2.222342432), t("attached")), (?- u, v('$V'(q)))], XML),
write(XML).
"<Assert mapClosure="universal"><Atom><Rel>a</Rel><Data iso:type="symbol">item</Data></Atom><Atom><Rel>b</Rel><Data iso:type="symbol">item</Data></Atom><Atom><Rel>c</Rel><Data iso:type="symbol">item</Data></Atom></Assert><Query closure="existential"><And><Atom><Rel>p</Rel></Atom><Atom><Rel>q</Rel></Atom><Atom><Rel>r</Rel><Data iso:type="number">1</Data></Atom><Atom><Rel>s</Rel><Data iso:type="number">-2.222342432</Data></Atom><Atom><Rel>t</Rel><Data iso:type="string">"attached"</Data></Atom></And></Query><Query closure="existential"><And><Atom><Rel>u</Rel></Atom><Atom><Rel>v</Rel><Var>q</Var></Atom></And></Query>" XML = "<Assert mapClosure= ...".
```
To insert escape characters into the printed RuleML/xmL, we use
`writeq/1` in place of `write/1`:
```
?- parse_ruleml([a(item), b(item), c(item)], [(?- p, q, r(1), s(-2.222342432), t("attached")), (?- u, v('$V'(q)))], XML),
writeq(XML).
"<Assert mapClosure=\"universal\"><Atom><Rel>a</Rel><Data iso:type=\"symbol\">item</Data></Atom><Atom><Rel>b</Rel><Data iso:type=\"symbol\">item</Data></Atom><Atom><Rel>c</Rel><Data iso:type=\"symbol\">item</Data></Atom></Assert><Query closure=\"existential\"><And><Atom><Rel>p</Rel></Atom><Atom><Rel>q</Rel></Atom><Atom><Rel>r</Rel><Data iso:type=\"number\">1</Data></Atom><Atom><Rel>s</Rel><Data iso:type=\"number\">-2.222342432</Data></Atom><Atom><Rel>t</Rel><Data iso:type=\"string\">\"attached\"</Data></Atom></And></Query><Query closure=\"existential\"><And><Atom><Rel>u</Rel></Atom><Atom><Rel>v</Rel><Var>q</Var></Atom></And></Query>" XML = "<Assert mapClosure= ...".
```
XML can be pretty printed using a [free online XML pretty
printer](https://codebeautify.org/xmlviewer), as here:
```
<Assert mapClosure=\"universal\">
<Atom>
<Rel>a</Rel>
<Data iso:type=\"symbol\">item</Data>
</Atom>
<Atom>
<Rel>b</Rel>
<Data iso:type=\"symbol\">item</Data>
</Atom>
<Atom>
<Rel>c</Rel>
<Data iso:type=\"symbol\">item</Data>
</Atom>
</Assert>
<Query closure=\"existential\">
<And>
<Atom>
<Rel>p</Rel>
</Atom>
<Atom>
<Rel>q</Rel>
</Atom>
<Atom>
<Rel>r</Rel>
<Data iso:type=\"number\">1</Data>
</Atom>
<Atom>
<Rel>s</Rel>
<Data iso:type=\"number\">-2.222342432</Data>
</Atom>
<Atom>
<Rel>t</Rel>
<Data iso:type=\"string\">\"attached\"</Data>
</Atom>
</And>
</Query>
<Query closure=\"existential\">
<And>
<Atom>
<Rel>u</Rel>
</Atom>
<Atom>
<Rel>v</Rel>
<Var>q</Var>
</Atom>
</And>
</Query>
```
The AssertItems and QueryItems lists can then be recovered using this
RuleML/Xml string, with the `\` character added to the end of each
line:
```
?- parse_ruleml(AssertItems, QueryItems,
"<Assert mapClosure=\"universal\">\
<Atom>\
<Rel>a</Rel>\
<Data iso:type=\"symbol\">item</Data>\
</Atom>\
<Atom>\
<Rel>b</Rel>\
<Data iso:type=\"symbol\">item</Data>\
</Atom>\
<Atom>\
<Rel>c</Rel>\
<Data iso:type=\"symbol\">item</Data>\
</Atom>\
</Assert>\
<Query closure=\"existential\">\
<And>\
<Atom>\
<Rel>p</Rel>\
</Atom>\
<Atom>\
<Rel>q</Rel>\
</Atom>\
<Atom>\
<Rel>r</Rel>\
<Data iso:type=\"number\">1</Data>\
</Atom>\
<Atom>\
<Rel>s</Rel>\
<Data iso:type=\"number\">-2.222342432</Data>\
</Atom>\
<Atom>\
<Rel>t</Rel>\
<Data iso:type=\"string\">\"attached\"</Data>\
</Atom>\
</And>\
</Query>\
<Query closure=\"existential\">\
<And>\
<Atom>\
<Rel>u</Rel>\
</Atom>\
<Atom>\
<Rel>v</Rel>\
<Var>q</Var>\
</Atom>\
</And>\
</Query>").
AssertItems = [a(item),b(item),c(item)], QueryItems = [(?-p,q,r(1),s(-2.222342432),t("attached")),(?-u,v('$V'(q)))].
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,6 @@ verify_attributes(Var, Other, Goals) :-
( Els = [] -> % exactly one element ( Els = [] -> % exactly one element
Goals = [Other=El] % implied binding Goals = [Other=El] % implied binding
; Goals = [], ; Goals = [],
put_atts(Other, -dom(_)),
put_atts(Other, dom(Dc))% rescue intersection put_atts(Other, dom(Dc))% rescue intersection
) )
; Goals = [], ; Goals = [],

View File

@@ -0,0 +1,31 @@
:- module(echo_server, [echo_server/0,
echo_server/1]).
:- use_module(library(format)).
:- use_module(library(sockets)).
echo_server :-
echo_server('127.0.0.1').
echo_server(Addr) :-
socket_server_open(Addr:Port, ServerSocket),
format("echo_server: connection opened at ~w:~d~n", [Addr, Port]),
socket_server_accept(ServerSocket, Client, Stream, [eof_action(eof_code)]),
format("echo_server: connection accepted from ~a~n", [Client]),
!,
echo_loop(Stream),
socket_server_close(ServerSocket).
echo_loop(Stream) :-
read_term(Stream, Term, []),
( Term == end_of_file ->
true
;
format("received: ~w~n", [Term]),
!,
echo_loop(Stream)
).

View File

@@ -0,0 +1,51 @@
/* least_time.pl
*
* By Mark Thom, 2020
*
* find_min_time/2 solves a problem sometimes posed in the first round
* of Google interviews: given a time of day in 24 H format, what is the
* lexicographically least permutation of the time that is itself a
* valid time in 24 H format?
*
* Full generality is achieved using the reif library.
*/
:- module(least_time, [find_min_time/2,
write_time_nl/1]).
:- use_module(library(dcgs)).
:- use_module(library(format)).
:- use_module(library(lists)).
:- use_module(library(reif)).
valid_time([H1,H2,M1,M2], T) :-
memberd_t(H1, [0,1,2], TH1),
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
memberd_t(M1, [0,1,2,3,4,5], TM1),
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
( H1 =:= 2 ->
( H2 =< 3 ->
T = true
; T = false
)
; T = true
)
; T = false
).
permuted_times(Time, PermutedTimes) :-
setof(P, permutation(Time, P), PermutedTimes0),
tfilter(valid_time, PermutedTimes0, PermutedTimes).
find_min_time(Time, Min) :-
valid_time(Time, true),
permuted_times(Time, [Min|_]).
write_time_nl(Time) :-
format("\"~w~w:~w~w\"~n", Time).

View File

@@ -31,6 +31,7 @@
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(dif)). :- use_module(library(dif)).
:- use_module(library(format)).
:- use_module(library(lists)). :- use_module(library(lists)).
pl_resolution(Clauses0, Chain) :- pl_resolution(Clauses0, Chain) :-

31
src/examples/utf8.pl Normal file
View File

@@ -0,0 +1,31 @@
:- use_module(library(charsio)).
:- use_module(library(lists)).
:- initialization(unit_test).
unit_test :-
chars_utf8bytes("a£\x2124\", Bs),
Bs = [97, 194, 163, 226, 132, 164],
chars_utf8bytes(Cs, Bs),
Cs = "a£\x2124\".
write_f :-
open('x.txt', write, Stream, [type(binary)]),
F = put_byte(Stream),
chars_utf8bytes("£\x2124\\x2764\\x1F496\\n", Bs),
maplist(F, Bs),
close(Stream).
get_bytes(Stream, Res) :- get_bytes(Stream, [], Res).
get_bytes(Stream, Acc, Res) :-
get_byte(Stream, B),
(B =:= -1 ->
reverse(Acc, Res)
; get_bytes(Stream, [B|Acc], Res)).
read_f :-
open('x.txt', read, Stream, [type(binary)]),
get_bytes(Stream, Bs),
chars_utf8bytes(Cs, Bs),
write(Cs),
close(Stream).

936
src/ffi.rs Normal file
View File

@@ -0,0 +1,936 @@
/* How does FFI work?
Each WAM machine has a ForeignFunctionTable instance that contains a table of functions and structs.
Structs are defined via foreign_struct/2. Basic types are defined by libffi, but struct types need to
be manually defined to get an ffi_type. Additionally, to recover structs from return arguments, we store
fields and atom_fields, as a way to lookup the content of the struct (fields) and the nested structs (atom_fields).
Functions are defined via use_foreign_module/2. It opens a library and leaks the memory of the library,
to prevent Rust freeing the memory. There's no way to recover that memory at the moment. We get a pointer for
each function and we build a CIF for each one, with the input arguments and the return argument.
Exec happens via '$foreign_call', we find the function, we try to cast the values that we have to the definition
of the function, we reserve memory for them and we build an array of pointers. To get the return argument, we
reserve enough memory for the return and we build the Scryer values from them.
Structs are a bit tricky as they need to be aligned. For that, we reserve enough memory (libffi calculates that)
and for each field: we add to the pointer until we're aligned to the next data type we're going to write, we write it,
and finally we add the pointer the size of what we've written.
*/
use crate::arena::Arena;
use crate::atom_table::Atom;
use crate::forms::Number;
use crate::machine::machine_errors::DomainErrorType;
use crate::parser::ast::{Fixnum, MightNotFitInFixnum};
use dashu::Integer;
use libffi::middle::{Arg, Cif, CodePtr, Type};
use libloading::{Library, Symbol};
use ordered_float::OrderedFloat;
use std::alloc::{self, Layout};
use std::collections::HashMap;
use std::error::Error;
use std::ffi::{c_char, c_void, CStr, CString};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::ptr::NonNull;
pub struct FunctionDefinition {
pub name: Atom,
pub return_value: Atom,
pub args: Vec<Atom>,
}
#[derive(Debug)]
pub struct FunctionImpl {
cif: Cif,
args: Vec<FfiType>,
code_ptr: CodePtr,
return_type: FfiType,
}
impl FunctionImpl {
unsafe fn call_void(&self, args: &[Arg], _: &mut Arena) -> Result<Value, FfiError> {
self.cif.call::<()>(self.code_ptr, args);
Ok(Value::Number(Number::Fixnum(Fixnum::build_with(0))))
}
unsafe fn call_int<T>(&self, args: &[Arg], arena: &mut Arena) -> Result<Value, FfiError>
where
Integer: From<T>,
T: Copy + TryInto<i64> + MightNotFitInFixnum,
{
let n = self.cif.call::<T>(self.code_ptr, args);
Ok(Value::Number(fixnum!(Number, n, arena)))
}
unsafe fn call_float<T>(&self, args: &[Arg], _: &mut Arena) -> Result<Value, FfiError>
where
T: Into<f64>,
{
let n = self.cif.call::<T>(self.code_ptr, args);
Ok(Value::Number(Number::Float(OrderedFloat(n.into()))))
}
unsafe fn call_ptr(&self, args: &[Arg], arena: &mut Arena) -> Result<Value, FfiError> {
let ptr = unsafe { self.cif.call::<*mut c_void>(self.code_ptr, args) };
Ok(Value::Number(fixnum!(Number, ptr as isize, arena)))
}
unsafe fn call_cstr(&self, args: &[Arg], _: &mut Arena) -> Result<Value, FfiError> {
let ptr = unsafe {
self.cif
.call::<Option<NonNull<c_char>>>(self.code_ptr, args)
};
if let Some(cstr) = ptr {
Ok(Value::CString(
unsafe { CStr::from_ptr(cstr.as_ptr()) }.to_owned(),
))
} else {
Ok(Value::Number(Number::Fixnum(Fixnum::build_with(0))))
}
}
unsafe fn call_struct(
&self,
return_type_name: Atom,
args: &[Arg],
arena: &mut Arena,
structs_table: &HashMap<Atom, StructImpl>,
) -> Result<Value, FfiError> {
let struct_type = structs_table
.get(&return_type_name)
.ok_or(FfiError::StructNotFound(return_type_name))?;
let ffi_type = unsafe { *struct_type.ffi_type.as_raw_ptr() };
let layout = Layout::from_size_align(ffi_type.size, ffi_type.alignment.into())
.map_err(|_| FfiError::LayoutError)?;
let alloc = FfiStruct::new(layout, FfiAllocator::Rust)?;
unsafe {
libffi::raw::ffi_call(
self.cif.as_raw_ptr(),
Some(*self.code_ptr.as_safe_fun()),
alloc.ptr.as_ptr(),
args.as_ptr() as *mut *mut c_void,
)
};
let struct_val =
struct_type.read(alloc.ptr.as_ptr(), return_type_name, structs_table, arena);
drop(alloc);
struct_val
}
fn call(
&self,
args: &[Arg],
arena: &mut Arena,
structs_table: &HashMap<Atom, StructImpl>,
) -> Result<Value, FfiError> {
let call_fn: unsafe fn(&Self, &[Arg], &mut Arena) -> Result<Value, FfiError> =
match self.return_type {
FfiType::Void => FunctionImpl::call_void,
FfiType::U8 => FunctionImpl::call_int::<u8>,
FfiType::I8 | FfiType::Bool => FunctionImpl::call_int::<i8>,
FfiType::U16 => FunctionImpl::call_int::<u16>,
FfiType::I16 => FunctionImpl::call_int::<i16>,
FfiType::U32 => FunctionImpl::call_int::<u32>,
FfiType::I32 => FunctionImpl::call_int::<i32>,
FfiType::U64 => FunctionImpl::call_int::<u64>,
FfiType::I64 => FunctionImpl::call_int::<i64>,
FfiType::F32 => FunctionImpl::call_float::<f32>,
FfiType::F64 => FunctionImpl::call_float::<f64>,
FfiType::Ptr => FunctionImpl::call_ptr,
FfiType::CStr => FunctionImpl::call_cstr,
FfiType::Struct(name) => {
return unsafe { self.call_struct(name, args, arena, structs_table) }
}
};
unsafe { call_fn(self, args, arena) }
}
}
#[derive(Debug, Default)]
pub struct ForeignFunctionTable {
table: HashMap<Atom, FunctionImpl>,
structs: HashMap<Atom, StructImpl>,
}
#[derive(Clone, Debug)]
struct StructImpl {
ffi_type: Type,
fields: Vec<FfiType>,
}
impl StructImpl {
fn layout(&self) -> Result<Layout, FfiError> {
let ffi_type = unsafe { *self.ffi_type.as_raw_ptr() };
Layout::from_size_align(ffi_type.size, ffi_type.alignment.into())
.map_err(|_| FfiError::LayoutError)
}
fn build(
&self,
structs_table: &HashMap<Atom, StructImpl>,
struct_args: &mut [Value],
) -> Result<FfiStruct, FfiError> {
let args = ArgValue::build_args(struct_args, &self.fields, structs_table)?;
let alloc = FfiStruct::new(self.layout()?, FfiAllocator::Rust)?;
let Ok(mut current_layout) = Layout::from_size_align(0, 1) else {
return Err(FfiError::LayoutError);
};
unsafe fn write_primitive<T>(
ptr: NonNull<c_void>,
layout: &mut Layout,
val: T,
) -> Result<(), FfiError> {
let (new_layout, offset) = layout
.extend(Layout::new::<T>())
.map_err(|_| FfiError::LayoutError)?;
*layout = new_layout;
ptr.byte_offset(offset as isize).cast::<T>().write(val);
Ok(())
}
for arg in args {
unsafe {
match arg {
ArgValue::U8(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::I8(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::U16(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::I16(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::U32(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::I32(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::U64(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::I64(i) => write_primitive(alloc.ptr, &mut current_layout, i)?,
ArgValue::F32(f) => write_primitive(alloc.ptr, &mut current_layout, f)?,
ArgValue::F64(f) => write_primitive(alloc.ptr, &mut current_layout, f)?,
ArgValue::Ptr(p, _) => write_primitive(alloc.ptr, &mut current_layout, p)?,
ArgValue::Struct(arg) => {
let Ok((new_layout, offset)) = current_layout.extend(arg.layout) else {
return Err(FfiError::LayoutError);
};
current_layout = new_layout;
std::ptr::copy(
arg.ptr.as_ptr(),
alloc.ptr.byte_offset(offset as isize).as_ptr(),
arg.layout.size(),
);
}
}
}
}
if alloc.layout != current_layout.pad_to_align() {
// sanity check
return Err(FfiError::LayoutError);
}
Ok(alloc)
}
fn read(
&self,
ptr: *mut c_void,
struct_name: Atom,
struct_table: &HashMap<Atom, StructImpl>,
arena: &mut Arena,
) -> Result<Value, FfiError> {
unsafe {
let mut returns = Vec::new();
unsafe fn read_primitive<T>(
ptr: *mut c_void,
layout: &mut Layout,
) -> Result<T, FfiError> {
let (new_layout, offset) = layout
.extend(Layout::new::<T>())
.map_err(|_| FfiError::LayoutError)?;
*layout = new_layout;
let n = std::ptr::read::<T>(ptr.byte_offset(offset as isize).cast());
Ok(n)
}
unsafe fn read_int<T>(
ptr: *mut c_void,
layout: &mut Layout,
arena: &mut Arena,
) -> Result<Value, FfiError>
where
T: Copy + TryInto<i64> + MightNotFitInFixnum,
Integer: From<T>,
{
let n = read_primitive::<T>(ptr, layout)?;
Ok(Value::Number(fixnum!(Number, n, arena)))
}
unsafe fn read_float<T>(
ptr: *mut c_void,
layout: &mut Layout,
) -> Result<Value, FfiError>
where
T: Into<f64>,
{
let n = read_primitive::<T>(ptr, layout)?;
Ok(Value::Number(Number::Float(OrderedFloat(n.into()))))
}
let mut layout = Layout::from_size_align(0, 1).map_err(|_| FfiError::LayoutError)?;
for field_type in &self.fields {
let val = match field_type {
FfiType::U8 => read_int::<u8>(ptr, &mut layout, arena),
FfiType::I8 | FfiType::Bool => read_int::<i8>(ptr, &mut layout, arena),
FfiType::U16 => read_int::<u16>(ptr, &mut layout, arena),
FfiType::I16 => read_int::<i16>(ptr, &mut layout, arena),
FfiType::U32 => read_int::<u32>(ptr, &mut layout, arena),
FfiType::I32 => read_int::<i32>(ptr, &mut layout, arena),
FfiType::U64 => read_int::<u64>(ptr, &mut layout, arena),
FfiType::I64 => read_int::<i64>(ptr, &mut layout, arena),
FfiType::Ptr => {
let ptr = read_primitive::<*mut c_void>(ptr, &mut layout)?;
Ok(Value::Number(fixnum!(Number, ptr as isize, arena)))
}
FfiType::CStr => {
let ptr = read_primitive::<*mut c_void>(ptr, &mut layout)?;
Ok(Value::CString(CStr::from_ptr(ptr.cast()).to_owned()))
}
FfiType::F32 => read_float::<f32>(ptr, &mut layout),
FfiType::F64 => read_float::<f64>(ptr, &mut layout),
FfiType::Struct(substruct) => {
let Some(substruct_type) = struct_table.get(substruct) else {
return Err(FfiError::StructNotFound(*substruct));
};
let ffi_type = *substruct_type.ffi_type.as_raw_ptr();
let field_layout =
Layout::from_size_align(ffi_type.size, ffi_type.alignment as usize)
.map_err(|_| FfiError::LayoutError)?;
let (new_layout, offset) = layout
.extend(field_layout)
.map_err(|_| FfiError::LayoutError)?;
layout = new_layout;
let field_ptr = ptr.byte_offset(offset as isize);
let struct_val =
substruct_type.read(field_ptr, *substruct, struct_table, arena)?;
Ok(struct_val)
}
FfiType::Void => return Err(FfiError::VoidArgumentType),
};
returns.push(val?);
}
Ok(Value::Struct(struct_name, returns))
}
}
}
struct PointerArgs<'a, 'val> {
memory: Vec<Arg>,
phantom: PhantomData<&'a mut ArgValue<'val>>,
}
impl<'args, 'val> PointerArgs<'args, 'val> {
fn new(args: &'args [ArgValue<'val>]) -> Self {
let args = args
.iter()
.map(|arg| match arg {
ArgValue::U8(a) => libffi::middle::arg(a),
ArgValue::I8(a) => libffi::middle::arg(a),
ArgValue::U16(a) => libffi::middle::arg(a),
ArgValue::I16(a) => libffi::middle::arg(a),
ArgValue::U32(a) => libffi::middle::arg(a),
ArgValue::I32(a) => libffi::middle::arg(a),
ArgValue::U64(a) => libffi::middle::arg(a),
ArgValue::I64(a) => libffi::middle::arg(a),
ArgValue::F32(a) => libffi::middle::arg(a),
ArgValue::F64(a) => libffi::middle::arg(a),
ArgValue::Ptr(ptr, _) => Arg::new(ptr),
ArgValue::Struct(s) => unsafe {
std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr())
},
})
.collect();
PointerArgs {
memory: args,
phantom: PhantomData,
}
}
}
impl Deref for PointerArgs<'_, '_> {
type Target = [Arg];
fn deref(&self) -> &Self::Target {
&self.memory
}
}
#[derive(Debug, Clone, Copy)]
enum FfiType {
Void,
Bool,
U8,
I8,
U16,
I16,
U32,
I32,
U64,
I64,
F32,
F64,
Ptr,
CStr,
Struct(Atom),
}
impl FfiType {
fn from_atom(atom: &Atom) -> Self {
match atom {
atom!("sint64") | atom!("i64") => Self::I64,
atom!("sint32") | atom!("i32") => Self::I32,
atom!("sint16") | atom!("i16") => Self::I16,
atom!("sint8") | atom!("i8") => Self::I8,
atom!("uint64") | atom!("u64") => Self::U64,
atom!("uint32") | atom!("u32") => Self::U32,
atom!("uint16") | atom!("u16") => Self::U16,
atom!("uint8") | atom!("u8") => Self::U8,
atom!("bool") => Self::Bool,
atom!("void") => Self::Void,
atom!("cstr") => Self::CStr,
atom!("ptr") => Self::Ptr,
atom!("f32") => Self::F32,
atom!("f64") => Self::F64,
struct_name => Self::Struct(*struct_name),
}
}
fn to_type(self, structs_table: &HashMap<Atom, StructImpl>) -> Result<Type, FfiError> {
Ok(match self {
Self::I64 => libffi::middle::Type::i64(),
Self::I32 => libffi::middle::Type::i32(),
Self::I16 => libffi::middle::Type::i16(),
Self::I8 => libffi::middle::Type::i8(),
Self::U64 => libffi::middle::Type::u64(),
Self::U32 => libffi::middle::Type::u32(),
Self::U16 => libffi::middle::Type::u16(),
Self::U8 => libffi::middle::Type::u8(),
Self::Bool => libffi::middle::Type::i8(),
Self::Void => libffi::middle::Type::void(),
Self::CStr => libffi::middle::Type::pointer(),
Self::Ptr => libffi::middle::Type::pointer(),
Self::F32 => libffi::middle::Type::f32(),
Self::F64 => libffi::middle::Type::f64(),
Self::Struct(struct_name) => structs_table
.get(&struct_name)
.ok_or(FfiError::StructNotFound(struct_name))?
.ffi_type
.clone(),
})
}
}
enum ArgValue<'a> {
U8(u8),
I8(i8),
U16(u16),
I16(i16),
U32(u32),
I32(i32),
U64(u64),
I64(i64),
F32(f32),
F64(f64),
Ptr(*mut c_void, PhantomData<&'a CString>),
Struct(FfiStruct),
}
impl<'val> ArgValue<'val> {
fn new(
val: &'val mut Value,
arg_type: &FfiType,
structs_table: &HashMap<Atom, StructImpl>,
) -> Result<Self, FfiError> {
match arg_type {
FfiType::U8 => Ok(Self::U8(val.as_int()?)),
FfiType::I8 | FfiType::Bool => Ok(Self::I8(val.as_int()?)),
FfiType::U16 => Ok(Self::U16(val.as_int()?)),
FfiType::I16 => Ok(Self::I16(val.as_int()?)),
FfiType::U32 => Ok(Self::U32(val.as_int()?)),
FfiType::I32 => Ok(Self::I32(val.as_int()?)),
FfiType::U64 => Ok(Self::U64(val.as_int()?)),
FfiType::I64 => Ok(Self::I64(val.as_int()?)),
FfiType::F32 => Ok(Self::F32(val.as_float()? as f32)),
FfiType::F64 => Ok(Self::F64(val.as_float()?)),
FfiType::Ptr => Ok(Self::Ptr(val.as_ptr()?, PhantomData)),
FfiType::CStr => Ok(Self::Ptr(val.as_ptr()?, PhantomData)),
FfiType::Struct(arg_type_name) => {
let (val_type_name, args) = val.as_struct()?;
if *arg_type_name != val_type_name {
return Err(FfiError::ValueCast(*arg_type_name, val_type_name));
}
let Some(struct_type) = structs_table.get(&val_type_name) else {
return Err(FfiError::StructNotFound(*arg_type_name));
};
Ok(Self::Struct(struct_type.build(structs_table, args)?))
}
FfiType::Void => Err(FfiError::VoidArgumentType),
}
}
fn build_args(
args: &'val mut [Value],
types: &[FfiType],
structs_table: &HashMap<Atom, StructImpl>,
) -> Result<Vec<Self>, FfiError> {
if types.len() != args.len() {
return Err(FfiError::ArgCountMismatch);
}
args.iter_mut()
.zip(types)
.map(|(arg, arg_type)| ArgValue::new(arg, arg_type, structs_table))
.collect::<Result<Vec<_>, _>>()
}
}
struct FfiStruct {
ptr: NonNull<c_void>,
layout: Layout,
allocator: FfiAllocator,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum FfiAllocator {
Rust,
C,
}
impl TryFrom<Atom> for FfiAllocator {
type Error = ();
fn try_from(value: Atom) -> Result<Self, Self::Error> {
match value {
atom!("rust") => Ok(Self::Rust),
atom!("c") => Ok(Self::C),
_ => Err(()),
}
}
}
impl FfiAllocator {
/// # Safety
///
/// - layout must not have a size of 0
unsafe fn alloc(self, layout: Layout) -> Result<NonNull<c_void>, FfiError> {
let ptr = match self {
FfiAllocator::Rust => unsafe { alloc::alloc(layout).cast() },
FfiAllocator::C => unsafe { libc::malloc(layout.size()) },
};
NonNull::new(ptr).ok_or(FfiError::AllocationFailed)
}
/// # Safety
///
/// - ptr must point to an allocation currently allocated by this allocator
/// - layout must match the layout that was used to allocate the allocation pointed to by ptr
unsafe fn dealloc(self, layout: Layout, ptr: NonNull<c_void>) {
match self {
FfiAllocator::Rust => unsafe { alloc::dealloc(ptr.as_ptr().cast(), layout) },
FfiAllocator::C => unsafe { libc::free(ptr.as_ptr()) },
}
}
}
impl FfiStruct {
fn new(layout: Layout, allocator: FfiAllocator) -> Result<Self, FfiError> {
assert_ne!(layout.size(), 0);
Ok(FfiStruct {
ptr: unsafe { allocator.alloc(layout) }?,
layout,
allocator,
})
}
}
impl Drop for FfiStruct {
fn drop(&mut self) {
unsafe { self.allocator.dealloc(self.layout, self.ptr) };
}
}
impl ForeignFunctionTable {
pub fn merge(&mut self, other: ForeignFunctionTable) {
self.table.extend(other.table);
}
pub fn define_struct(&mut self, name: Atom, atom_fields: Vec<Atom>) -> Result<(), FfiError> {
let fields: Vec<_> = atom_fields.iter().map(FfiType::from_atom).collect();
let struct_type = libffi::middle::Type::structure(
fields
.iter()
.map(|field| field.to_type(&self.structs))
.collect::<Result<Vec<_>, _>>()?,
);
unsafe {
// ensure that size and alignment of struct_type are set properly
use libffi::low::{ffi_abi_FFI_DEFAULT_ABI, prep_cif};
prep_cif(
&mut Default::default(),
ffi_abi_FFI_DEFAULT_ABI,
1,
struct_type.as_raw_ptr(),
[struct_type.as_raw_ptr()].as_mut_ptr(),
)?;
};
self.structs.insert(
name,
StructImpl {
ffi_type: struct_type,
fields,
},
);
Ok(())
}
pub(crate) fn load_library(
&mut self,
library_name: &str,
functions: &Vec<FunctionDefinition>,
) -> Result<(), Box<dyn Error>> {
let mut ff_table: ForeignFunctionTable = Default::default();
let library = unsafe { Library::new(library_name) }?;
for function in functions {
let symbol_name: CString = CString::new(&*function.name.as_str())?;
let code_ptr: Symbol<*mut c_void> =
unsafe { library.get(symbol_name.as_bytes_with_nul()) }?;
let args: Vec<_> = function.args.iter().map(FfiType::from_atom).collect();
let return_type = FfiType::from_atom(&function.return_value);
let cif = libffi::middle::Cif::new(
args.iter()
.map(|arg| arg.to_type(&self.structs))
.collect::<Result<Vec<_>, _>>()?,
return_type.to_type(&self.structs)?,
);
ff_table.table.insert(
function.name,
FunctionImpl {
cif,
args,
code_ptr: CodePtr(unsafe { code_ptr.into_raw() }.as_raw_ptr()),
return_type,
},
);
}
std::mem::forget(library);
self.merge(ff_table);
Ok(())
}
pub fn exec(
&mut self,
fn_name: Atom,
mut args: Vec<Value>,
arena: &mut Arena,
) -> Result<Value, FfiError> {
let fn_impl = self
.table
.get(&fn_name)
.ok_or(FfiError::FunctionNotFound(fn_name))?;
let args = ArgValue::build_args(&mut args, &fn_impl.args, &self.structs)?;
let args = PointerArgs::new(&args);
fn_impl.call(&args, arena, &self.structs)
}
pub fn allocate(
&mut self,
allocator: FfiAllocator,
kind: Atom,
mut args: Value,
arena: &mut Arena,
) -> Result<Value, FfiError> {
fn allocate_primitive<T: Copy>(
allocator: FfiAllocator,
initial_value: T,
arena: &mut Arena,
) -> Result<Value, FfiError> {
const { assert!(std::mem::size_of::<T>() != 0) };
let ptr = unsafe { allocator.alloc(Layout::new::<T>()) }?;
unsafe { ptr.cast::<T>().write(initial_value) };
Ok(Value::Number(fixnum!(
Number,
ptr.as_ptr().expose_provenance(),
arena
)))
}
match FfiType::from_atom(&kind) {
FfiType::Void => Err(FfiError::VoidArgumentType),
FfiType::Bool => {
let val = args.as_int::<u8>()?;
let init = match val {
0 => false,
1 => true,
_ => return Err(FfiError::ValueOutOfRange(DomainErrorType::ZeroOrOne, args)),
};
allocate_primitive::<bool>(allocator, init, arena)
}
FfiType::U8 => allocate_primitive::<u8>(allocator, args.as_int()?, arena),
FfiType::I8 => allocate_primitive::<i8>(allocator, args.as_int()?, arena),
FfiType::U16 => allocate_primitive::<u16>(allocator, args.as_int()?, arena),
FfiType::I16 => allocate_primitive::<i16>(allocator, args.as_int()?, arena),
FfiType::U32 => allocate_primitive::<u32>(allocator, args.as_int()?, arena),
FfiType::I32 => allocate_primitive::<i32>(allocator, args.as_int()?, arena),
FfiType::U64 => allocate_primitive::<u64>(allocator, args.as_int()?, arena),
FfiType::I64 => allocate_primitive::<i64>(allocator, args.as_int()?, arena),
FfiType::F32 => allocate_primitive::<f32>(allocator, args.as_float()? as f32, arena),
FfiType::F64 => allocate_primitive::<f64>(allocator, args.as_float()?, arena),
FfiType::Ptr => allocate_primitive::<*mut c_void>(allocator, args.as_ptr()?, arena),
FfiType::CStr => Err(FfiError::CStrFieldType),
FfiType::Struct(_) => {
let Some(struct_impl) = self.structs.get(&kind) else {
return Err(FfiError::StructNotFound(kind));
};
let (_, args) = args.as_struct()?;
let ffi_struct = struct_impl.build(&self.structs, args)?;
let ptr = ManuallyDrop::new(ffi_struct).ptr;
Ok(Value::Number(fixnum!(
Number,
ptr.as_ptr().expose_provenance(),
arena
)))
}
}
}
pub fn read_ptr(
&mut self,
kind: Atom,
mut ptr: Value,
arena: &mut Arena,
) -> Result<Value, FfiError> {
unsafe fn read_int<T>(ptr: NonNull<c_void>, arena: &mut Arena) -> Value
where
T: Copy + TryInto<i64> + MightNotFitInFixnum,
Integer: From<T>,
{
let n = ptr.cast::<T>().read();
Value::Number(fixnum!(Number, n, arena))
}
let ptr = ptr.as_ptr()?;
let Some(ptr) = NonNull::new(ptr) else {
return Err(FfiError::NullPtr);
};
match FfiType::from_atom(&kind) {
FfiType::Void => Err(FfiError::VoidArgumentType),
FfiType::Bool | FfiType::U8 => Ok(unsafe { read_int::<u8>(ptr, arena) }),
FfiType::I8 => Ok(unsafe { read_int::<i8>(ptr, arena) }),
FfiType::U16 => Ok(unsafe { read_int::<u16>(ptr, arena) }),
FfiType::I16 => Ok(unsafe { read_int::<i16>(ptr, arena) }),
FfiType::U32 => Ok(unsafe { read_int::<u32>(ptr, arena) }),
FfiType::I32 => Ok(unsafe { read_int::<i32>(ptr, arena) }),
FfiType::U64 => Ok(unsafe { read_int::<u64>(ptr, arena) }),
FfiType::I64 => Ok(unsafe { read_int::<i64>(ptr, arena) }),
FfiType::F32 => Ok(Value::Number(Number::Float(
(unsafe { ptr.cast::<f32>().read() } as f64).into(),
))),
FfiType::F64 => Ok(Value::Number(Number::Float(
unsafe { ptr.cast::<f64>().read() }.into(),
))),
FfiType::Ptr => {
let addr = unsafe { ptr.cast::<*mut c_void>().read() }.expose_provenance();
Ok(Value::Number(fixnum!(Number, addr, arena)))
}
FfiType::CStr => Ok(Value::CString(
unsafe { CStr::from_ptr(ptr.as_ptr().cast()) }.to_owned(),
)),
FfiType::Struct(_) => {
let Some(struct_impl) = self.structs.get(&kind) else {
return Err(FfiError::StructNotFound(kind));
};
struct_impl.read(ptr.as_ptr(), kind, &self.structs, arena)
}
}
}
pub fn deallocate(
&mut self,
allocator: FfiAllocator,
kind: Atom,
mut ptr: Value,
) -> Result<(), FfiError> {
fn deallocate_primitive<T: Copy>(allocator: FfiAllocator, ptr: NonNull<c_void>) {
const { assert!(std::mem::size_of::<T>() != 0) };
unsafe { allocator.dealloc(Layout::new::<T>(), ptr) };
}
let ptr = ptr.as_ptr()?;
let Some(ptr) = NonNull::new(ptr) else {
return Err(FfiError::NullPtr);
};
match FfiType::from_atom(&kind) {
FfiType::Void => return Err(FfiError::VoidArgumentType),
FfiType::Bool => deallocate_primitive::<bool>(allocator, ptr),
FfiType::U8 => deallocate_primitive::<u8>(allocator, ptr),
FfiType::I8 => deallocate_primitive::<i8>(allocator, ptr),
FfiType::U16 => deallocate_primitive::<u16>(allocator, ptr),
FfiType::I16 => deallocate_primitive::<i16>(allocator, ptr),
FfiType::U32 => deallocate_primitive::<u32>(allocator, ptr),
FfiType::I32 => deallocate_primitive::<i32>(allocator, ptr),
FfiType::U64 => deallocate_primitive::<u64>(allocator, ptr),
FfiType::I64 => deallocate_primitive::<i64>(allocator, ptr),
FfiType::F32 => deallocate_primitive::<f32>(allocator, ptr),
FfiType::F64 => deallocate_primitive::<f64>(allocator, ptr),
FfiType::Ptr => deallocate_primitive::<*mut c_void>(allocator, ptr),
FfiType::CStr => return Err(FfiError::CStrFieldType),
FfiType::Struct(_) => {
let Some(struct_impl) = self.structs.get(&kind) else {
return Err(FfiError::StructNotFound(kind));
};
let layout = struct_impl.layout()?;
drop(FfiStruct {
ptr,
layout,
allocator,
})
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum Value {
Number(Number),
CString(CString),
Struct(Atom, Vec<Value>),
}
impl Value {
fn as_int<I>(&self) -> Result<I, FfiError>
where
Integer: TryInto<I>,
i64: TryInto<I>,
{
match self {
Value::Number(Number::Integer(ibig_ptr)) => {
let ibig: &Integer = ibig_ptr;
ibig.clone().try_into().map_err(|_| {
FfiError::ValueOutOfRange(DomainErrorType::FixedSizedInt, self.clone())
})
}
Value::Number(Number::Fixnum(fixnum)) => fixnum.get_num().try_into().map_err(|_| {
FfiError::ValueOutOfRange(DomainErrorType::FixedSizedInt, self.clone())
}),
_ => Err(FfiError::ValueOutOfRange(
DomainErrorType::FixedSizedInt,
self.clone(),
)),
}
}
fn as_float(&self) -> Result<f64, FfiError> {
match self {
&Value::Number(Number::Float(OrderedFloat(f))) => Ok(f),
_ => Err(FfiError::ValueOutOfRange(
DomainErrorType::F64,
self.clone(),
)),
}
}
fn as_ptr(&mut self) -> Result<*mut c_void, FfiError> {
match self {
Value::CString(ref mut cstr) => Ok(cstr.as_ptr().cast_mut().cast()),
Value::Number(Number::Fixnum(fixnum)) => Ok(std::ptr::with_exposed_provenance_mut(
fixnum.get_num() as usize,
)),
_ => Err(FfiError::ValueOutOfRange(
DomainErrorType::PtrLike,
self.clone(),
)),
}
}
fn as_struct(&mut self) -> Result<(Atom, &mut [Self]), FfiError> {
match self {
Value::Struct(name, values) => Ok((*name, values)),
_ => Err(FfiError::ValueOutOfRange(
DomainErrorType::FfiStruct,
self.clone(),
)),
}
}
}
#[derive(Debug)]
pub enum FfiError {
ValueCast(Atom, Atom),
ValueOutOfRange(DomainErrorType, Value),
VoidArgumentType,
FunctionNotFound(Atom),
StructNotFound(Atom),
ArgCountMismatch,
AllocationFailed,
// LayoutError should never occour
LayoutError,
UnsupportedTypedef,
UnsupportedAbi,
CStrFieldType,
NullPtr,
}
impl std::fmt::Display for FfiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl Error for FfiError {}
impl From<libffi::low::Error> for FfiError {
fn from(value: libffi::low::Error) -> Self {
match value {
libffi::low::Error::Typedef => FfiError::UnsupportedTypedef,
libffi::low::Error::Abi => FfiError::UnsupportedAbi,
}
}
}

1017
src/forms.rs Normal file

File diff suppressed because it is too large Load Diff

798
src/functor_macro.rs Normal file
View File

@@ -0,0 +1,798 @@
//! A macro to construct functor terms ready to be written to the WAM
//! heap.
use crate::atom_table::*;
use crate::instructions::IndexingCodePtr;
use crate::machine::heap::Heap;
use crate::parser::ast::Fixnum;
use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum FunctorElement {
AbsoluteCell(HeapCellValue),
Cell(HeapCellValue),
InnerFunctor(u64, Vec<FunctorElement>),
String(u64, String),
}
// helper macros
macro_rules! count {
() => (0);
( $x:tt $($xs:tt)* ) => (1 + count!($($xs)*));
}
// core macros
/*
* functor! is more declarative now, with fewer effects and more
* work done at compile time using const functions. With these
* advantages come new quirks: expressions must generally be wrapped
* in round parentheses for rustc to parse them. See the tests module
* below for examples, especially those involving atom!
* subexpressions.
*/
macro_rules! functor {
($name:expr) => ({
vec![FunctorElement::Cell(atom_as_cell!($name))]
});
($name:expr, [$($dt:ident($($value:tt),*)),+]) => ({
build_functor!([$($dt($($value),*)),*],
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
1,
[])
});
}
macro_rules! inner_functor {
($name:expr, $res_len:expr, [$($dt:ident($($value:tt),*)),+]) => ({
build_functor!([$($dt($($value),*)),*],
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
1 + $res_len,
[])
});
}
macro_rules! build_functor {
([], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
vec![$($res,)* $($subfunctor),*]
});
([indexing_code_ptr($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let (inner_functor, cell_size) = indexing_code_ptr($e);
let referent = if cell_size == 1 {
heap_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
} else {
str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
};
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(referent)],
1 + cell_size + $res_len,
[$($subfunctor, )* FunctorElement::InnerFunctor(cell_size, inner_functor)])
});
([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
1 + $res_len,
[$($subfunctor),*])
});
([cell($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::AbsoluteCell($e)],
1 + $res_len,
[$($subfunctor),*])
});
([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
1 + $res_len,
[$($subfunctor),*])
});
([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let number_cell = HeapCellValue::arena_from($n, $arena);
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(number_cell)],
1 + $res_len,
[$($subfunctor),*])
});
([list([]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(empty_list_as_cell!())],
1 + $res_len,
[$($subfunctor),*])
});
([list([$id:ident($($id_value:tt),*) $(, $in_dt:ident($($in_value:tt),*))*]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([functor((atom!(".")), [$id($($id_value),*), list([$($in_dt($($in_value),*)),*])])
$(, $dt($($value),*))*],
[$($res),*],
$res_len,
[$($subfunctor),*])
});
([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
#[allow(unused_parens)]
let string = $s;
let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64;
let result_len = 1 + count!($($dt)*) + $res_len;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(pstr_loc_as_cell!(heap_index!(result_len as usize) as u64))],
1 + $res_len + pstr_len,
[$($subfunctor, )* FunctorElement::String(pstr_len, string)])
});
([atom_as_cell($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(atom_as_cell!($n))],
1 + $res_len,
[$($subfunctor),*])
});
([functor($stub:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
let result_len = 1u64 + count!($($dt)*) + $res_len;
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&$stub)) as u64;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
1 + $res_len + inner_functor_size,
[$($subfunctor, )*
FunctorElement::InnerFunctor(inner_functor_size, $stub)])
});
([$id:ident($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell($id!($n))],
1 + $res_len,
[$($subfunctor),*])
});
([functor($name:expr, [$($in_dt:ident($($in_value:tt),*)),+]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let result_len = 1u64 + count!($($dt)*) + $res_len;
let inner_functor = inner_functor!($name, 0, [$($in_dt($($in_value),*)),*]);
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&inner_functor)) as u64;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
1 + $res_len + inner_functor_size,
[$($subfunctor, )*
FunctorElement::InnerFunctor(inner_functor_size, inner_functor)])
});
}
pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> (Vec<FunctorElement>, u64) {
match code_ptr {
IndexingCodePtr::DynamicExternal(o) => {
(functor!(atom!("dynamic_external"), [fixnum(o)]), 2)
}
IndexingCodePtr::External(o) => (functor!(atom!("external"), [fixnum(o)]), 2),
IndexingCodePtr::Internal(o) => (functor!(atom!("internal"), [fixnum(o)]), 2),
IndexingCodePtr::Fail => (vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))], 1),
}
}
pub(crate) fn variadic_functor(
name: Atom,
arity: usize,
iter: impl Iterator<Item = Vec<FunctorElement>>,
) -> Vec<FunctorElement> {
let mut arg_vec = vec![
FunctorElement::Cell(atom_as_cell!(name, arity)),
FunctorElement::Cell(list_loc_as_cell!(2)),
];
let key_value_pairs: Vec<_> = iter.collect();
let num_items = key_value_pairs.len();
let mut functor_offset = 0;
for (idx, kv_func) in key_value_pairs.iter().enumerate() {
let functor_size = cell_index!(Heap::compute_functor_byte_size(kv_func));
arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(
2 + num_items * 2 + functor_offset
)));
arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(4 + 2 * idx)));
functor_offset += functor_size;
}
arg_vec.pop();
arg_vec.push(FunctorElement::Cell(empty_list_as_cell!()));
arg_vec.extend(key_value_pairs.into_iter().map(|kv_func| {
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func));
FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func)
}));
arg_vec
}
#[cfg(test)]
#[allow(unused_parens)]
mod tests {
use super::*;
use indexmap::indexmap;
use std::string::String;
use FunctorElement::*;
#[test]
fn basic_terms() {
let functor = functor!(
atom!("first"),
[atom_as_cell((atom!("a"))), char_as_cell('c')]
);
assert_eq!(functor.len(), 3);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 2)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(char_as_cell!('c')));
let functor = functor!(
atom!("second"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 5);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("second"), 3)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(4)));
assert_eq!(functor[3], Cell(char_as_cell!('c')));
assert_eq!(
functor[4],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
let functor = functor!(
atom!("third"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 7);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("third"), 4)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(8)));
assert_eq!(functor[4], Cell(char_as_cell!('c')));
assert_eq!(
functor[5],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))
);
let functor = functor!(
atom!("fourth"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1)]),
functor((atom!("d")), [fixnum(453), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 9);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("fourth"), 5)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(6)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(9)));
assert_eq!(functor[4], Cell(str_loc_as_cell!(11)));
assert_eq!(functor[5], Cell(char_as_cell!('c')));
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
assert_eq!(
functor[7],
InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))
);
assert_eq!(
functor[8],
InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))
);
}
#[test]
fn basic_terms_in_heap() {
let functor = functor!(
atom!("first"),
[atom_as_cell((atom!("a"))), char_as_cell('b')]
);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
assert_eq!(heap[2], char_as_cell!('b'));
heap.truncate(2);
let functor = functor!(
atom!("second"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1), fixnum(2)]),
char_as_cell('b')
]
);
assert_eq!(functor.len(), 7);
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("second"), 4));
assert_eq!(heap[3], atom_as_cell!(atom!("a")));
assert_eq!(heap[4], str_loc_as_cell!(7));
assert_eq!(heap[5], str_loc_as_cell!(10));
assert_eq!(heap[6], char_as_cell!('b'));
assert_eq!(heap[7], atom_as_cell!(atom!("b"), 2));
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[10], atom_as_cell!(atom!("c"), 2));
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(2)));
}
#[test]
fn nested_functors() {
let functor = functor!(
atom!("first"),
[
atom_as_cell((atom!("a"))),
functor(
(atom!("d")),
[
fixnum(1),
functor(
(atom!("b")),
[atom_as_cell((atom!("c"))), char_as_cell('c')]
)
]
),
functor((atom!("e")), [fixnum(453), fixnum(2)]),
char_as_cell('b')
]
);
assert_eq!(functor.len(), 7);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 4)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(11)));
assert_eq!(functor[4], Cell(char_as_cell!('b')));
assert_eq!(
functor[5],
InnerFunctor(
6,
vec![
Cell(atom_as_cell!(atom!("d"), 2)),
Cell(fixnum_as_cell!(Fixnum::build_with(1))),
Cell(str_loc_as_cell!(3)),
InnerFunctor(
3,
functor!(atom!("b"), [atom_as_cell((atom!("c"))), char_as_cell('c')])
)
]
)
);
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("e"), [fixnum(453), fixnum(2)]))
);
}
#[test]
fn nested_functors_in_heap() {
let functor = functor!(
atom!("first"),
[
atom_as_cell((atom!("a"))),
functor(
(atom!("second")),
[
fixnum(1),
functor(
(atom!("third")),
[atom_as_cell((atom!("b"))), char_as_cell('c')]
)
]
),
functor((atom!("fourth")), [fixnum(453), fixnum(2)]),
char_as_cell('b')
]
);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap.cell_len(), 14);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 4));
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
assert_eq!(heap[2], str_loc_as_cell!(5));
assert_eq!(heap[3], str_loc_as_cell!(11));
assert_eq!(heap[4], char_as_cell!('b'));
assert_eq!(heap[5], atom_as_cell!(atom!("second"), 2));
assert_eq!(heap[6], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[7], str_loc_as_cell!(8));
assert_eq!(heap[8], atom_as_cell!(atom!("third"), 2));
assert_eq!(heap[9], atom_as_cell!(atom!("b")));
assert_eq!(heap[10], char_as_cell!('c'));
assert_eq!(heap[11], atom_as_cell!(atom!("fourth"), 2));
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(453)));
assert_eq!(heap[13], fixnum_as_cell!(Fixnum::build_with(2)));
}
#[test]
fn functors_with_strings_in_heap() {
let functor = functor!(atom!("first"), [string((String::from("a string")))]);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap.cell_len(), 5);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
heap.slice_to_str(heap_index!(2), "a string".len()),
"a string"
);
assert_eq!(heap[4], empty_list_as_cell!());
heap.truncate(0);
let functor = functor!(
atom!("second"),
[string((String::from("a stuttered\0 string")))]
);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 10);
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
heap.slice_to_str(heap_index!(2), "a stuttered".len()),
"a stuttered"
);
assert_eq!(heap[4], list_loc_as_cell!(5));
assert_eq!(heap[5], char_as_cell!('\u{0}'));
assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(
heap.slice_to_str(heap_index!(7), " string".len()),
" string"
);
assert_eq!(heap[9], empty_list_as_cell!());
}
#[test]
fn functors_with_lists_in_heap() {
let functor = functor!(
atom!("first"),
[list([fixnum(1), atom_as_cell((atom!("a"))), fixnum(2)])]
);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 11);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
assert_eq!(heap[1], str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[3], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[4], str_loc_as_cell!(5));
assert_eq!(heap[5], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[6], atom_as_cell!(atom!("a")));
assert_eq!(heap[7], str_loc_as_cell!(8));
assert_eq!(heap[8], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[10], empty_list_as_cell!());
}
#[test]
fn inlined_atoms() {
let atom_table = AtomTable::new();
let inlined = AtomTable::build_with(&atom_table, "inline");
assert!(inlined.is_inlined());
assert_eq!(&*inlined.as_str(), "inline");
let non_inlined = AtomTable::build_with(&atom_table, "longer non-inlined atom");
assert!(!non_inlined.is_inlined());
assert_eq!(&*non_inlined.as_str(), "longer non-inlined atom");
}
#[test]
fn functors_with_indexing_code_ptr() {
let code_ptr = IndexingCodePtr::Internal(0);
let functor = functor!(
atom!("first"),
[
string((String::from("a string"))),
indexing_code_ptr(code_ptr)
]
);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 8);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0)));
heap.truncate(0);
let functor = functor!(
atom!("second"),
[
string((String::from("a string"))),
functor(
(atom!("third")),
[
atom_as_cell((atom!("a"))),
string((String::from("another string"))),
indexing_code_ptr(code_ptr)
]
)
]
);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 15);
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10)));
assert_eq!(heap[9], str_loc_as_cell!(13));
assert_eq!(
heap.slice_to_str(heap_index!(10), "another string".len()),
"another string"
);
assert_eq!(heap[12], empty_list_as_cell!());
assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0)));
let functor = functor!(
atom!("fourth"),
[
string((String::from("a string"))),
functor(
(atom!("a")),
[
functor(
(atom!("fifth")),
[
fixnum(5),
string((String::from("another string"))),
indexing_code_ptr(code_ptr)
]
),
string((String::from("and another")))
]
)
]
);
heap.truncate(0);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 21);
assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2));
assert_eq!(heap[7], str_loc_as_cell!(9));
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(18))); // <-- wrong!
assert_eq!(heap[9], atom_as_cell!(atom!("fifth"), 3));
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5)));
assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13)));
assert_eq!(heap[12], str_loc_as_cell!(16));
assert_eq!(
heap.slice_to_str(heap_index!(13), "another string".len()),
"another string"
);
assert_eq!(heap[15], empty_list_as_cell!());
assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0)));
assert_eq!(
heap.slice_to_str(heap_index!(18), "and another".len()),
"and another"
);
assert_eq!(heap[20], empty_list_as_cell!());
let constants = indexmap![
atom_as_cell!(atom!("a")) => IndexingCodePtr::External(2),
atom_as_cell!(atom!("d")) => IndexingCodePtr::External(7),
];
let functor = variadic_functor(
atom!("switch_on_constants"),
1,
constants
.iter()
.map(|(c, ptr)| functor!(atom!(":"), [cell((*c)), indexing_code_ptr((*ptr))])),
);
heap.truncate(0);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap[0], atom_as_cell!(atom!("switch_on_constants"), 1));
assert_eq!(heap[1], list_loc_as_cell!(2));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(heap[3], list_loc_as_cell!(4));
assert_eq!(heap[4], str_loc_as_cell!(11));
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!(":"), 2));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], str_loc_as_cell!(9));
assert_eq!(heap[9], atom_as_cell!(atom!("external"), 1));
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[11], atom_as_cell!(atom!(":"), 2));
assert_eq!(heap[12], atom_as_cell!(atom!("d")));
assert_eq!(heap[13], str_loc_as_cell!(14));
assert_eq!(heap[14], atom_as_cell!(atom!("external"), 1));
assert_eq!(heap[15], fixnum_as_cell!(Fixnum::build_with(7)));
}
#[test]
fn undefined_procedure_functor() {
// existence_error
let culprit = functor!(atom!("/"), [atom_as_cell((atom!("a"))), fixnum(1)]);
let stub = functor!(
atom!("existence_error"),
[
atom_as_cell((atom!("procedure"))),
functor((culprit.clone()))
]
);
println!("{stub:?}");
// now the error form
let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]);
println!("{lineless_error_form:?}");
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(lineless_error_form);
functor_writer(&mut heap).unwrap();
assert_eq!(heap[0], atom_as_cell!(atom!("error"), 2));
assert_eq!(heap[1], str_loc_as_cell!(3));
assert_eq!(heap[2], str_loc_as_cell!(9));
assert_eq!(heap[3], atom_as_cell!(atom!("existence_error"), 2));
assert_eq!(heap[4], atom_as_cell!(atom!("procedure")));
assert_eq!(heap[5], str_loc_as_cell!(6)); // is str_loc_as_cell!(3)
assert_eq!(heap[6], atom_as_cell!(atom!("/"), 2));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[9], atom_as_cell!(atom!("/"), 2));
assert_eq!(heap[10], atom_as_cell!(atom!("a")));
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
}
#[test]
fn argless_functor() {
let name = functor!(atom!("[]"));
assert_eq!(name.len(), 1);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(name);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, heap_loc_as_cell!(0));
}
#[test]
fn predefined_subfunctors() {
let stub = functor!(atom!("sub"), [atom_as_cell((atom!("[]")))]);
let name = functor!(atom!("super"), [functor(stub)]);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(name);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 4);
assert_eq!(heap[0], atom_as_cell!(atom!("super"), 1));
assert_eq!(heap[1], str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("sub"), 1));
assert_eq!(heap[3], empty_list_as_cell!());
}
}

3129
src/heap_iter.rs Normal file

File diff suppressed because it is too large Load Diff

2232
src/heap_print.rs Normal file

File diff suppressed because it is too large Load Diff

23
src/http.rs Normal file
View File

@@ -0,0 +1,23 @@
use bytes::{buf::Reader, Bytes};
use std::sync::{Arc, Condvar, Mutex};
use warp::http;
pub struct HttpListener {
pub incoming: std::sync::mpsc::Receiver<HttpRequest>,
}
pub struct HttpRequest {
pub request_data: HttpRequestData,
pub response: HttpResponse,
}
pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<warp::reply::Response>>, Condvar)>;
pub struct HttpRequestData {
pub method: http::Method,
pub headers: http::HeaderMap,
pub path: String,
pub query: String,
pub body: Reader<Bytes>,
}

1553
src/indexing.rs Normal file

File diff suppressed because it is too large Load Diff

442
src/iterators.rs Normal file
View File

@@ -0,0 +1,442 @@
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
use crate::parser::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::*;
use std::rc::Rc;
use std::vec::Vec;
#[allow(clippy::borrowed_box)]
#[derive(Debug, Clone)]
pub(crate) enum TermRef<'a> {
AnonVar(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
Var(Level, &'a Cell<VarReg>, VarPtr),
}
#[allow(clippy::borrowed_box)]
#[derive(Debug)]
pub(crate) enum TermIterState<'a> {
AnonVar(Level),
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
Literal(Level, &'a Cell<RegType>, &'a Literal),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
Var(Level, &'a Cell<VarReg>, VarPtr),
}
impl<'a> TermIterState<'a> {
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
match term {
Term::AnonVar => TermIterState::AnonVar(lvl),
Term::Clause(cell, name, subterms) => {
TermIterState::Clause(lvl, 0, cell, *name, subterms)
}
Term::Cons(cell, head, tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
}
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
Term::PartialString(cell, string_buf, tail) => {
TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
}
Term::CompleteString(cell, string) => {
TermIterState::CompleteString(lvl, cell, string.clone())
}
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
}
}
}
#[derive(Debug)]
pub(crate) struct QueryIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
impl<'a> QueryIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack
.push(TermIterState::subterm_to_state(lvl, term));
}
/*
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
let state_stack = terms
.iter()
.rev()
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
.collect();
QueryIterator { state_stack }
}
*/
fn from_term(term: &'a Term) -> Self {
let state = match term {
Term::AnonVar
| Term::Cons(..)
| Term::Literal(..)
| Term::PartialString(..)
| Term::CompleteString(..) => {
return QueryIterator {
state_stack: vec![],
}
}
Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
};
QueryIterator {
state_stack: vec![state],
}
}
fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
match term {
QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
self.state_stack
.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
}
QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
self.state_stack
.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
}
_ => {}
}
}
pub fn new(term: &'a QueryTerm) -> Self {
let mut iter = QueryIterator {
state_stack: vec![],
};
iter.extend_state(Level::Root, term);
iter
}
}
impl<'a> Iterator for QueryIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl));
}
TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
if child_num == child_terms.len() {
match name {
atom!("$call") if lvl == Level::Root => {
self.push_subterm(Level::Shallow, &child_terms[0]);
}
_ => {
return match lvl {
Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
}
}
};
} else {
self.state_stack.push(TermIterState::Clause(
lvl,
child_num + 1,
cell,
name,
child_terms,
));
self.push_subterm(lvl.child_level(), &child_terms[child_num]);
}
}
TermIterState::InitialCons(lvl, cell, head, tail) => {
self.state_stack
.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.push_subterm(lvl.child_level(), tail);
self.push_subterm(lvl.child_level(), head);
}
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
self.state_stack
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
self.push_subterm(lvl.child_level(), tail);
}
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
return Some(TermRef::PartialString(lvl, cell, string, tail));
}
TermIterState::CompleteString(lvl, cell, string) => {
return Some(TermRef::CompleteString(lvl, cell, string));
}
TermIterState::FinalCons(lvl, cell, head, tail) => {
return Some(TermRef::Cons(lvl, cell, head, tail));
}
TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant));
}
TermIterState::Var(lvl, cell, var_ptr) => {
return Some(TermRef::Var(lvl, cell, var_ptr));
}
};
}
None
}
}
#[derive(Debug)]
pub(crate) struct FactIterator<'a> {
state_queue: VecDeque<TermIterState<'a>>,
iterable_root: RootIterationPolicy,
}
impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue
.push_back(TermIterState::subterm_to_state(lvl, term));
}
pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
let state_queue = terms
.iter()
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
.collect();
FactIterator {
state_queue,
iterable_root: RootIterationPolicy::NotIterated,
}
}
fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
let states = match term {
Term::AnonVar => {
vec![TermIterState::AnonVar(Level::Root)]
}
Term::Clause(cell, name, terms) => {
vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
}
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
Level::Root,
cell,
head.as_ref(),
tail.as_ref(),
)],
Term::PartialString(cell, string, tail) => {
vec![TermIterState::InitialPartialString(
Level::Root,
cell,
string.clone(),
tail,
)]
}
Term::CompleteString(cell, string) => {
vec![TermIterState::CompleteString(
Level::Root,
cell,
string.clone(),
)]
}
Term::Literal(cell, constant) => {
vec![TermIterState::Literal(Level::Root, cell, constant)]
}
Term::Var(cell, var_ptr) => {
vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
}
};
FactIterator {
state_queue: VecDeque::from(states),
iterable_root,
}
}
}
impl<'a> Iterator for FactIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_queue.pop_front() {
match state {
TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl));
}
TermIterState::Clause(lvl, _, cell, name, child_terms) => {
for child_term in child_terms {
self.push_subterm(lvl.child_level(), child_term);
}
match lvl {
Level::Root if !self.iterable_root.iterable() => continue,
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
};
}
TermIterState::InitialCons(lvl, cell, head, tail) => {
self.push_subterm(Level::Deep, head);
self.push_subterm(Level::Deep, tail);
return Some(TermRef::Cons(lvl, cell, head, tail));
}
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
self.push_subterm(Level::Deep, tail);
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
}
TermIterState::CompleteString(lvl, cell, atom) => {
return Some(TermRef::CompleteString(lvl, cell, atom));
}
TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant))
}
TermIterState::Var(lvl, cell, var_ptr) => {
return Some(TermRef::Var(lvl, cell, var_ptr));
}
_ => {}
}
}
None
}
}
pub(crate) fn post_order_iter(term: &Term) -> QueryIterator<'_> {
QueryIterator::from_term(term)
}
pub(crate) fn breadth_first_iter(
term: &Term,
iterable_root: RootIterationPolicy,
) -> FactIterator<'_> {
FactIterator::new(term, iterable_root)
}
#[derive(Debug, Copy, Clone)]
enum ClauseIteratorState<'a> {
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
}
#[derive(Debug, Clone)]
pub(crate) enum ClauseItem<'a> {
FirstBranch(usize),
NextBranch,
BranchEnd(usize),
Chunk { terms: &'a VecDeque<QueryTerm> },
}
#[derive(Debug)]
pub(crate) struct ClauseIterator<'a> {
state_stack: Vec<ClauseIteratorState<'a>>,
remaining_chunks_on_stack: usize,
}
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
if chunk_vec.len() == 1 {
if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
return ClauseIteratorState::RemainingBranches(branches, 0);
}
}
ClauseIteratorState::RemainingChunks(chunk_vec, 0)
}
impl<'a> ClauseIterator<'a> {
pub fn new(clauses: &'a ChunkedTermVec) -> Self {
match state_from_chunked_terms(&clauses.chunk_vec) {
state @ ClauseIteratorState::RemainingBranches(..) => Self {
state_stack: vec![state],
remaining_chunks_on_stack: 0,
},
state @ ClauseIteratorState::RemainingChunks(..) => Self {
state_stack: vec![state],
remaining_chunks_on_stack: 1,
},
}
}
#[inline(always)]
pub fn in_tail_position(&self) -> bool {
self.remaining_chunks_on_stack == 0
}
fn branch_end_depth(&mut self) -> usize {
let mut depth = 1;
while let Some(state) = self.state_stack.pop() {
match state {
ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
depth += 1;
}
_ => {
self.state_stack.push(state);
break;
}
}
}
depth
}
}
impl<'a> Iterator for ClauseIterator<'a> {
type Item = ClauseItem<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_stack.pop() {
match state {
ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
if focus + 1 < chunks.len() {
self.state_stack
.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
} else {
self.remaining_chunks_on_stack -= 1;
}
match &chunks[focus] {
ChunkedTerms::Branch(branches) => {
self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0));
}
ChunkedTerms::Chunk { ref terms } => {
return Some(ClauseItem::Chunk { terms });
}
}
}
ClauseIteratorState::RemainingChunks(chunks, focus) => {
debug_assert_eq!(chunks.len(), focus);
}
ClauseIteratorState::RemainingBranches(branches, focus)
if focus < branches.len() =>
{
self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, focus + 1));
let state = state_from_chunked_terms(&branches[focus]);
if let ClauseIteratorState::RemainingChunks(..) = &state {
self.remaining_chunks_on_stack += 1;
}
self.state_stack.push(state);
return if focus == 0 {
Some(ClauseItem::FirstBranch(branches.len()))
} else {
Some(ClauseItem::NextBranch)
};
}
ClauseIteratorState::RemainingBranches(branches, focus) => {
debug_assert_eq!(branches.len(), focus);
return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
}
}
}
None
}
}

View File

@@ -1,51 +0,0 @@
use std::cell::{Cell};
use std::vec::{Vec};
pub type Var = String;
pub type Atom = String;
#[derive(Debug)]
pub enum TopLevel {
Fact(Term),
Query(Term)
}
#[derive(Debug)]
pub enum Term {
Atom(Cell<usize>, Atom),
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
Var(Cell<usize>, Var)
}
pub enum FactInstruction {
GetStructure(Atom, usize, usize),
UnifyVariable(usize),
UnifyValue(usize)
}
pub enum QueryInstruction {
PutStructure(Atom, usize, usize),
SetVariable(usize),
SetValue(usize),
}
pub type CompiledFact = Vec<FactInstruction>;
pub type CompiledQuery = Vec<QueryInstruction>;
#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
HeapCell(usize),
RegNum(usize)
}
impl Term {
pub fn set_cell(&self, cell_num: usize) {
match self {
&Term::Atom(ref cell, _) => cell.set(cell_num),
&Term::Clause(ref cell, _, _) => cell.set(cell_num),
&Term::Var(ref cell, _) => cell.set(cell_num)
};
}
}

View File

@@ -1,126 +0,0 @@
use l0::ast::{Atom, Term, FactInstruction, QueryInstruction, Var};
use l0::iterators::{BreadthFirstIterator, PostOrderIterator};
use std::collections::{HashSet};
use std::fmt;
use std::vec::{Vec};
impl fmt::Display for QueryInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&QueryInstruction::PutStructure(ref a, ref s, ref r) =>
write!(f, "put_structure {}/{}, X{}", a, s, r),
&QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable X{}", r),
&QueryInstruction::SetValue(ref r) =>
write!(f, "set_value X{}", r),
}
}
}
impl fmt::Display for FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&FactInstruction::GetStructure(ref a, ref s, ref r) =>
write!(f, "get_structure {}/{}, X{}", a, s, r),
&FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable X{}", r),
&FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value X{}", r)
}
}
}
pub trait CompilationTarget<'a> {
type Iterator : Iterator<Item=&'a Term>;
fn iter(term: &'a Term) -> Self::Iterator;
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self;
fn to_value(cell_num: usize) -> Self;
fn to_variable(cell_num: usize) -> Self;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
type Iterator = BreadthFirstIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.breadth_first_iter()
}
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
FactInstruction::GetStructure(name, arity, cell_num)
}
fn to_value(cell_num: usize) -> Self {
FactInstruction::UnifyValue(cell_num)
}
fn to_variable(cell_num: usize) -> Self {
FactInstruction::UnifyVariable(cell_num)
}
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
type Iterator = PostOrderIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter()
}
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
QueryInstruction::PutStructure(name, arity, cell_num)
}
fn to_value(cell_num: usize) -> Self {
QueryInstruction::SetValue(cell_num)
}
fn to_variable(cell_num: usize) -> Self {
QueryInstruction::SetVariable(cell_num)
}
}
fn subterm_to_instr<'a, Target>(subterm: &'a Term,
bindings: &mut HashSet<&'a Var>)
-> Target
where Target: CompilationTarget<'a>
{
match subterm {
&Term::Atom(ref cell_num, _) =>
Target::to_value(cell_num.get()),
&Term::Var(ref cell_num, ref atom) if bindings.contains(atom) =>
Target::to_value(cell_num.get()),
&Term::Var(ref cell_num, ref atom) => {
bindings.insert(atom);
Target::to_variable(cell_num.get())
},
&Term::Clause(ref cell_num, _, _) =>
Target::to_value(cell_num.get())
}
}
pub fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
where Target: CompilationTarget<'a>
{
let mut iter = Target::iter(term);
let mut target = Vec::<Target>::new();
let mut bindings = HashSet::new();
while let Some(term) = iter.next() {
match term {
&Term::Atom(ref cell_num, ref atom) =>
target.push(Target::to_structure(atom.clone(), 0, cell_num.get())),
&Term::Clause(ref cell_num, ref atom, ref terms) => {
target.push(Target::to_structure(atom.clone(), 0, cell_num.get()));
for subterm in terms {
target.push(subterm_to_instr(subterm.as_ref(), &mut bindings));
}
},
_ => {},
};
}
target
}

View File

@@ -1,98 +0,0 @@
use l0::ast::{Term};
use std::collections::{VecDeque};
use std::vec::{Vec};
enum DepthFirstIteratorState<'a> {
// child no., the containing clause, its vector.
Clause(usize, &'a Term, &'a Vec<Box<Term>>),
NonClause(&'a Term)
}
pub struct PostOrderIterator<'a> {
state_stack: Vec<DepthFirstIteratorState<'a>>
}
impl<'a> PostOrderIterator<'a> {
fn push_clause(&mut self,
child_num: usize,
term: &'a Term,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(DepthFirstIteratorState::Clause(child_num,
term,
child_terms));
}
fn render_new_state(term: &'a Term) -> DepthFirstIteratorState<'a> {
match term {
&Term::Clause(_, _, ref child_terms) =>
DepthFirstIteratorState::Clause(0, term, child_terms),
_ => DepthFirstIteratorState::NonClause(term)
}
}
fn push_term(&mut self, term: &'a Term) {
self.state_stack.push(Self::render_new_state(term));
}
}
impl<'a> Iterator for PostOrderIterator<'a> {
type Item = &'a Term;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
DepthFirstIteratorState::Clause(child_num, term, child_terms) => {
if child_num == child_terms.len() {
return Some(term);
} else {
self.push_clause(child_num + 1, term, child_terms);
self.push_term(child_terms[child_num].as_ref());
}
},
DepthFirstIteratorState::NonClause(term) => return Some(term),
};
}
None
}
}
pub struct BreadthFirstIterator<'a> {
state_queue : VecDeque<&'a Term>
}
impl<'a> Iterator for BreadthFirstIterator<'a> {
type Item = &'a Term;
fn next(&mut self) -> Option<Self::Item> {
if let Some(term) = self.state_queue.pop_front() {
if let &Term::Clause(_, _, ref child_terms) = term {
for term in child_terms {
self.state_queue.push_back(term);
}
return Some(term);
}
return Some(term);
}
None
}
}
impl<'a> Term {
pub fn post_order_iter(&'a self) -> PostOrderIterator<'a> {
let initial_state = PostOrderIterator::render_new_state(self);
PostOrderIterator { state_stack: vec![initial_state] }
}
pub fn breadth_first_iter(&'a self) -> BreadthFirstIterator<'a> {
let mut queue = VecDeque::new();
queue.push_back(self);
BreadthFirstIterator { state_queue: queue }
}
}

View File

@@ -1,31 +0,0 @@
use std::cell::{Cell};
use l0::ast::{Atom, Term, TopLevel, Var};
grammar;
pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t),
<t:Term> "." => TopLevel::Fact(t),
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t),
};
Term : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts;
ts.push(t);
Term::Clause(Cell::new(0), a, ts)
},
<Atom> => Term::Atom(Cell::new(0), <>),
<Var> => Term::Var(Cell::new(0), <>),
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,238 +0,0 @@
use l0::ast::{Addr, Atom, CompiledFact, FactInstruction, QueryInstruction};
use std::vec::{Vec};
#[derive(Clone)]
enum HeapCell {
NamedStr(usize, Atom),
Ref(usize),
Str(usize),
}
#[derive(Clone, Copy)]
enum MachineMode {
Read,
Write
}
type Heap = Vec<HeapCell>;
type Registers = Vec<HeapCell>;
pub struct Machine {
h : usize,
s : usize,
pub fail : bool,
heap : Heap,
mode : MachineMode,
pub program : Option<CompiledFact>,
registers : Registers
}
impl Machine {
pub fn new() -> Machine {
Machine { h : 0,
s : 0,
fail : false,
heap : Vec::with_capacity(256),
mode : MachineMode::Write,
program : None,
registers : vec![HeapCell::Ref(0); 33] }
}
fn lookup(&self, a: Addr) -> &HeapCell {
match a {
Addr::HeapCell(hc) => &self.heap[hc],
Addr::RegNum(reg) => &self.registers[reg]
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
if let &HeapCell::Ref(value) = self.lookup(a) {
if let Addr::HeapCell(av) = a {
if value != av {
a = Addr::HeapCell(value);
continue;
}
}
}
return a;
};
}
fn is_unbound(hc: &HeapCell, index: usize) -> bool {
match hc {
&HeapCell::Ref(r) => r == index,
_ => false
}
}
//TODO: try to compress this function. currently it is dog shit.
fn bind(&mut self, a: Addr, val: usize) {
let mut a = a;
loop {
match a {
Addr::RegNum(reg) => {
if let HeapCell::Ref(hc) = self.registers[reg] {
a = Addr::HeapCell(hc);
} else if Machine::is_unbound(&self.heap[val], val) {
self.heap[val] = self.registers[reg].clone();
break;
} else {
self.fail = true;
break;
}
},
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
self.heap[hc] = HeapCell::Ref(val);
break;
},
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
self.heap[val] = HeapCell::Ref(hc);
break;
},
_ => {
self.fail = true;
break;
}
};
}
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl : Vec<Addr> = vec![a1, a2];
self.fail = false;
while !(pdl.is_empty() || self.fail) {
let d1 = self.deref(pdl.pop().unwrap());
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (self.lookup(d1), self.lookup(d2)) {
(&HeapCell::Ref(hc), _) =>
self.bind(d2, hc),
(_, &HeapCell::Ref(hc)) =>
self.bind(d1, hc),
(&HeapCell::Str(a1), &HeapCell::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCell::NamedStr(n1, ref f1) = r1 {
if let &HeapCell::NamedStr(n2, ref f2) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
},
_ => self.fail = true,
};
}
}
}
pub fn execute_query_instr<'a, 'b : 'a>(&'a mut self, instr: &'b QueryInstruction) {
match instr {
&QueryInstruction::PutStructure(ref name, arity, reg) => {
self.heap.push(HeapCell::Str(self.h + 1));
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
self.registers[reg] = self.heap[self.h].clone();
self.h += 2;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCell::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
},
}
}
pub fn execute_fact_instr<'a, 'b : 'a>(&'a mut self, instr: &'b FactInstruction) {
match instr {
&FactInstruction::GetStructure(ref name, arity, reg) => {
let addr = self.deref(Addr::RegNum(reg));
match self.lookup(addr) {
&HeapCell::Str(a) => {
let result = &self.heap[a];
if let &HeapCell::NamedStr(named_arity, ref named_str) = result {
if arity == named_arity && *name == *named_str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
&HeapCell::Ref(r) => {
self.heap.push(HeapCell::Str(self.h + 1));
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
let h = self.h;
self.bind(Addr::HeapCell(r), h);
self.h += 2;
self.mode = MachineMode::Write;
},
_ => {
self.fail = true;
}
};
},
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
MachineMode::Write => {
self.heap.push(HeapCell::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
}
};
self.s += 1;
},
&FactInstruction::UnifyValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
MachineMode::Write => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
}
};
self.s += 1;
}
}
}
pub fn reset_heap(&mut self) {
let program = self.program.take();
*self = Machine::new();
self.program = program;
}
}

View File

@@ -1,7 +0,0 @@
mod l0_parser;
pub mod ast;
pub mod iterators;
pub mod parser;
pub mod codegen;
pub mod machine;

View File

@@ -1,52 +0,0 @@
use l0::ast::{Term, TopLevel, Var};
use l0::l0_parser::{parse_TopLevel};
use std::collections::{HashMap};
extern crate lalrpop_util as __lalrpop_util;
pub type ParseResult<'a> =
Result<TopLevel, __lalrpop_util::ParseError<usize,(usize, &'a str),()>>;
pub fn parse_top_level<'a>(input: &'a str) -> ParseResult {
let result = parse_TopLevel(&*input);
if let Ok(result) = result {
return Ok(mark_cells(result));
}
result
}
#[inline]
fn mark_cells(tl: TopLevel) -> TopLevel {
match tl {
TopLevel::Fact(term) => TopLevel::Fact(mark_term_cells(term)),
TopLevel::Query(term) => TopLevel::Query(mark_term_cells(term))
}
}
fn mark_term_cells(term: Term) -> Term {
let mut cell_num = 1;
{
let mut bindings: HashMap<&Var, usize> = HashMap::new();
let mut iter = term.breadth_first_iter();
while let Some(term) = iter.next() {
if let &Term::Var(ref cell, ref var) = term {
let cell_num_in_map = bindings.entry(var).or_insert(cell_num);
if *cell_num_in_map != cell_num {
cell.set(*cell_num_in_map);
continue;
}
}
term.set_cell(cell_num);
cell_num += 1;
}
}
term
}

View File

@@ -1,123 +0,0 @@
use std::cell::Cell;
use std::fmt;
use std::vec::Vec;
pub type Var = String;
pub type Atom = String;
pub enum TopLevel {
Fact(Term),
Query(Term)
}
#[derive(Clone, Copy)]
pub enum Level {
Shallow, Deep
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Level::Shallow => write!(f, "A"),
&Level::Deep => write!(f, "X")
}
}
}
#[derive(Clone, Copy)]
pub enum Reg {
ArgAndNorm(usize, usize),
Norm(usize)
}
impl Reg {
pub fn has_arg(&self) -> bool {
match self {
&Reg::ArgAndNorm(_, _) => true,
_ => false
}
}
pub fn norm(&self) -> usize {
match self {
&Reg::ArgAndNorm(_, norm) | &Reg::Norm(norm) => norm
}
}
}
pub enum Term {
Atom(Cell<usize>, Atom),
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
Var(Cell<Reg>, Var)
}
pub enum TermRef<'a> {
Atom(Level, &'a Cell<usize>, &'a Atom),
Clause(Level, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<Reg>, &'a Var)
}
#[derive(Clone)]
pub enum FactInstruction {
GetStructure(Level, Atom, usize, usize),
GetValue(usize, usize),
GetVariable(usize, usize),
Proceed,
UnifyVariable(usize),
UnifyValue(usize)
}
pub enum QueryInstruction {
Call(Atom, usize),
PutStructure(Level, Atom, usize, usize),
PutValue(usize, usize),
PutVariable(usize, usize),
SetVariable(usize),
SetValue(usize),
}
pub type CompiledFact = Vec<FactInstruction>;
pub type CompiledQuery = Vec<QueryInstruction>;
#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
HeapCell(usize),
RegNum(usize)
}
#[derive(Clone)]
pub enum HeapCellValue {
NamedStr(usize, Atom),
Ref(usize),
Str(usize),
}
pub type Heap = Vec<HeapCellValue>;
pub type Registers = Vec<HeapCellValue>;
impl Term {
pub fn subterms(&self) -> usize {
match self {
&Term::Clause(_, _, ref terms) => terms.len(),
_ => 1
}
}
pub fn name(&self) -> &Atom {
match self {
&Term::Atom(_, ref atom)
| &Term::Var(_, ref atom)
| &Term::Clause(_, ref atom, _) => atom
}
}
pub fn arity(&self) -> usize {
match self {
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
&Term::Clause(_, _, ref child_terms) => child_terms.len()
}
}
}

View File

@@ -1,312 +0,0 @@
use l1::ast::{Atom, CompiledFact, CompiledQuery, FactInstruction,
Level, QueryInstruction, Reg, Term, TermRef, Var};
use l1::iterators::{FactIterator, QueryIterator};
use std::cell::Cell;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;
impl fmt::Display for QueryInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&QueryInstruction::Call(ref name, ref arity) =>
write!(f, "call {}/{}", name, arity),
&QueryInstruction::PutStructure(ref lvl, ref a, ref s, ref r) =>
write!(f, "put_structure {}/{}, {}{}", a, s, lvl, r),
&QueryInstruction::PutValue(ref a, ref x) =>
write!(f, "put_value X{}, A{}", x, a),
&QueryInstruction::PutVariable(ref a, ref x) =>
write!(f, "put_variable X{}, A{}", x, a),
&QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable X{}", r),
&QueryInstruction::SetValue(ref r) =>
write!(f, "set_value X{}", r),
}
}
}
impl fmt::Display for FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&FactInstruction::GetStructure(ref lvl, ref a, ref s, ref r) =>
write!(f, "get_structure {}/{}, {}{}", a, s, lvl, r),
&FactInstruction::GetValue(ref a, ref x) =>
write!(f, "get_value X{}, A{}", x, a),
&FactInstruction::GetVariable(ref a, ref x) =>
write!(f, "get_variable X{}, A{}", x, a),
&FactInstruction::Proceed =>
write!(f, "proceed"),
&FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable X{}", r),
&FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value X{}", r)
}
}
}
struct TermMarker<'a> {
bindings: HashMap<&'a Var, Reg>,
arg_c: usize,
norm_c: usize
}
impl<'a> TermMarker<'a> {
fn new(term: &'a Term) -> TermMarker<'a> {
TermMarker { bindings: HashMap::new(),
arg_c: 1,
norm_c: term.subterms() + 1 }
}
fn contains_var(&self, var: &'a Var) -> bool {
self.bindings.contains_key(var)
}
fn get(&self, var: &'a Var) -> Reg {
*self.bindings.get(var).unwrap()
}
fn insert(&mut self, var: &'a Var, r: Reg) {
self.bindings.insert(var, r);
}
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<usize>) {
if cell.get() == 0 {
match lvl {
Level::Deep => {
let norm = self.norm_c;
self.norm_c += 1;
cell.set(norm);
},
Level::Shallow => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(arg);
}
};
}
}
fn mark_var(&mut self, lvl: Level, var: &'a Var) -> Reg {
if self.contains_var(var) {
let reg = self.get(var);
match lvl {
Level::Deep => Reg::Norm(reg.norm()),
Level::Shallow if reg.has_arg() => {
let arg = self.arg_c;
self.arg_c += 1;
Reg::ArgAndNorm(arg, reg.norm())
},
Level::Shallow => {
let norm = reg.norm();
let reg = Reg::ArgAndNorm(self.arg_c, norm);
self.arg_c += 1;
self.insert(var, reg);
reg
}
}
} else {
let reg = match lvl {
Level::Deep => Reg::Norm(self.norm_c),
Level::Shallow => {
let reg = Reg::ArgAndNorm(self.arg_c, self.norm_c);
self.arg_c += 1;
reg
}
};
self.norm_c += 1;
self.insert(var, reg);
reg
}
}
}
trait CompilationTarget<'a> {
type Iterator : Iterator<Item=TermRef<'a>>;
fn iter(&'a Term) -> Self::Iterator;
fn to_structure(Level, Atom, usize, usize) -> Self;
fn argument_to_variable(usize, usize) -> Self;
fn argument_to_value(usize, usize) -> Self;
fn subterm_to_variable(usize) -> Self;
fn subterm_to_value(usize) -> Self;
fn clause_arg_to_instr(usize) -> Self;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
type Iterator = FactIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.breadth_first_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
FactInstruction::GetStructure(lvl, atom, arity, cell_num)
}
fn argument_to_variable(arg: usize, val: usize) -> Self {
FactInstruction::GetVariable(arg, val)
}
fn argument_to_value(arg: usize, val: usize) -> Self {
FactInstruction::GetValue(arg, val)
}
fn subterm_to_variable(val: usize) -> Self {
FactInstruction::UnifyVariable(val)
}
fn subterm_to_value(val: usize) -> Self {
FactInstruction::UnifyValue(val)
}
fn clause_arg_to_instr(val: usize) -> Self {
FactInstruction::UnifyVariable(val)
}
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
type Iterator = QueryIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
QueryInstruction::PutStructure(lvl, atom, arity, cell_num)
}
fn argument_to_variable(arg: usize, val: usize) -> Self {
QueryInstruction::PutVariable(arg, val)
}
fn argument_to_value(arg: usize, val: usize) -> Self {
QueryInstruction::PutValue(arg, val)
}
fn subterm_to_variable(val: usize) -> Self {
QueryInstruction::SetVariable(val)
}
fn subterm_to_value(val: usize) -> Self {
QueryInstruction::SetValue(val)
}
fn clause_arg_to_instr(val: usize) -> Self {
QueryInstruction::SetValue(val)
}
}
fn to_structure<'a, Target>(tm: &mut TermMarker<'a>,
lvl: Level,
name: &'a Atom,
cell: &'a Cell<usize>,
arity: usize)
-> Target
where Target: CompilationTarget<'a>
{
tm.mark_non_var(lvl, cell);
Target::to_structure(lvl, name.clone(), arity, cell.get())
}
fn non_var_subterm<'a, Target>(tm: &mut TermMarker<'a>, cell: &'a Cell<usize>)
-> Target
where Target: CompilationTarget<'a>
{
tm.mark_non_var(Level::Deep, cell);
Target::clause_arg_to_instr(cell.get())
}
fn var_term<'a, Target>(tm: &mut TermMarker<'a>,
lvl: Level,
cell: &'a Cell<Reg>,
var: &'a Var)
-> Target
where Target: CompilationTarget<'a>
{
if !tm.contains_var(var) {
let reg = tm.mark_var(lvl, var);
cell.set(reg);
match reg {
Reg::ArgAndNorm(arg, norm) =>
Target::argument_to_variable(arg, norm),
Reg::Norm(norm) =>
Target::subterm_to_variable(norm)
}
} else {
let reg = tm.mark_var(lvl, var);
cell.set(reg);
match reg {
Reg::ArgAndNorm(arg, norm) =>
Target::argument_to_value(arg, norm),
Reg::Norm(norm) =>
Target::subterm_to_value(norm)
}
}
}
fn subterm_to_instr<'a, Target>(tm: &mut TermMarker<'a>, subterm: &'a Term)
-> Target
where Target: CompilationTarget<'a>
{
match subterm {
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
non_var_subterm(tm, cell),
&Term::Var(ref cell, ref var) =>
var_term(tm, Level::Deep, cell, var)
}
}
fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
where Target: CompilationTarget<'a>
{
let iter = Target::iter(term);
let mut target = Vec::<Target>::new();
let mut marker = TermMarker::new(term);
for term in iter {
match term {
TermRef::Atom(lvl, term, atom) =>
target.push(to_structure(&mut marker, lvl, atom, term, 0)),
TermRef::Clause(lvl, term, atom, terms) => {
target.push(to_structure(&mut marker, lvl, atom, term, terms.len()));
for subterm in terms {
target.push(subterm_to_instr(&mut marker, subterm.as_ref()));
}
},
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
target.push(var_term(&mut marker, lvl, cell, var)),
_ => {}
};
}
target
}
pub fn compile_fact(term: &Term) -> CompiledFact {
let mut compiled_fact = compile_target(term);
compiled_fact.push(FactInstruction::Proceed);
compiled_fact
}
pub fn compile_query<'a>(term: &'a Term) -> CompiledQuery {
let mut compiled_query = compile_target(term);
if let &Term::Clause(_, ref atom, ref terms) = term {
compiled_query.push(QueryInstruction::Call(atom.clone(), terms.len()));
}
compiled_query
}

View File

@@ -1,175 +0,0 @@
use l1::ast::{Atom, Level, Reg, Term, TermRef, Var};
use std::cell::Cell;
use std::collections::VecDeque;
use std::vec::Vec;
enum IteratorState<'a> {
Atom(Level, &'a Cell<usize>, &'a Atom),
Clause(Level, usize, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
IsolatedAtom(&'a Cell<usize>, &'a Atom),
IsolatedVar(&'a Cell<Reg>, &'a Var),
RootClause(usize, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<Reg>, &'a Var)
}
impl<'a> IteratorState<'a> {
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
{
match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::Atom(lvl, cell, atom),
&Term::Clause(ref cell, ref atom, ref child_terms) =>
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
&Term::Var(ref cell, ref var) =>
IteratorState::Var(lvl, cell, var)
}
}
}
pub struct QueryIterator<'a> {
state_stack: Vec<IteratorState<'a>>
}
impl<'a> QueryIterator<'a> {
fn push_clause(&mut self,
lvl: Level,
child_num: usize,
cell: &'a Cell<usize>,
name: &'a Atom,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::Clause(lvl,
child_num,
cell,
name,
child_terms));
}
fn push_root_clause(&mut self,
child_num: usize,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
}
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack.push(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> QueryIterator<'a> {
let state = match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::IsolatedAtom(cell, atom),
&Term::Clause(_, _, ref terms) =>
IteratorState::RootClause(0, terms),
&Term::Var(ref cell, ref var) =>
IteratorState::IsolatedVar(cell, var)
};
QueryIterator { state_stack: vec![state] }
}
}
impl<'a> Iterator for QueryIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
if child_num == child_terms.len() {
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
} else {
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
}
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(child_num, child_terms) => {
if child_num == child_terms.len() {
return None;
} else {
self.push_root_clause(child_num + 1, child_terms);
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
};
}
None
}
}
pub struct FactIterator<'a> {
state_queue: VecDeque<IteratorState<'a>>,
}
impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue.push_back(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> FactIterator<'a> {
let states = match term {
&Term::Atom(ref cell, ref atom) =>
vec![IteratorState::IsolatedAtom(cell, atom)],
&Term::Clause(_, _, ref terms) =>
vec![IteratorState::RootClause(0, terms)],
&Term::Var(ref cell, ref var) =>
vec![IteratorState::IsolatedVar(cell, var)]
};
FactIterator { state_queue: VecDeque::from(states) }
}
}
impl<'a> Iterator for FactIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_queue.pop_front() {
match state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Deep, child_term);
}
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(_, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Shallow, child_term);
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
}
}
None
}
}
impl Term {
pub fn post_order_iter(&self) -> QueryIterator {
QueryIterator::new(self)
}
pub fn breadth_first_iter(&self) -> FactIterator {
FactIterator::new(self)
}
}

View File

@@ -1,32 +0,0 @@
use std::cell::Cell;
use l1::ast::{Atom, Reg, Term, TopLevel, Var};
grammar;
pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t),
<t:Term> "." => TopLevel::Fact(t),
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t),
};
Term : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts;
ts.push(t);
Term::Clause(Cell::new(0), a, ts)
},
<Atom> => Term::Atom(Cell::new(0), <>),
<Var> => Term::Var(Cell::new(Reg::Norm(0)), <>)
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,309 +0,0 @@
use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
FactInstruction, Heap, HeapCellValue, QueryInstruction,
Registers};
use std::collections::HashMap;
use std::vec::Vec;
#[derive(Clone, Copy)]
enum MachineMode {
Read,
Write
}
pub struct Machine {
h : usize,
s : usize,
p : usize,
code : CompiledFact,
code_dir : HashMap<(Atom, usize), usize>,
fail : bool,
heap : Heap,
mode : MachineMode,
registers : Registers
}
impl Machine {
pub fn new() -> Machine {
Machine { h : 0,
s : 0,
p : 0,
code : Vec::new(),
code_dir : HashMap::new(),
fail : false,
heap : Vec::with_capacity(256),
mode : MachineMode::Write,
registers : vec![HeapCellValue::Ref(0); 32] }
}
pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
{
let index = self.code.len();
self.code.append(&mut fact);
self.code_dir.insert((name, arity), index);
}
pub fn failed(&self) -> bool {
self.fail
}
fn lookup(&self, a: Addr) -> &HeapCellValue {
match a {
Addr::HeapCell(hc) => &self.heap[hc],
Addr::RegNum(reg) => &self.registers[reg]
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
if let &HeapCellValue::Ref(value) = self.lookup(a) {
if let Addr::HeapCell(av) = a {
if value != av {
a = Addr::HeapCell(value);
continue;
}
} else {
a = Addr::HeapCell(value);
continue;
}
}
return a;
};
}
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
match hc {
&HeapCellValue::Ref(r) => r == index,
_ => false
}
}
//TODO: try to compress this function.
fn bind(&mut self, a: Addr, val: usize) {
let mut a = a;
loop {
match a {
Addr::RegNum(reg) => {
if let HeapCellValue::Ref(hc) = self.registers[reg] {
a = Addr::HeapCell(hc);
} else if Machine::is_unbound(&self.heap[val], val) {
self.heap[val] = self.registers[reg].clone();
break;
} else {
self.fail = true;
break;
}
},
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
self.heap[hc] = HeapCellValue::Ref(val);
break;
},
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
self.heap[val] = HeapCellValue::Ref(hc);
break;
},
_ => {
self.fail = true;
break;
}
};
}
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl = vec![a1, a2];
self.fail = false;
while !(pdl.is_empty() || self.fail) {
let d1 = self.deref(pdl.pop().unwrap());
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (self.lookup(d1), self.lookup(d2)) {
(&HeapCellValue::Ref(hc), _) =>
self.bind(d2, hc),
(_, &HeapCellValue::Ref(hc)) =>
self.bind(d1, hc),
(&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
},
_ => self.fail = true,
};
}
}
}
pub fn execute_fact(&mut self) {
loop {
if let &FactInstruction::Proceed = &self.code[self.p] {
break;
} else if self.fail {
break;
}
let fact_instr = self.code[self.p].clone();
self.execute_fact_instr(fact_instr);
}
}
pub fn execute_query(&mut self, query: &CompiledQuery) {
for instr in query {
self.execute_query_instr(instr);
if self.fail {
break;
}
}
}
fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
match instr {
&QueryInstruction::Call(ref name, arity) => {
// why is Option<&T> not Deref?!?!?
// is it because if the value is None, there's nothing to
// dereference?
let compiled_fact_index =
self.code_dir.get(&(name.clone(), arity))
.map(|index| *index);
match compiled_fact_index {
Some(compiled_fact_index) => {
self.p = compiled_fact_index;
self.execute_fact();
},
None => self.fail = true,
};
}
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
self.registers[reg] = self.heap[self.h].clone();
self.h += 2;
},
&QueryInstruction::PutValue(arg, norm) =>
self.registers[arg] = self.registers[norm].clone(),
&QueryInstruction::PutVariable(arg, norm) => {
self.heap.push(HeapCellValue::Ref(self.h));
self.registers[norm] = self.heap[self.h].clone();
self.registers[arg] = self.heap[self.h].clone();
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCellValue::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
},
}
}
fn execute_fact_instr(&mut self, instr: FactInstruction) {
match instr {
FactInstruction::Proceed => return,
FactInstruction::GetStructure(_, name, arity, reg) => {
let addr = self.deref(Addr::RegNum(reg));
match self.lookup(addr) {
&HeapCellValue::Str(a) => {
let result = &self.heap[a];
if let &HeapCellValue::NamedStr(named_arity, ref named_str) = result {
if arity == named_arity && *name == *named_str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
&HeapCellValue::Ref(r) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name));
let h = self.h;
self.bind(Addr::HeapCell(r), h);
self.h += 2;
self.mode = MachineMode::Write;
},
_ => {
self.fail = true;
}
};
},
FactInstruction::GetVariable(arg, norm) =>
self.registers[norm] = self.registers[arg].clone(),
FactInstruction::GetValue(arg, norm) =>
self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
MachineMode::Write => {
self.heap.push(HeapCellValue::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
}
};
self.s += 1;
},
FactInstruction::UnifyValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
MachineMode::Write => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
}
};
self.s += 1;
}
}
self.p += 1;
}
pub fn reset_machine_state(&mut self) {
self.h = 0;
self.s = 0;
self.p = 0;
self.fail = false;
self.heap = Vec::with_capacity(256);
self.mode = MachineMode::Write;
self.registers = vec![HeapCellValue::Ref(0); 32];
}
}

View File

@@ -1,5 +0,0 @@
pub mod ast;
pub mod iterators;
pub mod l1_parser;
pub mod codegen;
pub mod machine;

View File

@@ -1,253 +0,0 @@
use std::cell::Cell;
use std::fmt;
use std::ops::{Add, AddAssign};
use std::vec::Vec;
pub type Var = String;
pub type Atom = String;
pub enum TopLevel {
Fact(Term),
Rule(Rule),
Query(Term)
}
#[derive(Clone, Copy)]
pub enum Level {
Shallow, Deep
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Level::Shallow => write!(f, "A"),
&Level::Deep => write!(f, "X")
}
}
}
#[derive(Clone, Copy)]
pub enum RegType {
Perm(usize),
Temp(usize)
}
impl RegType {
pub fn reg_num(self) -> usize {
match self {
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
}
}
pub fn is_perm(self) -> bool {
match self {
RegType::Perm(_) => true,
_ => false
}
}
}
impl fmt::Display for VarReg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
write!(f, "Y{} A{}", reg, arg),
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
write!(f, "X{} A{}", reg, arg)
}
}
}
impl From<RegType> for Addr {
fn from(reg: RegType) -> Addr {
match reg {
RegType::Perm(reg) => Addr::StackCell(reg),
RegType::Temp(reg) => Addr::RegNum(reg)
}
}
}
impl fmt::Display for RegType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&RegType::Perm(val) => write!(f, "Y{}", val),
&RegType::Temp(val) => write!(f, "X{}", val)
}
}
}
#[derive(Clone, Copy)]
pub enum VarReg {
ArgAndNorm(RegType, usize),
Norm(RegType)
}
impl VarReg {
pub fn norm(self) -> RegType {
match self {
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
}
}
pub fn root_register(self) -> usize {
match self {
VarReg::ArgAndNorm(_, root) => root,
VarReg::Norm(root) => root.reg_num()
}
}
}
pub enum Term {
Atom(Cell<RegType>, Atom),
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
Var(Cell<VarReg>, Var)
}
pub struct Rule {
pub head: (Term, Term),
pub clauses: Vec<Term>
}
pub enum TermRef<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
}
pub enum FactInstruction {
GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
UnifyVariable(RegType),
UnifyValue(RegType)
}
pub enum QueryInstruction {
PutStructure(Level, Atom, usize, RegType),
PutValue(RegType, usize),
PutVariable(RegType, usize),
SetVariable(RegType),
SetValue(RegType)
}
pub enum ControlInstruction {
Allocate(usize),
Call(Atom, usize),
Deallocate,
Proceed
}
pub type CompiledFact = Vec<FactInstruction>;
pub type CompiledQuery = Vec<QueryInstruction>;
pub enum Line {
Control(ControlInstruction),
Fact(CompiledFact),
Query(CompiledQuery)
}
pub type Code = Vec<Line>;
#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
HeapCell(usize),
RegNum(usize),
StackCell(usize),
}
#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
NamedStr(usize, Atom),
Ref(usize),
Str(usize)
}
impl HeapCellValue {
pub fn as_ref(&self, focus: usize) -> HeapCellRef {
match self {
&HeapCellValue::Ref(r) => HeapCellRef::Ref(r),
&HeapCellValue::Str(s) => HeapCellRef::Str(s),
&HeapCellValue::NamedStr(_, _) => HeapCellRef::Str(focus)
}
}
}
#[derive(Copy, Clone)]
pub enum HeapCellRef {
Ref(usize),
Str(usize)
}
impl HeapCellRef {
pub fn heap_offset(&self) -> usize {
match self {
&HeapCellRef::Ref(r) | &HeapCellRef::Str(r) => r
}
}
}
impl From<HeapCellRef> for HeapCellValue {
fn from(hcr: HeapCellRef) -> HeapCellValue {
match hcr {
HeapCellRef::Ref(r) => HeapCellValue::Ref(r),
HeapCellRef::Str(s) => HeapCellValue::Str(s)
}
}
}
#[derive(Clone, Copy)]
pub enum CodePtr {
DirEntry(usize),
TopLevel
}
impl Add<usize> for CodePtr {
type Output = CodePtr;
fn add(self, rhs: usize) -> Self::Output {
match self {
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
CodePtr::TopLevel => CodePtr::TopLevel
}
}
}
impl AddAssign<usize> for CodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
_ => {}
}
}
}
pub type Heap = Vec<HeapCellValue>;
pub type Registers = Vec<HeapCellRef>;
impl Term {
pub fn subterms(&self) -> usize {
match self {
&Term::Clause(_, _, ref terms) => terms.len(),
_ => 1
}
}
pub fn name(&self) -> &Atom {
match self {
&Term::Atom(_, ref atom)
| &Term::Var(_, ref atom)
| &Term::Clause(_, ref atom, _) => atom
}
}
pub fn arity(&self) -> usize {
match self {
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
&Term::Clause(_, _, ref child_terms) => child_terms.len()
}
}
}

View File

@@ -1,469 +0,0 @@
use l2::ast::*;
use l2::iterators::{FactIterator, QueryIterator};
use std::cell::Cell;
use std::cmp::max;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;
impl fmt::Display for FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
write!(f, "get_structure {}/{}, {}", name, arity, r),
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
&FactInstruction::GetValue(ref x, ref a) =>
write!(f, "get_value {}, A{}", x, a),
&FactInstruction::GetVariable(ref x, ref a) =>
write!(f, "get_variable {}, A{}", x, a),
&FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable {}", r),
&FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value {}", r)
}
}
}
impl fmt::Display for QueryInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, {}", name, arity, r),
&QueryInstruction::PutValue(ref x, ref a) =>
write!(f, "put_value {}, A{}", x, a),
&QueryInstruction::PutVariable(ref x, ref a) =>
write!(f, "put_variable {}, A{}", x, a),
&QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable {}", r),
&QueryInstruction::SetValue(ref r) =>
write!(f, "set_value {}", r),
}
}
}
impl fmt::Display for ControlInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ControlInstruction::Allocate(num_cells) =>
write!(f, "allocate {}", num_cells),
&ControlInstruction::Call(ref name, ref arity) =>
write!(f, "call {}/{}", name, arity),
&ControlInstruction::Deallocate =>
write!(f, "deallocate"),
&ControlInstruction::Proceed =>
write!(f, "proceed")
}
}
}
trait CompilationTarget<'a> {
type Iterator : Iterator<Item=TermRef<'a>>;
fn iter(&'a Term) -> Self::Iterator;
fn to_structure(Level, Atom, usize, RegType) -> Self;
fn argument_to_variable(RegType, usize) -> Self;
fn argument_to_value(RegType, usize) -> Self;
fn subterm_to_variable(RegType) -> Self;
fn subterm_to_value(RegType) -> Self;
fn clause_arg_to_instr(RegType) -> Self;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
type Iterator = FactIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.breadth_first_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
FactInstruction::GetStructure(lvl, atom, arity, reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Self {
FactInstruction::GetVariable(arg, val)
}
fn argument_to_value(arg: RegType, val: usize) -> Self {
FactInstruction::GetValue(arg, val)
}
fn subterm_to_variable(val: RegType) -> Self {
FactInstruction::UnifyVariable(val)
}
fn subterm_to_value(val: RegType) -> Self {
FactInstruction::UnifyValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Self {
FactInstruction::UnifyVariable(val)
}
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
type Iterator = QueryIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
QueryInstruction::PutStructure(lvl, atom, arity, reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Self {
QueryInstruction::PutVariable(arg, val)
}
fn argument_to_value(arg: RegType, val: usize) -> Self {
QueryInstruction::PutValue(arg, val)
}
fn subterm_to_variable(val: RegType) -> Self {
QueryInstruction::SetVariable(val)
}
fn subterm_to_value(val: RegType) -> Self {
QueryInstruction::SetValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Self {
QueryInstruction::SetValue(val)
}
}
struct TermMarker<'a> {
bindings: HashMap<&'a Var, VarReg>,
arg_c: usize,
perm_c: usize,
temp_c: usize
}
impl<'a> TermMarker<'a> {
fn new() -> TermMarker<'a> {
TermMarker { bindings: HashMap::new(),
arg_c: 1,
perm_c: 1,
temp_c: 1 }
}
fn contains_var(&self, var: &'a Var) -> bool {
self.bindings.contains_key(var)
}
fn get(&self, var: &'a Var) -> VarReg {
*self.bindings.get(var).unwrap()
}
fn insert(&mut self, var: &'a Var, r: VarReg) {
self.bindings.insert(var, r);
}
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
let reg_type = cell.get();
if reg_type.reg_num() == 0 {
match lvl {
Level::Deep if reg_type.is_perm() => {
let perm = self.perm_c;
self.perm_c += 1;
cell.set(RegType::Perm(perm));
},
Level::Deep => {
let temp = self.temp_c;
self.temp_c += 1;
cell.set(RegType::Temp(temp));
},
Level::Shallow if reg_type.is_perm() => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(RegType::Perm(arg));
},
Level::Shallow => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(RegType::Temp(arg));
}
};
}
}
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
{
let reg = self.get(var);
match lvl {
Level::Deep => VarReg::Norm(reg.norm()),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
self.arg_c += 1;
self.insert(var, reg);
reg
}
}
}
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
{
let inner_reg = if reg.is_perm() {
let perm = self.perm_c;
self.perm_c += 1;
RegType::Perm(perm)
} else {
let temp = self.temp_c;
self.temp_c += 1;
RegType::Temp(temp)
};
let reg = match lvl {
Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
self.arg_c += 1;
reg
}
};
self.insert(var, reg);
reg
}
fn advance_at_header(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_c = max(term.subterms(), self.temp_c) + 1;
}
fn advance(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_c = term.subterms() + 1;
}
}
#[derive(Copy, Clone)]
enum TermStatus {
New, Old, Recurrent
}
pub struct CodeGenerator<'a> {
marker: TermMarker<'a>
}
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
impl<'a> CodeGenerator<'a> {
pub fn new() -> Self {
CodeGenerator { marker: TermMarker::new() }
}
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
&self.marker.bindings
}
fn to_structure<Target>(&mut self,
lvl: Level,
name: &'a Atom,
cell: &'a Cell<RegType>,
arity: usize)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, cell);
Target::to_structure(lvl, name.clone(), arity, cell.get())
}
fn var_term<Target>(&mut self,
lvl: Level,
cell: &'a Cell<VarReg>,
var: &'a Var)
-> Target
where Target: CompilationTarget<'a>
{
if !self.marker.contains_var(var) {
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
cell.set(reg);
match reg {
VarReg::ArgAndNorm(arg, norm) =>
Target::argument_to_variable(arg, norm),
VarReg::Norm(norm) =>
Target::subterm_to_variable(norm)
}
} else {
let reg = self.marker.mark_old_var(lvl, var);
cell.set(reg);
match reg {
VarReg::ArgAndNorm(arg, norm) =>
Target::argument_to_value(arg, norm),
VarReg::Norm(norm) =>
Target::subterm_to_value(norm)
}
}
}
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(Level::Deep, cell);
Target::clause_arg_to_instr(cell.get())
}
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
where Target: CompilationTarget<'a>
{
match subterm {
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
self.non_var_subterm(cell),
&Term::Var(ref cell, ref var) =>
self.var_term(Level::Deep, cell, var)
}
}
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
where Target: CompilationTarget<'a>
{
let iter = Target::iter(term);
let mut target = Vec::new();
for term in iter {
match term {
TermRef::Atom(lvl, term, atom) =>
target.push(self.to_structure(lvl, atom, term, 0)),
TermRef::Clause(lvl, term, atom, terms) => {
target.push(self.to_structure(lvl, atom, term, terms.len()));
for subterm in terms {
target.push(self.subterm_to_instr(subterm.as_ref()));
}
},
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
target.push(self.var_term(lvl, cell, var)),
_ => {}
};
}
target
}
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
where Iter : Iterator<Item=TermRef<'a>>
{
for term in iter {
if let TermRef::Var(_, reg_cell, var) = term {
let mut status = vs.entry(var)
.or_insert((TermStatus::New, Vec::new()));
status.1.push(reg_cell);
match status.0 {
TermStatus::Old => status.0 = TermStatus::Recurrent,
_ => {}
};
}
}
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
match *term_status {
TermStatus::New => *term_status = TermStatus::Old,
TermStatus::Recurrent => {
for cell_reg in cb.drain(0..) {
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
}
},
_ => {}
}
}
}
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut vfs = HashMap::new();
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
Self::mark_vars_in_term(iter, &mut vfs);
for term in clauses {
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
}
vfs
}
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
match term {
&Term::Atom(_, ref atom) => {
let call = ControlInstruction::Call(atom.clone(), 0);
compiled_query.push(Line::Control(call));
},
&Term::Clause(_, ref atom, ref terms) => {
let call = ControlInstruction::Call(atom.clone(), terms.len());
compiled_query.push(Line::Control(call));
},
_ => {}
}
}
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
let vfs = Self::mark_perm_vars(&rule);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut perm_vars = 0;
for &(term_status, _) in vfs.values() {
if let TermStatus::Recurrent = term_status {
perm_vars += 1;
}
}
let mut body = Vec::new();
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0)));
self.marker.advance_at_header(p1);
body.push(Line::Query(self.compile_target(p1)));
Self::add_conditional_call(&mut body, p1);
body = clauses.iter()
.map(|ref term| self.compile_query(term))
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
body
});
body.push(Line::Control(ControlInstruction::Deallocate));
body
}
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
let proceed = Line::Control(ControlInstruction::Proceed);
compiled_fact.push(proceed);
compiled_fact
}
pub fn compile_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
Self::add_conditional_call(&mut compiled_query, term);
compiled_query
}
}

View File

@@ -1,64 +0,0 @@
use l2::ast::*;
use std::vec::Vec;
#[derive(Clone, Copy)]
pub enum HeapCellView<'a> {
Str(usize, &'a Atom),
Var(usize)
}
pub struct HeapCellViewer<'a> {
heap: &'a Heap,
state_stack: Vec<(usize, &'a HeapCellValue)>
}
impl<'a> HeapCellViewer<'a> {
pub fn new(heap: &'a Heap, focus: usize) -> Self {
HeapCellViewer {
heap: heap,
state_stack: vec![(focus, &heap[focus])]
}
}
fn follow(&self, value: &'a HeapCellValue) -> &'a HeapCellValue {
match value {
&HeapCellValue::NamedStr(_, _) => value,
&HeapCellValue::Ref(cell_num) | &HeapCellValue::Str(cell_num) =>
&self.heap[cell_num],
}
}
}
impl<'a> Iterator for HeapCellViewer<'a> {
type Item = HeapCellView<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(hcv) = self.state_stack.pop() {
match hcv {
(focus, &HeapCellValue::NamedStr(arity, ref name)) => {
for i in (1 .. arity + 1).rev() {
self.state_stack.push((focus + i, &self.heap[focus + i]));
}
return Some(HeapCellView::Str(arity, name));
},
(_, &HeapCellValue::Ref(cell_num)) => {
let new_hcv = self.follow(hcv.1);
if hcv.1 == new_hcv {
return Some(HeapCellView::Var(cell_num));
} else {
self.state_stack.push((cell_num, new_hcv));
}
},
(_, &HeapCellValue::Str(cell_num)) => {
let new_hcv = self.follow(hcv.1);
self.state_stack.push((cell_num, new_hcv));
}
}
}
None
}
}

View File

@@ -1,175 +0,0 @@
use l2::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::vec::Vec;
enum IteratorState<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
IsolatedVar(&'a Cell<VarReg>, &'a Var),
RootClause(usize, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
}
impl<'a> IteratorState<'a> {
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
{
match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::Atom(lvl, cell, atom),
&Term::Clause(ref cell, ref atom, ref child_terms) =>
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
&Term::Var(ref cell, ref var) =>
IteratorState::Var(lvl, cell, var)
}
}
}
pub struct QueryIterator<'a> {
state_stack: Vec<IteratorState<'a>>
}
impl<'a> QueryIterator<'a> {
fn push_clause(&mut self,
lvl: Level,
child_num: usize,
cell: &'a Cell<RegType>,
name: &'a Atom,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::Clause(lvl,
child_num,
cell,
name,
child_terms));
}
fn push_root_clause(&mut self,
child_num: usize,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
}
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack.push(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> QueryIterator<'a> {
let state = match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::IsolatedAtom(cell, atom),
&Term::Clause(_, _, ref terms) =>
IteratorState::RootClause(0, terms),
&Term::Var(ref cell, ref var) =>
IteratorState::IsolatedVar(cell, var)
};
QueryIterator { state_stack: vec![state] }
}
}
impl<'a> Iterator for QueryIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
if child_num == child_terms.len() {
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
} else {
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
}
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(child_num, child_terms) => {
if child_num == child_terms.len() {
return None;
} else {
self.push_root_clause(child_num + 1, child_terms);
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
};
}
None
}
}
pub struct FactIterator<'a> {
state_queue: VecDeque<IteratorState<'a>>,
}
impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue.push_back(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> FactIterator<'a> {
let states = match term {
&Term::Atom(ref cell, ref atom) =>
vec![IteratorState::IsolatedAtom(cell, atom)],
&Term::Clause(_, _, ref terms) =>
vec![IteratorState::RootClause(0, terms)],
&Term::Var(ref cell, ref var) =>
vec![IteratorState::IsolatedVar(cell, var)]
};
FactIterator { state_queue: VecDeque::from(states) }
}
}
impl<'a> Iterator for FactIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_queue.pop_front() {
match state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Deep, child_term);
}
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(_, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Shallow, child_term);
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
}
}
None
}
}
impl Term {
pub fn post_order_iter(&self) -> QueryIterator {
QueryIterator::new(self)
}
pub fn breadth_first_iter(&self) -> FactIterator {
FactIterator::new(self)
}
}

View File

@@ -1,45 +0,0 @@
use l2::ast::*;
use std::cell::Cell;
grammar;
pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t),
<r:Rule> "." => TopLevel::Rule(r),
<t:Term> "." => TopLevel::Fact(t),
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t),
};
Clause : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts;
ts.push(t);
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
},
};
Rule : Rule = {
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
Rule { head: (c, h), clauses: cs },
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
clauses: cs }
};
Term : Term = {
<Clause> => <>,
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>),
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,456 +0,0 @@
use l2::ast::*;
use l2::codegen::*;
use l2::heapview::*;
use l2::stack::*;
use std::collections::HashMap;
use std::vec::Vec;
#[derive(Clone, Copy)]
enum MachineMode {
Read,
Write
}
struct MachineState {
h: usize,
s: usize,
p: CodePtr,
cp: CodePtr,
fail: bool,
heap: Heap,
mode: MachineMode,
stack: Stack,
registers: Registers
}
type CodeDir = HashMap<(Atom, usize), usize>;
pub struct Machine {
ms: MachineState,
code: Code,
code_dir: CodeDir
}
impl Machine {
pub fn new() -> Self {
Machine {
ms: MachineState::new(),
code: Vec::new(),
code_dir: HashMap::new()
}
}
pub fn failed(&self) -> bool {
self.ms.fail
}
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
let p = self.code.len();
let name = fact.name().clone();
let arity = fact.arity();
self.code.append(&mut code);
self.code_dir.insert((name, arity), p);
}
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
let p = self.code.len();
let name = rule.head.0.name().clone();
let arity = rule.head.0.arity();
self.code.append(&mut code);
self.code_dir.insert((name, arity), p);
}
fn execute_instr(&mut self, instr: &Line) -> bool {
let mut instr = instr;
loop {
match instr {
&Line::Fact(ref fact) => {
for fact_instr in fact {
self.ms.execute_fact_instr(&fact_instr);
}
self.ms.p += 1;
},
&Line::Query(ref query) => {
for query_instr in query {
self.ms.execute_query_instr(&query_instr);
}
self.ms.p += 1;
},
&Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
}
if self.failed() {
return false;
}
match self.ms.p {
CodePtr::DirEntry(p) if p < self.code.len() =>
instr = &self.code[p],
_ => break
}
}
true
}
fn heap_view(&self, var_dir: HashMap<&Var, HeapCellRef>) -> String {
let mut result = String::new();
for (var, hcr) in var_dir {
let mut arities = Vec::new();
let viewer = HeapCellViewer::new(&self.ms.heap, hcr.heap_offset());
if result != "" {
result += "\n";
}
result += var.as_str();
result += " = ";
for view in viewer {
match arities.pop() {
Some(n) => arities.push(n-1),
None => {}
}
if !(arities.is_empty() || result.ends_with("(")) {
result += ", ";
}
match view {
HeapCellView::Str(arity, ref name) => {
result += name.as_str();
if arity > 0 {
arities.push(arity);
result += "(";
}
},
HeapCellView::Var(cell_num) => {
result += "_";
result += cell_num.to_string().as_str();
}
}
while let Some(&0) = arities.last() {
result += ")";
arities.pop();
}
}
}
result
}
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> Option<String>
{
let mut succeeded = true;
for instr in code.iter().take(1) {
succeeded = self.execute_instr(&instr);
}
let mut heap_locs = HashMap::new();
if succeeded {
for (var, vr) in cg.vars() {
let hcr = self.ms.registers[vr.root_register()];
heap_locs.insert(*var, hcr);
}
for instr in code.iter().skip(1) {
succeeded = self.execute_instr(&instr);
if !succeeded {
break;
}
}
}
if succeeded {
Some(self.heap_view(heap_locs))
} else {
None
}
}
pub fn reset(&mut self) {
self.ms.reset();
}
}
impl MachineState {
fn new() -> MachineState {
MachineState { h: 0,
s: 0,
p: CodePtr::TopLevel,
cp: CodePtr::TopLevel,
fail: false,
heap: Vec::with_capacity(256),
mode: MachineMode::Write,
stack: Stack::new(),
registers: vec![HeapCellRef::Ref(0); 32] }
}
fn register_mut(&mut self, r: RegType) -> &mut HeapCellRef {
match r {
RegType::Temp(r) => &mut self.registers[r],
RegType::Perm(r) => &mut self.stack[r]
}
}
fn lookup(&self, a: Addr) -> HeapCellRef {
match a {
Addr::HeapCell(r) => self.heap[r].as_ref(r),
Addr::RegNum(r) => self.registers[r],
Addr::StackCell(s) => self.stack[s]
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
if let HeapCellRef::Ref(value) = self.lookup(a) {
if let Addr::HeapCell(av) = a {
if value != av {
a = Addr::HeapCell(value);
continue;
}
} else {
a = Addr::HeapCell(value);
continue;
}
}
return a;
};
}
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
match hc {
&HeapCellValue::Ref(r) => r == index,
_ => false
}
}
fn bind(&mut self, a: Addr, val: usize) {
let mut a = a;
loop {
match a {
addr @ Addr::RegNum(_) | addr @ Addr::StackCell(_) => {
if let HeapCellRef::Ref(hc) = self.lookup(addr) {
a = Addr::HeapCell(hc);
} else if Self::is_unbound(&self.heap[val], val) {
self.heap[val] = HeapCellValue::from(self.lookup(addr));
break;
} else {
self.fail = true;
break;
}
},
Addr::HeapCell(hc) => {
if Self::is_unbound(&self.heap[hc], hc) {
self.heap[hc] = HeapCellValue::Ref(val);
break;
} else if Self::is_unbound(&self.heap[val], val) {
self.heap[val] = HeapCellValue::Ref(hc);
break;
} else {
self.fail = true;
break;
}
}
};
}
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl = vec![a1, a2];
self.fail = false;
while !(pdl.is_empty() || self.fail) {
let d1 = self.deref(pdl.pop().unwrap());
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (self.lookup(d1), self.lookup(d2)) {
(HeapCellRef::Ref(hc), _) =>
self.bind(d2, hc),
(_, HeapCellRef::Ref(hc)) =>
self.bind(d1, hc),
(HeapCellRef::Str(a1), HeapCellRef::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 + 1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
},
};
}
}
}
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
match instr {
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
*self.register_mut(reg) = HeapCellRef::Str(self.h + 1);
self.h += 2;
},
&QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = match norm {
RegType::Temp(reg) => self.registers[reg],
RegType::Perm(reg) => self.stack[reg]
},
&QueryInstruction::PutVariable(norm, arg) => {
self.heap.push(HeapCellValue::Ref(self.h));
*self.register_mut(norm) = HeapCellRef::Ref(self.h);
self.registers[arg] = HeapCellRef::Ref(self.h);
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCellValue::Ref(self.h));
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
let heap_val = self.lookup(Addr::from(reg));
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
},
}
}
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
let addr = self.deref(Addr::from(reg));
match self.lookup(addr) {
HeapCellRef::Str(a) => {
let result = &self.heap[a];
if let &HeapCellValue::NamedStr(narity, ref str) = result {
if narity == arity && *name == *str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
HeapCellRef::Ref(_) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
let h = self.h;
self.bind(addr, h);
self.h += 2;
self.mode = MachineMode::Write;
}
};
},
&FactInstruction::GetVariable(norm, arg) =>
*self.register_mut(norm) = self.registers[arg],
&FactInstruction::GetValue(norm, arg) =>
self.unify(Addr::from(norm), Addr::RegNum(arg)),
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read =>
*self.register_mut(reg) = self.heap[self.s].as_ref(self.s),
MachineMode::Write => {
self.heap.push(HeapCellValue::Ref(self.h));
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
self.h += 1;
}
};
self.s += 1;
},
&FactInstruction::UnifyValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read =>
self.unify(Addr::from(reg), Addr::HeapCell(s)),
MachineMode::Write => {
let heap_val = self.lookup(Addr::from(reg));
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
}
};
self.s += 1;
}
}
}
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{
match instr {
&ControlInstruction::Allocate(num_cells) => {
self.stack.push(self.cp, num_cells);
self.p += 1;
},
&ControlInstruction::Call(ref name, arity) => {
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
.map(|index| *index);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.cp = self.p + 1;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
},
&ControlInstruction::Deallocate => {
self.p = self.stack.get_cp();
self.stack.pop();
},
&ControlInstruction::Proceed =>
self.p = self.cp,
};
}
fn reset(&mut self) {
self.h = 0;
self.s = 0;
self.p = CodePtr::TopLevel;
self.cp = CodePtr::TopLevel;
self.fail = false;
self.heap.clear();
self.mode = MachineMode::Write;
self.stack = Stack::new();
self.registers = vec![HeapCellRef::Ref(0); 32];
}
}

View File

@@ -1,7 +0,0 @@
pub mod ast;
pub mod heapview;
pub mod iterators;
pub mod l2_parser;
pub mod codegen;
pub mod machine;
pub mod stack;

View File

@@ -1,60 +0,0 @@
use l2::ast::*;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
struct Frame {
cp: CodePtr,
perms: Vec<HeapCellRef>
}
impl Frame {
fn new(cp: CodePtr, n: usize) -> Self {
Frame {
cp: cp,
perms: vec![HeapCellRef::Ref(0); n]
}
}
fn read_pv(&self, i: usize) -> &HeapCellRef {
self.perms.index(i)
}
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellRef {
self.perms.index_mut(i)
}
}
pub struct Stack(Vec<Frame>);
impl Stack {
pub fn new() -> Self {
Stack(Vec::new())
}
pub fn push(&mut self, cp: CodePtr, n: usize) {
self.0.push(Frame::new(cp, n));
}
pub fn get_cp(&self) -> CodePtr {
self.0.last().unwrap().cp
}
pub fn pop(&mut self) {
self.0.pop();
}
}
impl Index<usize> for Stack {
type Output = HeapCellRef;
fn index(&self, index: usize) -> &Self::Output {
self.0.last().unwrap().read_pv(index - 1)
}
}
impl IndexMut<usize> for Stack {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.0.last_mut().unwrap().read_pv_mut(index - 1)
}
}

View File

@@ -1,80 +0,0 @@
use l3::ast::*;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
pub struct Frame {
pub global_index: usize,
pub e: usize,
pub cp: CodePtr,
perms: Vec<Addr>
}
impl Frame {
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
Frame {
global_index: global_index,
e: e,
cp: cp,
perms: vec![Addr::HeapCell(0); n]
}
}
}
pub struct AndStack(Vec<Frame>);
impl AndStack {
pub fn new() -> Self {
AndStack(Vec::new())
}
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
self.0.push(Frame::new(global_index, e, cp, n));
}
pub fn top(&self) -> Option<&Frame> {
self.0.last()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn clear(&mut self) {
self.0.clear()
}
// drop the last n frames.
pub fn drop_frames(&mut self, n: usize) {
let len = self.0.len();
self.0.truncate(len - n);
}
}
impl Index<usize> for AndStack {
type Output = Frame;
fn index(&self, index: usize) -> &Self::Output {
self.0.index(index)
}
}
impl IndexMut<usize> for AndStack {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.0.index_mut(index)
}
}
impl Index<usize> for Frame {
type Output = Addr;
fn index(&self, index: usize) -> &Self::Output {
self.perms.index(index - 1)
}
}
impl IndexMut<usize> for Frame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.perms.index_mut(index - 1)
}
}

View File

@@ -1,303 +0,0 @@
use std::cell::Cell;
use std::collections::HashMap;
use std::ops::{Add, AddAssign};
use std::vec::Vec;
pub type Var = String;
pub type Atom = String;
pub enum PredicateClause {
Fact(Term),
Rule(Rule)
}
impl PredicateClause {
pub fn name(&self) -> &Atom {
match self {
&PredicateClause::Fact(ref t) => t.name(),
&PredicateClause::Rule(ref rule) => rule.head.0.name()
}
}
pub fn arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref t) => t.arity(),
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
}
}
}
pub enum TopLevel {
Fact(Term),
Predicate(Vec<PredicateClause>),
Query(Term),
Rule(Rule)
}
#[derive(Clone, Copy)]
pub enum Level {
Deep, Shallow
}
#[derive(Clone, Copy)]
pub enum RegType {
Perm(usize),
Temp(usize)
}
impl RegType {
pub fn reg_num(self) -> usize {
match self {
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
}
}
pub fn is_perm(self) -> bool {
match self {
RegType::Perm(_) => true,
_ => false
}
}
}
#[derive(Clone, Copy)]
pub enum VarReg {
ArgAndNorm(RegType, usize),
Norm(RegType)
}
impl VarReg {
pub fn norm(self) -> RegType {
match self {
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
}
}
pub fn root_register(self) -> usize {
match self {
VarReg::ArgAndNorm(_, root) => root,
VarReg::Norm(root) => root.reg_num()
}
}
}
pub enum Term {
Atom(Cell<RegType>, Atom),
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
Var(Cell<VarReg>, Var)
}
pub struct Rule {
pub head: (Term, Term),
pub clauses: Vec<Term>
}
pub enum TermRef<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
}
pub enum FactInstruction {
GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
UnifyVariable(RegType),
UnifyValue(RegType)
}
pub enum QueryInstruction {
PutStructure(Level, Atom, usize, RegType),
PutValue(RegType, usize),
PutVariable(RegType, usize),
SetVariable(RegType),
SetValue(RegType)
}
pub enum ChoiceInstruction {
RetryMeElse(usize),
TrustMe,
TryMeElse(usize)
}
pub enum ControlInstruction {
Allocate(usize),
Call(Atom, usize),
Deallocate,
Proceed
}
pub type CompiledFact = Vec<FactInstruction>;
pub type CompiledQuery = Vec<QueryInstruction>;
pub enum Line {
Choice(ChoiceInstruction),
Control(ControlInstruction),
Fact(CompiledFact),
Query(CompiledQuery)
}
pub enum LineOrCodeOffset<'a> {
Instruction(&'a Line),
Offset(usize)
}
impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
fn from(line: &'a Line) -> Self {
LineOrCodeOffset::Instruction(line)
}
}
pub type Code = Vec<Line>;
#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
HeapCell(usize),
StackCell(usize, usize),
Str(usize)
}
impl Addr {
pub fn is_ref(self) -> bool {
match self {
Addr::HeapCell(_) | Addr::StackCell(_, _) => true,
_ => false
}
}
pub fn as_ref(self) -> Option<Ref> {
match self {
Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)),
Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
_ => None
}
}
}
impl From<Ref> for Addr {
fn from(r: Ref) -> Self {
match r {
Ref::HeapCell(hc) => Addr::HeapCell(hc),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Ref {
HeapCell(usize),
StackCell(usize, usize)
}
#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
NamedStr(usize, Atom),
Ref(Ref),
Str(usize)
}
impl From<Addr> for HeapCellValue {
fn from(addr: Addr) -> HeapCellValue {
match addr {
Addr::HeapCell(hc) =>
HeapCellValue::Ref(Ref::HeapCell(hc)),
Addr::StackCell(fr, sc) =>
HeapCellValue::Ref(Ref::StackCell(fr, sc)),
Addr::Str(hc) =>
HeapCellValue::Str(hc)
}
}
}
impl HeapCellValue {
pub fn as_addr(&self, focus: usize) -> Addr {
match self {
&HeapCellValue::Ref(r) => Addr::from(r),
&HeapCellValue::Str(s) => Addr::Str(s),
&HeapCellValue::NamedStr(_, _) => Addr::Str(focus)
}
}
}
#[derive(Clone, Copy)]
pub enum CodePtr {
DirEntry(usize),
TopLevel
}
impl Default for CodePtr {
fn default() -> Self {
CodePtr::TopLevel
}
}
impl Add<usize> for CodePtr {
type Output = CodePtr;
fn add(self, rhs: usize) -> Self::Output {
match self {
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
CodePtr::TopLevel => CodePtr::TopLevel
}
}
}
impl AddAssign<usize> for CodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
_ => {}
}
}
}
pub type Heap = Vec<HeapCellValue>;
pub type Registers = Vec<Addr>;
impl Term {
pub fn subterms(&self) -> usize {
match self {
&Term::Clause(_, _, ref terms) => terms.len(),
_ => 1
}
}
pub fn name(&self) -> &Atom {
match self {
&Term::Atom(_, ref atom)
| &Term::Var(_, ref atom)
| &Term::Clause(_, ref atom, _) => atom
}
}
pub fn arity(&self) -> usize {
match self {
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
&Term::Clause(_, _, ref child_terms) => child_terms.len()
}
}
}
pub type HeapVarDict = HashMap<Var, Addr>;
pub enum EvalResult {
EntryFailure,
EntrySuccess,
InitialQuerySuccess(HeapVarDict),
QueryFailure,
SubsequentQuerySuccess,
}
impl EvalResult {
#[allow(dead_code)]
pub fn failed_query(&self) -> bool {
if let &EvalResult::QueryFailure = self {
true
} else {
false
}
}
}

View File

@@ -1,447 +0,0 @@
use l3::ast::*;
use l3::iterators::{FactIterator, QueryIterator};
use std::cell::Cell;
use std::cmp::max;
use std::collections::HashMap;
use std::vec::Vec;
trait CompilationTarget<'a> {
type Iterator : Iterator<Item=TermRef<'a>>;
fn iter(&'a Term) -> Self::Iterator;
fn to_structure(Level, Atom, usize, RegType) -> Self;
fn argument_to_variable(RegType, usize) -> Self;
fn argument_to_value(RegType, usize) -> Self;
fn subterm_to_variable(RegType) -> Self;
fn subterm_to_value(RegType) -> Self;
fn clause_arg_to_instr(RegType) -> Self;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
type Iterator = FactIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.breadth_first_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
FactInstruction::GetStructure(lvl, atom, arity, reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Self {
FactInstruction::GetVariable(arg, val)
}
fn argument_to_value(arg: RegType, val: usize) -> Self {
FactInstruction::GetValue(arg, val)
}
fn subterm_to_variable(val: RegType) -> Self {
FactInstruction::UnifyVariable(val)
}
fn subterm_to_value(val: RegType) -> Self {
FactInstruction::UnifyValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Self {
FactInstruction::UnifyVariable(val)
}
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
type Iterator = QueryIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
QueryInstruction::PutStructure(lvl, atom, arity, reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Self {
QueryInstruction::PutVariable(arg, val)
}
fn argument_to_value(arg: RegType, val: usize) -> Self {
QueryInstruction::PutValue(arg, val)
}
fn subterm_to_variable(val: RegType) -> Self {
QueryInstruction::SetVariable(val)
}
fn subterm_to_value(val: RegType) -> Self {
QueryInstruction::SetValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Self {
QueryInstruction::SetValue(val)
}
}
struct TermMarker<'a> {
bindings: HashMap<&'a Var, VarReg>,
arg_c: usize,
perm_c: usize,
temp_c: usize
}
impl<'a> TermMarker<'a> {
fn new() -> TermMarker<'a> {
TermMarker { bindings: HashMap::new(),
arg_c: 1,
perm_c: 1,
temp_c: 1 }
}
fn reset(&mut self) {
self.bindings.clear();
self.perm_c = 1;
}
fn contains_var(&self, var: &'a Var) -> bool {
self.bindings.contains_key(var)
}
fn get(&self, var: &'a Var) -> VarReg {
*self.bindings.get(var).unwrap()
}
fn insert(&mut self, var: &'a Var, r: VarReg) {
self.bindings.insert(var, r);
}
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
let reg_type = cell.get();
if reg_type.reg_num() == 0 {
match lvl {
Level::Deep if reg_type.is_perm() => {
let perm = self.perm_c;
self.perm_c += 1;
cell.set(RegType::Perm(perm));
},
Level::Deep => {
let temp = self.temp_c;
self.temp_c += 1;
cell.set(RegType::Temp(temp));
},
Level::Shallow if reg_type.is_perm() => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(RegType::Perm(arg));
},
Level::Shallow => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(RegType::Temp(arg));
}
};
}
}
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
{
let reg = self.get(var);
match lvl {
Level::Deep => VarReg::Norm(reg.norm()),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
self.arg_c += 1;
self.insert(var, reg);
reg
}
}
}
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
{
let inner_reg = if reg.is_perm() {
let perm = self.perm_c;
self.perm_c += 1;
RegType::Perm(perm)
} else {
let temp = self.temp_c;
self.temp_c += 1;
RegType::Temp(temp)
};
let reg = match lvl {
Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
self.arg_c += 1;
reg
}
};
self.insert(var, reg);
reg
}
fn advance_at_head(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_c = max(term.subterms(), self.temp_c) + 1;
}
fn advance(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_c = term.subterms() + 1;
}
}
#[derive(Copy, Clone)]
enum TermStatus {
New, Old, Recurrent
}
pub struct CodeGenerator<'a> {
marker: TermMarker<'a>
}
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
impl<'a> CodeGenerator<'a> {
pub fn new() -> Self {
CodeGenerator { marker: TermMarker::new() }
}
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
&self.marker.bindings
}
fn to_structure<Target>(&mut self,
lvl: Level,
name: &'a Atom,
cell: &'a Cell<RegType>,
arity: usize)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, cell);
Target::to_structure(lvl, name.clone(), arity, cell.get())
}
fn var_term<Target>(&mut self,
lvl: Level,
cell: &'a Cell<VarReg>,
var: &'a Var)
-> Target
where Target: CompilationTarget<'a>
{
if !self.marker.contains_var(var) {
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
cell.set(reg);
match reg {
VarReg::ArgAndNorm(arg, norm) =>
Target::argument_to_variable(arg, norm),
VarReg::Norm(norm) =>
Target::subterm_to_variable(norm)
}
} else {
let reg = self.marker.mark_old_var(lvl, var);
cell.set(reg);
match reg {
VarReg::ArgAndNorm(arg, norm) =>
Target::argument_to_value(arg, norm),
VarReg::Norm(norm) =>
Target::subterm_to_value(norm)
}
}
}
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(Level::Deep, cell);
Target::clause_arg_to_instr(cell.get())
}
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
where Target: CompilationTarget<'a>
{
match subterm {
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
self.non_var_subterm(cell),
&Term::Var(ref cell, ref var) =>
self.var_term(Level::Deep, cell, var)
}
}
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
where Target: CompilationTarget<'a>
{
let iter = Target::iter(term);
let mut target = Vec::new();
for term in iter {
match term {
TermRef::Atom(lvl, term, atom) =>
target.push(self.to_structure(lvl, atom, term, 0)),
TermRef::Clause(lvl, term, atom, terms) => {
target.push(self.to_structure(lvl, atom, term, terms.len()));
for subterm in terms {
target.push(self.subterm_to_instr(subterm.as_ref()));
}
},
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
target.push(self.var_term(lvl, cell, var)),
_ => {}
};
}
target
}
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
where Iter : Iterator<Item=TermRef<'a>>
{
for term in iter {
if let TermRef::Var(_, reg_cell, var) = term {
let mut status = vs.entry(var)
.or_insert((TermStatus::New, Vec::new()));
status.1.push(reg_cell);
match status.0 {
TermStatus::Old => status.0 = TermStatus::Recurrent,
_ => {}
};
}
}
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
match *term_status {
TermStatus::New => *term_status = TermStatus::Old,
TermStatus::Recurrent => {
for cell_reg in cb.drain(0..) {
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
}
},
_ => {}
}
}
}
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut vfs = HashMap::new();
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
Self::mark_vars_in_term(iter, &mut vfs);
for term in clauses {
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
}
vfs
}
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
match term {
&Term::Atom(_, ref atom) => {
let call = ControlInstruction::Call(atom.clone(), 0);
compiled_query.push(Line::Control(call));
},
&Term::Clause(_, ref atom, ref terms) => {
let call = ControlInstruction::Call(atom.clone(), terms.len());
compiled_query.push(Line::Control(call));
},
_ => {}
}
}
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
let vfs = Self::mark_perm_vars(&rule);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut perm_vars = 0;
for &(term_status, _) in vfs.values() {
if let TermStatus::Recurrent = term_status {
perm_vars += 1;
}
}
let mut body = Vec::new();
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0)));
self.marker.advance_at_head(p1);
body.push(Line::Query(self.compile_target(p1)));
Self::add_conditional_call(&mut body, p1);
body = clauses.iter()
.map(|ref term| self.compile_query(term))
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
body
});
body.push(Line::Control(ControlInstruction::Deallocate));
body
}
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
let proceed = Line::Control(ControlInstruction::Proceed);
compiled_fact.push(proceed);
compiled_fact
}
pub fn compile_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
Self::add_conditional_call(&mut compiled_query, term);
compiled_query
}
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
{
let mut code = Vec::new();
for (i, clause) in clauses.iter().enumerate() {
self.marker.reset();
let mut clause_code = match clause {
&PredicateClause::Fact(ref fact) =>
self.compile_fact(fact),
&PredicateClause::Rule(ref rule) =>
self.compile_rule(rule)
};
let choice = match i {
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe,
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
};
code.push(Line::Choice(choice));
code.append(&mut clause_code);
}
code
}
}

View File

@@ -1,86 +0,0 @@
use l3::and_stack::*;
use l3::ast::*;
use std::vec::Vec;
#[derive(Clone, Copy)]
pub enum HeapCellView<'a> {
Str(usize, &'a Atom),
HeapVar(usize),
StackVar(usize, usize)
}
pub struct HeapCellViewer<'a> {
heap: &'a Heap,
and_stack: &'a AndStack,
state_stack: Vec<Addr>
}
impl<'a> HeapCellViewer<'a> {
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self {
HeapCellViewer {
heap: heap,
and_stack: and_stack,
state_stack: vec![focus]
}
}
fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a>
{
loop {
match self.and_stack[fr][sc] {
Addr::HeapCell(hc) | Addr::Str(hc) =>
return self.follow_heap_ref(hc),
Addr::StackCell(fr1, sc1) => {
if fr1 == fr && sc1 == sc {
return HeapCellView::StackVar(fr, sc);
}
fr = fr1; sc = sc1;
}
}
}
}
fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> {
loop {
match &self.heap[focus] {
&HeapCellValue::NamedStr(arity, ref name) => {
for i in (1 .. arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(focus + i));
}
return HeapCellView::Str(arity, name);
},
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
if focus == hc {
return HeapCellView::HeapVar(hc);
} else {
focus = hc;
}
},
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) =>
return self.follow_stack_ref(fr, sc),
&HeapCellValue::Str(cell_num) =>
focus = cell_num,
}
}
}
}
impl<'a> Iterator for HeapCellViewer<'a> {
type Item = HeapCellView<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(addr) = self.state_stack.pop() {
match addr {
Addr::HeapCell(hc) | Addr::Str(hc) =>
return Some(self.follow_heap_ref(hc)),
Addr::StackCell(fr, sc) =>
return Some(self.follow_stack_ref(fr, sc))
}
}
None
}
}

View File

@@ -1,255 +0,0 @@
use l3::ast::*;
use l3::codegen::*;
use l3::l3_parser::*;
use l3::machine::*;
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::event::Key;
use std::io::{Write, stdin, stdout};
use std::fmt;
impl fmt::Display for FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
write!(f, "get_structure {}/{}, {}", name, arity, r),
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
&FactInstruction::GetValue(ref x, ref a) =>
write!(f, "get_value {}, A{}", x, a),
&FactInstruction::GetVariable(ref x, ref a) =>
write!(f, "get_variable {}, A{}", x, a),
&FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable {}", r),
&FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value {}", r)
}
}
}
impl fmt::Display for QueryInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()),
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
&QueryInstruction::PutValue(ref x, ref a) =>
write!(f, "put_value {}, A{}", x, a),
&QueryInstruction::PutVariable(ref x, ref a) =>
write!(f, "put_variable {}, A{}", x, a),
&QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable {}", r),
&QueryInstruction::SetValue(ref r) =>
write!(f, "set_value {}", r),
}
}
}
impl fmt::Display for ControlInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ControlInstruction::Allocate(num_cells) =>
write!(f, "allocate {}", num_cells),
&ControlInstruction::Call(ref name, ref arity) =>
write!(f, "call {}/{}", name, arity),
&ControlInstruction::Deallocate =>
write!(f, "deallocate"),
&ControlInstruction::Proceed =>
write!(f, "proceed")
}
}
}
impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ChoiceInstruction::TryMeElse(offset) =>
write!(f, "try_me_else {}", offset),
&ChoiceInstruction::RetryMeElse(offset) =>
write!(f, "retry_me_else {}", offset),
&ChoiceInstruction::TrustMe =>
write!(f, "trust_me")
}
}
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Level::Shallow => write!(f, "A"),
&Level::Deep => write!(f, "X")
}
}
}
impl fmt::Display for VarReg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
write!(f, "Y{} A{}", reg, arg),
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
write!(f, "X{} A{}", reg, arg)
}
}
}
impl fmt::Display for RegType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&RegType::Perm(val) => write!(f, "Y{}", val),
&RegType::Temp(val) => write!(f, "X{}", val)
}
}
}
fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
let name = predicate.first().unwrap().name();
let arity = predicate.first().unwrap().arity();
for clause in predicate.iter().skip(1) {
if !(name == clause.name() && arity == clause.arity()) {
return false;
}
}
true
}
#[allow(dead_code)]
pub fn print_code(code: &Code) {
for clause in code {
match clause {
&Line::Fact(ref fact) =>
for fact_instr in fact {
println!("{}", fact_instr);
},
&Line::Choice(ref choice) =>
println!("{}", choice),
&Line::Control(ref control) =>
println!("{}", control),
&Line::Query(ref query) =>
for query_instr in query {
println!("{}", query_instr);
}
}
}
}
pub fn read() -> String {
let _ = stdout().flush();
let mut buffer = String::new();
let mut result = String::new();
let stdin = stdin();
stdin.read_line(&mut buffer).unwrap();
if &*buffer.trim() == ":{" {
buffer.clear();
stdin.read_line(&mut buffer).unwrap();
while &*buffer.trim() != "}:" {
result += buffer.as_str();
buffer.clear();
stdin.read_line(&mut buffer).unwrap();
}
} else {
result = buffer;
}
result
}
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
{
let result = parse_TopLevel(buffer);
let mut cg = CodeGenerator::new();
match &result {
&Ok(TopLevel::Predicate(ref clauses)) => {
if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses);
wam.add_predicate(clauses, compiled_pred);
EvalResult::EntrySuccess
} else {
let msg = r"Error: predicate is inconsistent.
Each predicate must have the same name and arity.";
println!("{}", msg);
EvalResult::EntryFailure
}
},
&Ok(TopLevel::Fact(ref fact)) => {
let compiled_fact = cg.compile_fact(&fact);
wam.add_fact(fact, compiled_fact);
EvalResult::EntrySuccess
},
&Ok(TopLevel::Rule(ref rule)) => {
let compiled_rule = cg.compile_rule(&rule);
wam.add_rule(rule, compiled_rule);
EvalResult::EntrySuccess
},
&Ok(TopLevel::Query(ref query)) => {
let compiled_query = cg.compile_query(&query);
wam.run_query(compiled_query, &cg)
},
&Err(_) => {
println!("Grammatical error of some kind!");
EvalResult::EntryFailure
}
}
}
pub fn print(wam: &mut Machine, result: EvalResult) {
match result {
EvalResult::InitialQuerySuccess(heap_locs) => {
println!("yes");
'outer: loop {
let mut result = EvalResult::QueryFailure;
let bindings = wam.heap_view(&heap_locs);
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
write!(stdout, "{}\n\r", bindings).unwrap();
stdout.flush().unwrap();
if !wam.or_stack_is_empty() {
write!(stdout, "Press ; to continue or A to abort.\n\r").unwrap();
stdout.flush().unwrap();
for c in stdin.keys() {
match c.unwrap() {
Key::Char(';') => {
result = wam.continue_query();
break;
},
Key::Char('a') | Key::Char('A') =>
break 'outer,
_ => {}
}
};
if let &EvalResult::QueryFailure = &result {
write!(stdout, "no\n\r").unwrap();
stdout.flush().unwrap();
break;
}
} else {
break;
}
}
},
EvalResult::QueryFailure => println!("no"),
_ => {}
};
}

View File

@@ -1,175 +0,0 @@
use l3::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::vec::Vec;
enum IteratorState<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
IsolatedVar(&'a Cell<VarReg>, &'a Var),
RootClause(usize, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
}
impl<'a> IteratorState<'a> {
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
{
match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::Atom(lvl, cell, atom),
&Term::Clause(ref cell, ref atom, ref child_terms) =>
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
&Term::Var(ref cell, ref var) =>
IteratorState::Var(lvl, cell, var)
}
}
}
pub struct QueryIterator<'a> {
state_stack: Vec<IteratorState<'a>>
}
impl<'a> QueryIterator<'a> {
fn push_clause(&mut self,
lvl: Level,
child_num: usize,
cell: &'a Cell<RegType>,
name: &'a Atom,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::Clause(lvl,
child_num,
cell,
name,
child_terms));
}
fn push_root_clause(&mut self,
child_num: usize,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
}
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack.push(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> QueryIterator<'a> {
let state = match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::IsolatedAtom(cell, atom),
&Term::Clause(_, _, ref terms) =>
IteratorState::RootClause(0, terms),
&Term::Var(ref cell, ref var) =>
IteratorState::IsolatedVar(cell, var)
};
QueryIterator { state_stack: vec![state] }
}
}
impl<'a> Iterator for QueryIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() {
match iter_state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
if child_num == child_terms.len() {
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
} else {
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
}
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(child_num, child_terms) => {
if child_num == child_terms.len() {
return None;
} else {
self.push_root_clause(child_num + 1, child_terms);
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
};
}
None
}
}
pub struct FactIterator<'a> {
state_queue: VecDeque<IteratorState<'a>>,
}
impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue.push_back(IteratorState::to_state(lvl, term));
}
fn new(term: &'a Term) -> FactIterator<'a> {
let states = match term {
&Term::Atom(ref cell, ref atom) =>
vec![IteratorState::IsolatedAtom(cell, atom)],
&Term::Clause(_, _, ref terms) =>
vec![IteratorState::RootClause(0, terms)],
&Term::Var(ref cell, ref var) =>
vec![IteratorState::IsolatedVar(cell, var)]
};
FactIterator { state_queue: VecDeque::from(states) }
}
}
impl<'a> Iterator for FactIterator<'a> {
type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_queue.pop_front() {
match state {
IteratorState::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Deep, child_term);
}
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
},
IteratorState::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
IteratorState::RootClause(_, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Shallow, child_term);
}
},
IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var))
}
}
None
}
}
impl Term {
pub fn post_order_iter(&self) -> QueryIterator {
QueryIterator::new(self)
}
pub fn breadth_first_iter(&self) -> FactIterator {
FactIterator::new(self)
}
}

View File

@@ -1,59 +0,0 @@
use l3::ast::*;
use std::cell::Cell;
grammar;
pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t),
<Predicate> => TopLevel::Predicate(<>),
<Rule> "." => TopLevel::Rule(<>),
<Term> "." => TopLevel::Fact(<>)
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t)
};
Clause : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts;
ts.push(t);
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
}
};
Predicate : Vec<PredicateClause> = {
<pcs: (<PredicateClause>)+> <pc: PredicateClause> => {
let mut pcs = pcs;
pcs.push(pc);
pcs
}
};
PredicateClause : PredicateClause = {
<Rule> "." => PredicateClause::Rule(<>),
<Term> "." => PredicateClause::Fact(<>)
};
Rule : Rule = {
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
Rule { head: (c, h), clauses: cs },
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
clauses: cs }
};
Term : Term = {
<Clause> => <>,
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>)
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,677 +0,0 @@
use l3::ast::*;
use l3::codegen::*;
use l3::heapview::*;
use l3::and_stack::*;
use l3::or_stack::*;
use std::collections::HashMap;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
#[derive(Clone, Copy)]
enum MachineMode {
Read,
Write
}
struct MachineState {
h: usize,
s: usize,
p: CodePtr,
b: usize,
e: usize,
num_of_args: usize,
cp: CodePtr,
fail: bool,
heap: Heap,
mode: MachineMode,
and_stack: AndStack,
or_stack: OrStack,
registers: Registers,
trail: Vec<Ref>,
tr: usize,
hb: usize
}
type CodeDir = HashMap<(Atom, usize), usize>;
impl Index<RegType> for MachineState {
type Output = Addr;
fn index(&self, reg: RegType) -> &Self::Output {
match reg {
RegType::Temp(temp) => &self.registers[temp],
RegType::Perm(perm) => {
let e = self.e;
&self.and_stack[e][perm]
}
}
}
}
impl IndexMut<RegType> for MachineState {
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
match reg {
RegType::Temp(temp) => &mut self.registers[temp],
RegType::Perm(perm) => {
let e = self.e;
&mut self.and_stack[e][perm]
}
}
}
}
pub struct Machine {
ms: MachineState,
code: Code,
code_dir: CodeDir
}
impl Machine {
pub fn new() -> Self {
Machine {
ms: MachineState::new(),
code: Vec::new(),
code_dir: HashMap::new()
}
}
pub fn failed(&self) -> bool {
self.ms.fail
}
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
let p = self.code.len();
let name = fact.name().clone();
let arity = fact.arity();
self.code.append(&mut code);
self.code_dir.insert((name, arity), p);
}
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
let p = self.code.len();
let name = rule.head.0.name().clone();
let arity = rule.head.0.arity();
self.code.append(&mut code);
self.code_dir.insert((name, arity), p);
}
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code)
{
let p = self.code.len();
let name = pred.first().unwrap().name().clone();
let arity = pred.first().unwrap().arity();
self.code.append(&mut code);
self.code_dir.insert((name, arity), p);
}
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
{
let mut instr = match instr_src {
LineOrCodeOffset::Instruction(instr) => instr,
LineOrCodeOffset::Offset(p) => &self.code[p]
};
loop {
match instr {
&Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr),
&Line::Fact(ref fact) => {
for fact_instr in fact {
self.ms.execute_fact_instr(&fact_instr);
}
self.ms.p += 1;
},
&Line::Query(ref query) => {
for query_instr in query {
self.ms.execute_query_instr(&query_instr);
}
self.ms.p += 1;
},
&Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
}
if self.failed() {
let p = self.ms
.or_stack
.top()
.map(|fr| fr.bp)
.unwrap_or_default();
if let CodePtr::TopLevel = p {
return false;
} else {
self.ms.fail = false;
self.ms.p = p;
}
}
match self.ms.p {
CodePtr::DirEntry(p) if p < self.code.len() =>
instr = &self.code[p],
_ => break
}
}
true
}
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
let mut result = String::new();
for (var, addr) in var_dir {
let mut arities = Vec::new();
let viewer = HeapCellViewer::new(&self.ms.heap,
&self.ms.and_stack,
*addr);
if result != "" {
result += "\n\r";
}
result += var.as_str();
result += " = ";
for view in viewer {
match arities.pop() {
Some(n) => arities.push(n-1),
None => {}
}
if !(arities.is_empty() || result.ends_with("(")) {
result += ", ";
}
match view {
HeapCellView::Str(arity, ref name) => {
result += name.as_str();
if arity > 0 {
arities.push(arity);
result += "(";
}
},
HeapCellView::HeapVar(cell_num) => {
result += "_";
result += cell_num.to_string().as_str();
},
HeapCellView::StackVar(fr, sc) => {
result += "_s_";
result += fr.to_string().as_str();
result += "_";
result += sc.to_string().as_str();
}
}
while let Some(&0) = arities.last() {
result += ")";
arities.pop();
}
}
}
result
}
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult
{
let mut succeeded = true;
let mut heap_locs = HashMap::new();
for instr in code.iter().take(1) {
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
}
if succeeded {
for (var, vr) in cg.vars() {
let addr = self.ms.registers[vr.root_register()];
heap_locs.insert((*var).clone(), addr);
}
for instr in code.iter().skip(1) {
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
if !succeeded {
break;
}
}
}
if succeeded {
EvalResult::InitialQuerySuccess(heap_locs)
} else {
EvalResult::QueryFailure
}
}
pub fn or_stack_is_empty(&self) -> bool {
self.ms.or_stack.is_empty()
}
pub fn continue_query(&mut self) -> EvalResult
{
if !self.or_stack_is_empty() {
let b = self.ms.b;
self.ms.p = self.ms.or_stack[b].bp;
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
self.execute_instr(LineOrCodeOffset::Offset(p))
} else {
false
};
if succeeded {
EvalResult::SubsequentQuerySuccess
} else {
EvalResult::QueryFailure
}
} else {
EvalResult::QueryFailure
}
}
pub fn reset(&mut self) {
self.ms.reset();
}
}
impl MachineState {
fn new() -> MachineState {
MachineState { h: 0,
s: 0,
p: CodePtr::TopLevel,
b: 0,
e: 0,
num_of_args: 0,
cp: CodePtr::TopLevel,
fail: false,
heap: Vec::with_capacity(256),
mode: MachineMode::Write,
and_stack: AndStack::new(),
or_stack: OrStack::new(),
registers: vec![Addr::HeapCell(0); 32],
trail: Vec::new(),
tr: 0,
hb: 0
}
}
fn num_frames(&self) -> usize {
self.and_stack.len() + self.or_stack.len()
}
fn store(&self, a: Addr) -> Addr {
match a {
Addr::HeapCell(r) => self.heap[r].as_addr(r),
Addr::StackCell(fr, sc) => self.and_stack[fr][sc],
addr => addr
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
let value = self.store(a);
if value.is_ref() && value != a {
a = value;
continue;
}
return a;
};
}
fn bind(&mut self, r1: Ref, a2: Addr) {
let t2 = self.store(a2);
match r1 {
Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = t2,
Ref::HeapCell(hc) =>
self.heap[hc] = HeapCellValue::from(t2)
};
self.trail(r1);
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl = vec![a1, a2];
self.fail = false;
while !(pdl.is_empty() || self.fail) {
let d1 = self.deref(pdl.pop().unwrap());
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (self.store(d1), self.store(d2)) {
(Addr::HeapCell(hc), _) =>
self.bind(Ref::HeapCell(hc), d2),
(_, Addr::HeapCell(hc)) =>
self.bind(Ref::HeapCell(hc), d1),
(Addr::StackCell(fr, sc), _) =>
self.bind(Ref::StackCell(fr, sc), d2),
(_, Addr::StackCell(fr, sc)) =>
self.bind(Ref::StackCell(fr, sc), d1),
(Addr::Str(a1), Addr::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 + 1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
}
};
}
}
}
fn trail(&mut self, r: Ref) {
match r {
Ref::HeapCell(hc) => {
if hc < self.hb {
self.trail.push(r);
self.tr += 1;
}
},
Ref::StackCell(fr, _) => {
let fr_gi = self.and_stack[fr].global_index;
let b_gi = if !self.or_stack.is_empty() {
self.or_stack[self.b].global_index
} else {
0
};
if fr_gi < b_gi {
self.trail.push(r);
self.tr += 1;
}
}
}
}
fn unwind_trail(&mut self, a1: usize, a2: usize) {
for i in a1 .. a2 {
match self.trail[i] {
Ref::HeapCell(r) =>
self.heap[r] = HeapCellValue::Ref(self.trail[i]),
Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
}
}
}
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
match instr {
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
self[reg] = Addr::Str(self.h + 1);
self.h += 2;
},
&QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = self[norm],
&QueryInstruction::PutVariable(norm, arg) => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
self[norm] = Addr::HeapCell(self.h);
self.registers[arg] = Addr::HeapCell(self.h);
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
self[reg] = Addr::HeapCell(self.h);
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
let heap_val = self[reg];
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
},
}
}
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
let addr = self.deref(self[reg]);
match self.store(addr) {
Addr::Str(a) => {
let result = &self.heap[a];
if let &HeapCellValue::NamedStr(narity, ref str) = result {
if narity == arity && *name == *str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
let h = self.h;
self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h));
self.h += 2;
self.mode = MachineMode::Write;
}
};
},
&FactInstruction::GetVariable(norm, arg) =>
self[norm] = self.registers[arg],
&FactInstruction::GetValue(norm, arg) => {
let norm_addr = self[norm];
let reg_addr = self.registers[arg];
self.unify(norm_addr, reg_addr);
},
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read =>
self[reg] = self.heap[self.s].as_addr(self.s),
MachineMode::Write => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
self[reg] = Addr::HeapCell(self.h);
self.h += 1;
}
};
self.s += 1;
},
&FactInstruction::UnifyValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => {
let reg_addr = self[reg];
self.unify(reg_addr, Addr::HeapCell(s));
},
MachineMode::Write => {
let heap_val = self.store(self[reg]);
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
}
};
self.s += 1;
}
};
}
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{
match instr {
&ControlInstruction::Allocate(num_cells) => {
let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
self.e = self.and_stack.len() - 1;
self.p += 1;
},
&ControlInstruction::Call(ref name, arity) => {
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
.map(|index| *index);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.cp = self.p + 1;
self.num_of_args = arity;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
},
&ControlInstruction::Deallocate => {
let e = self.e;
let num_frame_e = self.and_stack.top().unwrap().global_index;
let num_frame_b = self.or_stack
.top()
.map(|fr| fr.global_index)
.unwrap_or(0);
self.p = self.and_stack[e].cp;
self.e = self.and_stack[e].e;
if num_frame_e > num_frame_b {
let top_e = self.and_stack.top().unwrap().e;
self.and_stack.drop_frames(top_e - self.e + 1);
}
},
&ControlInstruction::Proceed =>
self.p = self.cp,
};
}
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
{
match instr {
&ChoiceInstruction::TryMeElse(offset) => {
let n = self.num_of_args;
let num_frames = self.num_frames();
self.or_stack.push(num_frames + 1,
self.e,
self.cp,
self.b,
self.p + offset,
self.tr,
self.h,
self.num_of_args);
self.b = self.or_stack.len() - 1;
let b = self.b;
for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i];
}
self.hb = self.h;
self.p += 1;
},
&ChoiceInstruction::RetryMeElse(offset) => {
let b = self.b;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i];
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + offset;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.h = self.or_stack[b].h;
self.hb = self.h;
self.p += 1;
},
&ChoiceInstruction::TrustMe => {
let b = self.b;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i];
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.h = self.or_stack[b].h;
self.heap.truncate(self.h);
self.b = self.or_stack[b].b;
self.or_stack.pop();
self.hb = self.h;
self.p += 1;
}
}
}
fn reset(&mut self) {
self.h = 0;
self.hb = 0;
self.e = 0;
self.b = 0;
self.s = 0;
self.tr = 0;
self.p = CodePtr::TopLevel;
self.cp = CodePtr::TopLevel;
self.num_of_args = 0;
self.fail = false;
self.trail.clear();
self.heap.clear();
self.mode = MachineMode::Write;
self.and_stack.clear();
self.or_stack.clear();
self.registers = vec![Addr::HeapCell(0); 32];
}
}

View File

@@ -1,9 +0,0 @@
pub mod and_stack;
pub mod ast;
pub mod codegen;
pub mod heapview;
pub mod io;
pub mod iterators;
pub mod l3_parser;
pub mod machine;
pub mod or_stack;

View File

@@ -1,112 +0,0 @@
use l3::ast::*;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
pub struct Frame {
pub global_index: usize,
pub e: usize,
pub cp: CodePtr,
pub b: usize,
pub bp: CodePtr,
pub tr: usize,
pub h: usize,
args: Vec<Addr>
}
impl Frame {
fn new(global_index: usize,
e: usize,
cp: CodePtr,
b: usize,
bp: CodePtr,
tr: usize,
h: usize,
n: usize)
-> Self
{
Frame {
global_index: global_index,
e: e,
cp: cp,
b: b,
bp: bp,
tr: tr,
h: h,
args: vec![Addr::HeapCell(0); n]
}
}
pub fn num_args(&self) -> usize {
self.args.len()
}
}
pub struct OrStack(Vec<Frame>);
impl OrStack {
pub fn new() -> Self {
OrStack(Vec::new())
}
pub fn push(&mut self,
global_index: usize,
e: usize,
cp: CodePtr,
b: usize,
bp: CodePtr,
tr: usize,
h: usize,
n: usize)
{
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn clear(&mut self) {
self.0.clear()
}
pub fn top(&self) -> Option<&Frame> {
self.0.last()
}
pub fn pop(&mut self) {
self.0.pop();
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Index<usize> for OrStack {
type Output = Frame;
fn index(&self, index: usize) -> &Self::Output {
self.0.index(index)
}
}
impl IndexMut<usize> for OrStack {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.0.index_mut(index)
}
}
impl Index<usize> for Frame {
type Output = Addr;
fn index(&self, index: usize) -> &Self::Output {
self.args.index(index - 1)
}
}
impl IndexMut<usize> for Frame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.args.index_mut(index - 1)
}
}

83
src/lib.rs Normal file
View File

@@ -0,0 +1,83 @@
//! A free software ISO Prolog system.
#![recursion_limit = "4112"]
#![deny(missing_docs)]
#[macro_use]
extern crate static_assertions;
#[macro_use]
pub(crate) mod macros;
#[macro_use]
pub(crate) mod atom_table;
#[macro_use]
pub(crate) mod arena;
pub(crate) mod offset_table;
#[macro_use]
pub(crate) mod parser;
#[macro_use]
pub(crate) mod functor_macro;
mod allocator;
mod arithmetic;
pub(crate) mod codegen;
mod debray_allocator;
#[cfg(feature = "ffi")]
mod ffi;
mod forms;
mod heap_iter;
pub(crate) mod heap_print;
#[cfg(feature = "http")]
mod http;
mod indexing;
mod variable_records;
#[macro_use]
pub(crate) mod instructions {
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
}
mod iterators;
pub(crate) mod machine;
mod raw_block;
pub(crate) mod read;
#[cfg(feature = "repl")]
mod repl_helper;
mod targets;
pub(crate) mod types;
// Re-exports
pub use machine::config::*;
pub use machine::lib_machine::*;
pub use machine::Machine;
#[cfg(target_arch = "wasm32")]
pub mod wasm;
#[cfg(not(target_arch = "wasm32"))]
/// The entry point for the Scryer Prolog CLI.
pub fn run_binary() -> std::process::ExitCode {
use crate::atom_table::Atom;
use crate::machine::INTERRUPT;
#[cfg(feature = "repl")]
ctrlc::set_handler(move || {
INTERRUPT.store(true, std::sync::atomic::Ordering::Relaxed);
})
.unwrap();
#[cfg(target_arch = "wasm32")]
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
#[cfg(not(target_arch = "wasm32"))]
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
runtime.block_on(async move {
let mut wam = MachineBuilder::default()
.with_streams(StreamConfig::stdio())
.build();
wam.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 0))
})
}

163
src/lib/arithmetic.pl Normal file
View File

@@ -0,0 +1,163 @@
/** Arithmetic predicates
These predicates are additions to standard the arithmetic functions provided by `is/2`.
*/
:- module(arithmetic, [expmod/4, lcm/3, lsb/2, msb/2, number_to_rational/2,
number_to_rational/3, popcount/2,
rational_numerator_denominator/3]).
:- use_module(library(charsio), [write_term_to_chars/3]).
:- use_module(library(error)).
:- use_module(library(lists), [append/3, member/2]).
%% expmod(+Base, +Expo, +Mod, -R).
%
% Modular exponentiation. Base, Expo and Mod must be integers.
expmod(Base, Expo, Mod, R) :-
( member(N, [Base, Expo, Mod]), var(N) -> instantiation_error(expmod/4)
; member(N, [Base, Expo, Mod]), \+ integer(N) ->
type_error(integer, N, expmod/4)
; Expo < 0 -> domain_error(not_less_than_zero, Expo, expmod/4)
; expmod_(Base, Expo, Mod, 1, R)
).
expmod_(_, _, 1, _, 0) :- !.
expmod_(_, 0, _, R, R) :- !.
expmod_(Base0, Expo0, Mod, C0, R) :-
Expo0 /\ 1 =:= 1,
C is (C0 * Base0) mod Mod,
!,
Expo is Expo0 >> 1,
Base is (Base0 * Base0) mod Mod,
expmod_(Base, Expo, Mod, C, R).
expmod_(Base0, Expo0, Mod, C, R) :-
Expo is Expo0 >> 1,
Base is (Base0 * Base0) mod Mod,
expmod_(Base, Expo, Mod, C, R).
%% lcm(+A, +B, -Lcm) is det.
%
% Calculates the Least common multiple for A and B: the smallest positive integer
% that is divisible by both A and B.
%
% A and B need to be integers.
lcm(A, B, X) :-
builtins:must_be_number(A, lcm/2),
builtins:must_be_number(B, lcm/2),
( \+ integer(A) -> type_error(integer, A, lcm/2)
; \+ integer(B) -> type_error(integer, B, lcm/2)
; (A = 0, B = 0) -> X = 0
; builtins:can_be_number(X, lcm/2),
X is abs(B) // gcd(A,B) * abs(A)
).
%% lsb(+X, -N).
%
% True iff N is the least significat bit of integer X
lsb(X, N) :-
builtins:must_be_number(X, lsb/2),
( \+ integer(X) -> type_error(integer, X, lsb/2)
; X < 1 -> domain_error(not_less_than_one, X, lsb/2)
; builtins:can_be_number(N, lsb/2),
X1 is X /\ (-X),
msb_(X1, -1, N)
).
%% msb(+X, -N).
%
% True iff N is the most significant bit of integer X
msb(X, N) :-
builtins:must_be_number(X, msb/2),
( \+ integer(X) -> type_error(integer, X, msb/2)
; X < 1 -> domain_error(not_less_than_one, X, msb/2)
; builtins:can_be_number(N, msb/2),
X1 is X >> 1,
msb_(X1, 0, N)
).
msb_(0, N, N) :- !.
msb_(X, M, N) :-
X1 is X >> 1,
M1 is M + 1,
msb_(X1, M1, N).
%% number_to_rational(+Real, -Fraction).
%
% True iff given a number Real, Fraction is the same number represented as a fraction.
number_to_rational(Real, Fraction) :-
( var(Real) -> instantiation_error(number_to_rational/2)
; integer(Real) -> Fraction is Real rdiv 1
; (rational(Real) ; float(Real)) ->
number_to_rational(1.0e-6, Real, Fraction)
; type_error(number, Real, number_to_rational/2)
).
% If 0 <= Eps0 <= 1e-16 then the search is for "infinite" precision.
number_to_rational(Eps0, Real0, Fraction) :-
( var(Eps0) -> instantiation_error(number_to_rational/3)
; \+ number(Eps0) -> type_error(number, Eps0, number_to_rational/3)
; Eps0 < 0 -> domain_error(not_less_than_zero, Eps0, number_to_rational/3)
; Eps_ is Eps0 rdiv 1,
rational_numerator_denominator(Eps_, EpsN, EpsD),
Eps = EpsN/EpsD
),
( var(Real0) -> instantiation_error(number_to_rational/3)
; \+ number(Real0) -> type_error(number, Eps0, number_to_rational/3)
; Real_ is Real0 rdiv 1,
rational_numerator_denominator(Real_, RealN, RealD),
Real = RealN/RealD
),
E0/E1 = Eps,
P0/Q0 = Real,
( P0 < 0 -> I1 is -1 + P0 // Q0
; I1 is P0 // Q0
),
P1 is P0 mod Q0,
Q1 = Q0,
( P1 =:= 0 -> Fraction is I1 + 0 rdiv 1
; Qn1n is max(P1 * E1 - Q1 * E0, 0),
Qn1d is Q1 * E1,
Qn1 = Qn1n/Qn1d,
Qp1n is P1 * E1 + Q1 * E0,
Qp1d = Qn1d,
Qp1 = Qp1n/Qp1d,
stern_brocot_(Qn1, Qp1, 0/1, 1/0, P2/Q2),
Fraction is I1 + P2 rdiv Q2
),
!.
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
Fn1 is A + C,
Fd1 is B + D,
simplify_fraction(Fn1/Fd1, Fn/Fd),
S1 is sign(Fn * Qnd - Fd * Qnn),
S2 is sign(Fn * Qpd - Fd * Qpn),
( S1 < 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, Fn/Fd, C/D, Fraction)
; S2 > 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, Fn/Fd, Fraction)
; Fraction = Fn/Fd
).
simplify_fraction(A0/B0, A/B) :-
G is gcd(A0, B0),
A is A0 // G,
B is B0 // G.
%% rational_numerator_denominator(+Fraction, -Numerator, -Denominator).
%
% True iff given a fraction Fraction, Numerator is the numerator of that fraction
% and Denominator the denominator.
rational_numerator_denominator(R, N, D) :-
write_term_to_chars(R, [], Cs),
append(Ns, [' ', r, d, i, v, ' '|Ds], Cs),
number_chars(N, Ns),
number_chars(D, Ds).
%% popcount(+Number, -Bits1).
%
% True iff given an integer Number, Bits1 is the amount of 1 bits the binary representation
% of that number has.
popcount(X, N) :-
must_be(integer, X),
'$popcount'(X, N).

View File

@@ -54,31 +54,27 @@
:- use_module(library(lists)). :- use_module(library(lists)).
/** <module> Binary associations /** Binary associations
Assocs are Key-Value associations implemented as a balanced binary tree Assocs are Key-Value associations implemented as a balanced binary tree
(AVL tree). (AVL tree).
@see library(pairs), library(rbtrees) Authors: R.A.O'Keefe, L.Damas, V.S.Costa and Jan Wielemaker
@author R.A.O'Keefe, L.Damas, V.S.Costa and Jan Wielemaker
*/ */
/* :- meta_predicate(map_assoc(1, ?)).
:- meta_predicate :- meta_predicate(map_assoc(2, ?, ?)).
map_assoc(1, ?),
map_assoc(2, ?, ?). %% empty_assoc(?Assoc) is semidet.
*/
%! empty_assoc(?Assoc) is semidet.
% %
% Is true if Assoc is the empty association list. % Is true if Assoc is the empty association list.
empty_assoc(t). empty_assoc(t).
%! assoc_to_list(+Assoc, -Pairs) is det. %% assoc_to_list(+Assoc, -Pairs) is det.
% %
% Translate Assoc to a list Pairs of Key-Value pairs. The keys % Translate Assoc to a list Pairs of Key-Value pairs. The keys
% in Pairs are sorted in ascending order. % in Pairs are sorted in ascending order.
assoc_to_list(Assoc, List) :- assoc_to_list(Assoc, List) :-
assoc_to_list(Assoc, List, []). assoc_to_list(Assoc, List, []).
@@ -89,10 +85,10 @@ assoc_to_list(t(Key,Val,_,L,R), List, Rest) :-
assoc_to_list(t, List, List). assoc_to_list(t, List, List).
%! assoc_to_keys(+Assoc, -Keys) is det. %% assoc_to_keys(+Assoc, -Keys) is det.
% %
% True if Keys is the list of keys in Assoc. The keys are sorted % True if Keys is the list of keys in Assoc. The keys are sorted
% in ascending order. % in ascending order.
assoc_to_keys(Assoc, List) :- assoc_to_keys(Assoc, List) :-
assoc_to_keys(Assoc, List, []). assoc_to_keys(Assoc, List, []).
@@ -103,11 +99,11 @@ assoc_to_keys(t(Key,_,_,L,R), List, Rest) :-
assoc_to_keys(t, List, List). assoc_to_keys(t, List, List).
%! assoc_to_values(+Assoc, -Values) is det. %% assoc_to_values(+Assoc, -Values) is det.
% %
% True if Values is the list of values in Assoc. Values are % True if Values is the list of values in Assoc. Values are
% ordered in ascending order of the key to which they were % ordered in ascending order of the key to which they were
% associated. Values may contain duplicates. % associated. Values may contain duplicates.
assoc_to_values(Assoc, List) :- assoc_to_values(Assoc, List) :-
assoc_to_values(Assoc, List, []). assoc_to_values(Assoc, List, []).
@@ -117,12 +113,12 @@ assoc_to_values(t(_,Value,_,L,R), List, Rest) :-
assoc_to_values(R, More, Rest). assoc_to_values(R, More, Rest).
assoc_to_values(t, List, List). assoc_to_values(t, List, List).
%! is_assoc(+Assoc) is semidet. %% is_assoc(+Assoc) is semidet.
% %
% True if Assoc is an association list. This predicate checks % True if Assoc is an association list. This predicate checks
% that the structure is valid, elements are in order, and tree % that the structure is valid, elements are in order, and tree
% is balanced to the extent guaranteed by AVL trees. I.e., % is balanced to the extent guaranteed by AVL trees. I.e.,
% branches of each subtree differ in depth by at most 1. % branches of each subtree differ in depth by at most 1.
is_assoc(Assoc) :- is_assoc(Assoc) :-
is_assoc(Assoc, _Min, _Max, _Depth). is_assoc(Assoc, _Min, _Max, _Depth).
@@ -154,12 +150,10 @@ balance(=,-).
balance(<,<). balance(<,<).
balance(>,>). balance(>,>).
%! gen_assoc(?Key, +Assoc, ?Value) is nondet. %% gen_assoc(?Key, +Assoc, ?Value) is nondet.
% %
% True if Key-Value is an association in Assoc. Enumerates keys in % True if Key-Value is an association in Assoc. Enumerates keys in
% ascending order on backtracking. % ascending order on backtracking.
%
% @see get_assoc/3.
gen_assoc(Key, Assoc, Value) :- gen_assoc(Key, Assoc, Value) :-
( ground(Key) ( ground(Key)
@@ -174,11 +168,11 @@ gen_assoc_(Key, t(_,_,_,_,R), Val) :-
gen_assoc_(Key, R, Val). gen_assoc_(Key, R, Val).
%! get_assoc(+Key, +Assoc, -Value) is semidet. %% get_assoc(+Key, +Assoc, -Value) is semidet.
% %
% True if Key-Value is an association in Assoc. % True if Key-Value is an association in Assoc.
% %
% @error type_error(assoc, Assoc) if Assoc is not an association list. % Throws error: `type_error(assoc, Assoc)` if Assoc is not an association list.
get_assoc(Key, Assoc, Val) :- get_assoc(Key, Assoc, Val) :-
must_be(assoc, Assoc), must_be(assoc, Assoc),
@@ -204,9 +198,9 @@ get_assoc(>, Key, _, _, Tree, Val) :-
% :- endif. % :- endif.
%! get_assoc(+Key, +Assoc0, ?Val0, ?Assoc, ?Val) is semidet. %% get_assoc(+Key, +Assoc0, ?Val0, ?Assoc, ?Val) is semidet.
% %
% True if Key-Val0 is in Assoc0 and Key-Val is in Assoc. % True if Key-Val0 is in Assoc0 and Key-Val is in Assoc.
get_assoc(Key, t(K,V,B,L,R), Val, t(K,NV,B,NL,NR), NVal) :- get_assoc(Key, t(K,V,B,L,R), Val, t(K,NV,B,NL,NR), NVal) :-
compare(Rel, Key, K), compare(Rel, Key, K),
@@ -219,12 +213,12 @@ get_assoc(>, Key, V, L, R, Val, V, L, NR, NVal) :-
get_assoc(Key, R, Val, NR, NVal). get_assoc(Key, R, Val, NR, NVal).
%! list_to_assoc(+Pairs, -Assoc) is det. %% list_to_assoc(+Pairs, -Assoc) is det.
% %
% Create an association from a list Pairs of Key-Value pairs. List % Create an association from a list Pairs of Key-Value pairs. List
% must not contain duplicate keys. % must not contain duplicate keys.
% %
% @error domain_error(unique_key_pairs, List) if List contains duplicate keys % Throws error: `domain_error(unique_key_pairs, List)` if List contains duplicate keys
list_to_assoc(List, Assoc) :- list_to_assoc(List, Assoc) :-
( List = [] -> Assoc = t ( List = [] -> Assoc = t
@@ -249,13 +243,13 @@ list_to_assoc(N, List, More, Depth, t(K,V,Balance,L,R)) :-
compare(B, RDepth, LDepth), compare(B, RDepth, LDepth),
balance(B, Balance). balance(B, Balance).
%! ord_list_to_assoc(+Pairs, -Assoc) is det. %% ord_list_to_assoc(+Pairs, -Assoc) is det.
% %
% Assoc is created from an ordered list Pairs of Key-Value % Assoc is created from an ordered list Pairs of Key-Value
% pairs. The pairs must occur in strictly ascending order of % pairs. The pairs must occur in strictly ascending order of
% their keys. % their keys.
% %
% @error domain_error(key_ordered_pairs, List) if pairs are not ordered. % Throws error: `domain_error(key_ordered_pairs, List)` if pairs are not ordered.
ord_list_to_assoc(Sorted, Assoc) :- ord_list_to_assoc(Sorted, Assoc) :-
( Sorted = [] -> Assoc = t ( Sorted = [] -> Assoc = t
@@ -266,9 +260,9 @@ ord_list_to_assoc(Sorted, Assoc) :-
) )
). ).
%! ord_pairs(+Pairs) is semidet %% ord_pairs(+Pairs) is semidet
% %
% True if Pairs is a list of Key-Val pairs strictly ordered by key. % True if Pairs is a list of Key-Val pairs strictly ordered by key.
ord_pairs([K-_V|Rest]) :- ord_pairs([K-_V|Rest]) :-
ord_pairs(Rest, K). ord_pairs(Rest, K).
@@ -277,9 +271,9 @@ ord_pairs([K-_V|Rest], K0) :-
K0 @< K, K0 @< K,
ord_pairs(Rest, K). ord_pairs(Rest, K).
%! map_assoc(:Pred, +Assoc) is semidet. %% map_assoc(:Pred, +Assoc) is semidet.
% %
% True if Pred(Value) is true for all values in Assoc. % True if Pred(Value) is true for all values in Assoc.
map_assoc(Pred, T) :- map_assoc(Pred, T) :-
map_assoc_(T, Pred). map_assoc_(T, Pred).
@@ -290,10 +284,10 @@ map_assoc_(t(_,Val,_,L,R), Pred) :-
call(Pred, Val), call(Pred, Val),
map_assoc_(R, Pred). map_assoc_(R, Pred).
%! map_assoc(:Pred, +Assoc0, ?Assoc) is semidet. %% map_assoc(:Pred, +Assoc0, ?Assoc) is semidet.
% %
% Map corresponding values. True if Assoc is Assoc0 with Pred % Map corresponding values. True if Assoc is Assoc0 with Pred
% applied to all corresponding pairs of of values. % applied to all corresponding pairs of of values.
map_assoc(Pred, T0, T) :- map_assoc(Pred, T0, T) :-
map_assoc_(T0, Pred, T). map_assoc_(T0, Pred, T).
@@ -305,9 +299,9 @@ map_assoc_(t(Key,Val,B,L0,R0), Pred, t(Key,Ans,B,L1,R1)) :-
map_assoc_(R0, Pred, R1). map_assoc_(R0, Pred, R1).
%! max_assoc(+Assoc, -Key, -Value) is semidet. %% max_assoc(+Assoc, -Key, -Value) is semidet.
% %
% True if Key-Value is in Assoc and Key is the largest key. % True if Key-Value is in Assoc and Key is the largest key.
max_assoc(t(K,V,_,_,R), Key, Val) :- max_assoc(t(K,V,_,_,R), Key, Val) :-
max_assoc(R, K, V, Key, Val). max_assoc(R, K, V, Key, Val).
@@ -317,9 +311,9 @@ max_assoc(t(K,V,_,_,R), _, _, Key, Val) :-
max_assoc(R, K, V, Key, Val). max_assoc(R, K, V, Key, Val).
%! min_assoc(+Assoc, -Key, -Value) is semidet. %% min_assoc(+Assoc, -Key, -Value) is semidet.
% %
% True if Key-Value is in assoc and Key is the smallest key. % True if Key-Value is in assoc and Key is the smallest key.
min_assoc(t(K,V,_,L,_), Key, Val) :- min_assoc(t(K,V,_,L,_), Key, Val) :-
min_assoc(L, K, V, Key, Val). min_assoc(L, K, V, Key, Val).
@@ -329,10 +323,10 @@ min_assoc(t(K,V,_,L,_), _, _, Key, Val) :-
min_assoc(L, K, V, Key, Val). min_assoc(L, K, V, Key, Val).
%! put_assoc(+Key, +Assoc0, +Value, -Assoc) is det. %% put_assoc(+Key, +Assoc0, +Value, -Assoc) is det.
% %
% Assoc is Assoc0, except that Key is associated with % Assoc is Assoc0, except that Key is associated with
% Value. This can be used to insert and change associations. % Value. This can be used to insert and change associations.
put_assoc(Key, A0, Value, A) :- put_assoc(Key, A0, Value, A) :-
insert(A0, Key, Value, A, _). insert(A0, Key, Value, A, _).
@@ -364,11 +358,11 @@ table(< , right , - , no , no ) :- !.
table(> , left , - , no , no ) :- !. table(> , left , - , no , no ) :- !.
table(> , right , - , no , yes ) :- !. table(> , right , - , no , yes ) :- !.
%! del_min_assoc(+Assoc0, ?Key, ?Val, -Assoc) is semidet. %% del_min_assoc(+Assoc0, ?Key, ?Val, -Assoc) is semidet.
% %
% True if Key-Value is in Assoc0 and Key is the smallest key. % True if Key-Value is in Assoc0 and Key is the smallest key.
% Assoc is Assoc0 with Key-Value removed. Warning: This will % Assoc is Assoc0 with Key-Value removed. Warning: This will
% succeed with _no_ bindings for Key or Val if Assoc0 is empty. % succeed with _no_ bindings for Key or Val if Assoc0 is empty.
del_min_assoc(Tree, Key, Val, NewTree) :- del_min_assoc(Tree, Key, Val, NewTree) :-
del_min_assoc(Tree, Key, Val, NewTree, _DepthChanged). del_min_assoc(Tree, Key, Val, NewTree, _DepthChanged).
@@ -378,11 +372,11 @@ del_min_assoc(t(K,V,B,L,R), Key, Val, NewTree, Changed) :-
del_min_assoc(L, Key, Val, NewL, LeftChanged), del_min_assoc(L, Key, Val, NewL, LeftChanged),
deladjust(LeftChanged, t(K,V,B,NewL,R), left, NewTree, Changed). deladjust(LeftChanged, t(K,V,B,NewL,R), left, NewTree, Changed).
%! del_max_assoc(+Assoc0, ?Key, ?Val, -Assoc) is semidet. %% del_max_assoc(+Assoc0, ?Key, ?Val, -Assoc) is semidet.
% %
% True if Key-Value is in Assoc0 and Key is the greatest key. % True if Key-Value is in Assoc0 and Key is the greatest key.
% Assoc is Assoc0 with Key-Value removed. Warning: This will % Assoc is Assoc0 with Key-Value removed. Warning: This will
% succeed with _no_ bindings for Key or Val if Assoc0 is empty. % succeed with _no_ bindings for Key or Val if Assoc0 is empty.
del_max_assoc(Tree, Key, Val, NewTree) :- del_max_assoc(Tree, Key, Val, NewTree) :-
del_max_assoc(Tree, Key, Val, NewTree, _DepthChanged). del_max_assoc(Tree, Key, Val, NewTree, _DepthChanged).
@@ -392,10 +386,10 @@ del_max_assoc(t(K,V,B,L,R), Key, Val, NewTree, Changed) :-
del_max_assoc(R, Key, Val, NewR, RightChanged), del_max_assoc(R, Key, Val, NewR, RightChanged),
deladjust(RightChanged, t(K,V,B,L,NewR), right, NewTree, Changed). deladjust(RightChanged, t(K,V,B,L,NewR), right, NewTree, Changed).
%! del_assoc(+Key, +Assoc0, ?Value, -Assoc) is semidet. %% del_assoc(+Key, +Assoc0, ?Value, -Assoc) is semidet.
% %
% True if Key-Value is in Assoc0. Assoc is Assoc0 with % True if Key-Value is in Assoc0. Assoc is Assoc0 with
% Key-Value removed. % Key-Value removed.
del_assoc(Key, A0, Value, A) :- del_assoc(Key, A0, Value, A) :-
delete(A0, Key, Value, A, _). delete(A0, Key, Value, A, _).

114
src/lib/atts.pl Normal file
View File

@@ -0,0 +1,114 @@
:- module(atts, [op(1199, fx, attribute),
term_attributed_variables/2]).
:- use_module(library(dcgs)).
:- use_module(library(error)).
:- use_module(library(terms)).
/* represent the list of attributes belonging to a variable,
of a particular module, as a list of terms of the form
Module:put_atts(V, ListOfAtts). */
'$default_attr_list'(Module, V) -->
( { Module:get_atts(V, Attributes) } ->
'$default_attr_list'(Attributes, Module, V)
; []
).
'$default_attr_list'([PG | PGs], Module, AttrVar) -->
[Module:put_atts(AttrVar, PG)],
'$default_attr_list'(PGs, Module, AttrVar).
'$default_attr_list'([], _, _) --> [].
'$absent_attr'(V, Module, Attr) :-
( '$get_from_attr_list'(V, Module, Attr) ->
false
; true
).
'$copy_attr_list'(L, _Module, []) :- var(L), !.
'$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
( Module0 == Module ->
CopiedAtts = [Att|CopiedAtts0],
'$copy_attr_list'(Atts, Module, CopiedAtts0)
; '$copy_attr_list'(Atts, Module, CopiedAtts)
).
user:term_expansion(Term0, Terms) :-
nonvar(Term0),
Term0 = (:- attribute Atts),
nonvar(Atts),
prolog_load_context(module, Module),
phrase(expand_terms(Atts, Module), Terms).
expand_terms(Atts, Module) -->
put_attrs_var_check,
put_attrs(Atts, Module),
get_attrs_var_check(Module),
get_attrs(Atts, Module).
put_attrs_var_check -->
[(put_atts(Var, Attr) :- nonvar(Var),
throw(error(uninstantiation_error(Var), put_atts/2))),
(put_atts(Var, Attr) :- var(Attr),
throw(error(instantiation_error, put_atts/2)))].
get_attrs_var_check(Module) -->
[(get_atts(Var, Attr) :- nonvar(Var),
throw(error(uninstantiation_error(Var), get_atts/2))),
(get_atts(Var, Attr) :- var(Attr),
!,
'$get_attr_list'(Var, Ls),
nonvar(Ls),
atts:'$copy_attr_list'(Ls, Module, Attr))].
put_attrs(Name/Arity, Module) -->
put_attr(Name, Arity, Module),
[(put_atts(Var, Attr) :- lists:maplist(Module:put_atts(Var), Attr), !)].
put_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) },
put_attr(Name, Arity, Module),
put_attrs(Atts, Module).
get_attrs(Name/Arity, Module) -->
get_attr(Name, Arity, Module).
get_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) },
get_attr(Name, Arity, Module),
get_attrs(Atts, Module).
put_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
[(put_atts(V, +Attr) :-
!,
'$put_to_attr_list'(V, Module, Attr)),
(put_atts(V, Attr) :-
!,
'$put_to_attr_list'(V, Module, Attr)),
(put_atts(V, -Attr) :-
!,
'$del_from_attr_list'(V, Module, Attr))].
get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
[(get_atts(V, +Attr) :-
!,
functor(Attr, _, _),
atts:'$get_from_attr_list'(V, Module, Attr)),
(get_atts(V, Attr) :-
!,
functor(Attr, _, _),
atts:'$get_from_attr_list'(V, Module, Attr)),
(get_atts(V, -Attr) :-
!,
functor(Attr, _, _),
atts:'$absent_attr'(V, Module, Attr))].
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
nonvar(Term),
Term = put_atts(Var, M, Attr).
user:goal_expansion(Term, M:get_atts(Var, Attr)) :-
nonvar(Term),
Term = get_atts(Var, M, Attr).
term_attributed_variables(Term, Vars) :-
'$term_attributed_variables'(Term, Vars).

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