288 Commits

Author SHA1 Message Date
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
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
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
Nicolas Luck
7e97f16f41 Fix list result parsing 2023-08-22 22:46:00 +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
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
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
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
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
Nicolas Luck
9e85be11fe Fix result parsing for complex string results 2023-07-21 14:35:44 +02:00
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
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
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
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
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
82 changed files with 17973 additions and 11616 deletions

View File

@@ -14,22 +14,27 @@ jobs:
build-test: build-test:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false
matrix: matrix:
include: include:
- { os: windows-latest, rust-version: stable, shell: 'msys2 {0}', target: 'x86_64-pc-windows-gnu'} # operating systems
- { os: macos-11, rust-version: stable, shell: bash, target: 'x86_64-apple-darwin' } - { os: windows-latest, rust-version: stable, publish: true, target: 'x86_64-pc-windows-msvc'}
- { os: ubuntu-20.04, rust-version: stable, shell: bash, extra: true, target: 'x86_64-unknown-linux-gnu' } - { os: macos-11, rust-version: stable, publish: true, target: 'x86_64-apple-darwin' }
- { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'i686-unknown-linux-gnu' } - { os: ubuntu-20.04, rust-version: stable, publish: true, target: 'x86_64-unknown-linux-gnu' }
- { os: ubuntu-20.04, rust-version: 1.65, shell: bash, target: 'x86_64-unknown-linux-gnu'} # architectures
- { os: ubuntu-20.04, rust-version: beta, shell: bash, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: stable, publish: true, target: 'x86_64-unknown-linux-gnu', extra: true }
- { os: ubuntu-20.04, rust-version: nightly, shell: bash, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: stable, publish: true, target: 'i686-unknown-linux-gnu' }
- { os: ubuntu-22.04, rust-version: nightly, publish: true, target: 'wasm32-unknown-unknown', args: '--no-default-features' }
# rust versions
- { os: ubuntu-22.04, rust-version: "1.70", 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'}
defaults: defaults:
run: run:
shell: ${{ matrix.shell }} shell: bash
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master - uses: dtolnay/rust-toolchain@master
if: "!contains(matrix.os,'windows')"
id: toolchain id: toolchain
with: with:
toolchain: ${{ matrix.rust-version }} toolchain: ${{ matrix.rust-version }}
@@ -37,14 +42,12 @@ jobs:
components: clippy, rustfmt components: clippy, rustfmt
- name: Install i686 dependencies - name: Install i686 dependencies
if: "contains(matrix.target,'i686')" if: "contains(matrix.target,'i686')"
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 run: |
- uses: msys2/setup-msys2@v2 sudo dpkg --add-architecture i386
if: contains(matrix.os,'windows') sudo apt-get update
with: sudo apt-get install libssl-dev:i386 gcc-multilib clang -y
update: true echo "CC=clang" >> $GITHUB_ENV
install: >- echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV
base-devel
mingw-w64-x86_64-rust
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: | path: |
@@ -57,10 +60,10 @@ jobs:
# Build and test. # Build and test.
- name: Build library - name: Build library
run: cargo rustc --target ${{ matrix.target }} --verbose --lib -- -D warnings run: cargo rustc --lib --target ${{ matrix.target }} ${{ matrix.args }} --verbose
- name: Test - name: Test
if: "!matrix.extra" if: "!matrix.extra"
run: cargo test --target ${{ matrix.target }} --all --verbose run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all --verbose || echo "::warning ::Tests failed"
# Extra steps only run once to avoid duplication, when matrix.extra is true # Extra steps only run once to avoid duplication, when matrix.extra is true
- name: Test and report - name: Test and report
@@ -93,18 +96,19 @@ jobs:
# artifact. These binaries could be useful for testing the pipeline but # artifact. These binaries could be useful for testing the pipeline but
# are only retained by github for 90 days. # are only retained by github for 90 days.
- name: Build release binary - name: Build release binary
if: contains(matrix.rust-version,'stable') if: matrix.publish
run: | run: |
cargo rustc --target ${{ matrix.target }} --verbose --bin scryer-prolog --release -- -D warnings cargo rustc --target ${{ matrix.target }} ${{ matrix.args }} --verbose --bin scryer-prolog --release
echo "$PWD/target/release" >> $GITHUB_PATH echo "$PWD/target/release" >> $GITHUB_PATH
- name: Publish release binary artifact - name: Publish release binary artifact
if: contains(matrix.rust-version,'stable') if: matrix.publish
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
path: target/${{ matrix.target }}/release/scryer-prolog* path: target/${{ matrix.target }}/release/scryer-prolog*
name: scryer-prolog_${{ matrix.os }}_${{ matrix.target }} name: scryer-prolog_${{ matrix.os }}_${{ matrix.target }}
logtalk-test: logtalk-test:
# if: false # uncomment to disable job
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
needs: [build-test] needs: [build-test]
steps: steps:
@@ -118,7 +122,7 @@ jobs:
- name: Install Logtalk - name: Install Logtalk
uses: logtalk-actions/setup-logtalk@master uses: logtalk-actions/setup-logtalk@master
with: with:
logtalk-version: git logtalk-version: "3.70.0"
logtalk-tool-dependencies: false logtalk-tool-dependencies: false
# Run logtalk tests. # Run logtalk tests.
@@ -161,11 +165,15 @@ jobs:
run: | run: |
zip scryer-prolog_macos-11.zip ./scryer-prolog_macos-11_x86_64-apple-darwin/scryer-prolog zip scryer-prolog_macos-11.zip ./scryer-prolog_macos-11_x86_64-apple-darwin/scryer-prolog
zip scryer-prolog_ubuntu-20.04.zip ./scryer-prolog_ubuntu-20.04_x86_64-unknown-linux-gnu/scryer-prolog zip scryer-prolog_ubuntu-20.04.zip ./scryer-prolog_ubuntu-20.04_x86_64-unknown-linux-gnu/scryer-prolog
zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-gnu/scryer-prolog.exe zip scryer-prolog_ubuntu-22.04.zip ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/scryer-prolog
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 - name: Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
files: | files: |
scryer-prolog_macos-11.zip scryer-prolog_macos-11.zip
scryer-prolog_ubuntu-20.04.zip scryer-prolog_ubuntu-20.04.zip
scryer-prolog_ubuntu-22.04.zip
scryer-prolog_windows-latest.zip scryer-prolog_windows-latest.zip
scryer-prolog_wasm32.zip

643
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.9.2" version = "0.9.3"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021" edition = "2021"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
@@ -10,15 +10,20 @@ license = "BSD-3-Clause"
keywords = ["prolog", "prolog-interpreter", "prolog-system"] keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"] categories = ["command-line-utilities"]
build = "build/main.rs" build = "build/main.rs"
rust-version = "1.63" rust-version = "1.70"
[lib]
crate-type = ["cdylib", "rlib"]
[features] [features]
default = ["ffi", "repl", "hostname", "tls", "http"] default = ["ffi", "repl", "hostname", "tls", "http", "crypto-full"]
ffi = ["dep:libffi"] ffi = ["dep:libffi"]
repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"] repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
hostname = ["dep:hostname"] hostname = ["dep:hostname"]
tls = ["dep:native-tls"] tls = ["dep:native-tls"]
http = ["dep:hyper", "dep:reqwest"] http = ["dep:warp", "dep:reqwest"]
rust_beta_channel = []
crypto-full = []
[build-dependencies] [build-dependencies]
indexmap = "1.0.2" indexmap = "1.0.2"
@@ -26,9 +31,9 @@ proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
strum = "0.23" strum = "0.23"
strum_macros = "0.23" strum_macros = "0.23"
syn = { version = "1.0.88", features = ['full', 'visit', 'extra-traits'] } syn = { version = "2.0.32", features = ['full', 'visit', 'extra-traits'] }
to-syn-value = "0.1.0" to-syn-value = "0.1.1"
to-syn-value_derive = "0.1.0" to-syn-value_derive = "0.1.1"
walkdir = "2" walkdir = "2"
[dependencies] [dependencies]
@@ -59,21 +64,22 @@ smallvec = "1.8.0"
static_assertions = "1.1.0" static_assertions = "1.1.0"
ryu = "1.0.9" ryu = "1.0.9"
futures = "0.3" futures = "0.3"
regex = "1.9.1"
libloading = "0.7" libloading = "0.7"
derive_deref = "1.1.1" derive_deref = "1.1.1"
http-body-util = "0.1.0-rc.2"
bytes = "1" bytes = "1"
dashu = { git = "https://github.com/coasys/dashu.git", version = "0.3.1" } dashu = "0.4.0"
num-order = { version = "1.2.0" }
rand = "0.8.5" rand = "0.8.5"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libffi = { git = "https://github.com/coasys/libffi-rs.git", branch = "windows-space", optional = true, version = "3.2.0" } libffi = { version = "3.2.0", optional = true }
hostname = { version = "0.3.1", optional = true } hostname = { version = "0.3.1", optional = true }
crossterm = { version = "0.20.0", optional = true } crossterm = { version = "0.20.0", optional = true }
ctrlc = { version = "3.2.2", optional = true } ctrlc = { version = "3.2.2", optional = true }
rustyline = { version = "12.0.0", optional = true } rustyline = { version = "12.0.0", optional = true }
native-tls = { version = "0.2.4", optional = true } native-tls = { version = "0.2.4", optional = true }
hyper = { version = "=1.0.0-rc.3", features = ["full"], optional = true } warp = { version = "=0.3.5", features = ["tls"], optional = true }
reqwest = { version = "0.11.18", features = ["blocking"], optional = true } reqwest = { version = "0.11.18", features = ["blocking"], optional = true }
tokio = { version = "1.28.2", features = ["full"] } tokio = { version = "1.28.2", features = ["full"] }
@@ -81,6 +87,18 @@ tokio = { version = "1.28.2", features = ["full"] }
getrandom = { version = "0.2.10", features = ["js"] } getrandom = { version = "0.2.10", features = ["js"] }
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] } tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] }
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
console_error_panic_hook = "0.1"
console_log = "1.0"
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4"
serde-wasm-bindgen = "0.5"
web-sys = { version = "0.3", features = [
"Document",
"Window",
"Element",
]}
[target.'cfg(target_os = "wasi")'.dependencies] [target.'cfg(target_os = "wasi")'.dependencies]
ring-wasi = { version = "0.16.25" } ring-wasi = { version = "0.16.25" }
@@ -90,10 +108,8 @@ ring = { version = "0.16.13" }
[dev-dependencies] [dev-dependencies]
assert_cmd = "1.0.3" assert_cmd = "1.0.3"
predicates-core = "1.0.2" predicates-core = "1.0.2"
maplit = "1.0.2"
serial_test = "2.0.0" serial_test = "2.0.0"
[patch.crates-io] [patch.crates-io]
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
[profile.release]
debug = true

View File

@@ -20,7 +20,12 @@ COPY --from=cacher /scryer-prolog/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME COPY --from=cacher $CARGO_HOME $CARGO_HOME
RUN cargo build --release --bin scryer-prolog RUN cargo build --release --bin scryer-prolog
FROM debian:stable-slim # Newer versions of Debian (i.e. bookworm) contain libssl3 instead of libssl1.1
# which we depend on.
FROM debian:bullseye-slim
COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin
ENV RUST_BACKTRACE=1 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"] ENTRYPOINT ["/usr/local/bin/scryer-prolog"]

View File

@@ -26,9 +26,13 @@ Some of the Scryer Prolog features are:
* Compact string representation * Compact string representation
* Network libraries ([TCP sockets](/sockets.html), [HTTP server](/http/http_server.html), [HTTP client](/http/http_open.html), ...) * Network libraries ([TCP sockets](/sockets.html), [HTTP server](/http/http_server.html), [HTTP client](/http/http_open.html), ...)
* [Cryptographical predicates](/crypto.html) * [Cryptographical predicates](/crypto.html)
* [Foreign Function Interface](/ffi.html)
* WebAssembly support
* WAM based engine, cross-platform made in Rust * WAM based engine, cross-platform made in Rust
* _and more..._ * _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? ## 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. 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.
@@ -57,9 +61,13 @@ the builtin Prolog modules and libraries in Scryer, check the documentation site
## Downloads ## Downloads
The latest version of Scryer Prolog is *0.9.1*. And it's already useful for lots of tasks. The latest version of Scryer Prolog is *0.9.2*. And it's already useful for lots of tasks.
Scryer Prolog can 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. | Windows | [Download](https://github.com/mthom/scryer-prolog/releases/download/v0.9.2/scryer-prolog_windows-latest.zip) |
| macOS (Intel) | [Download](https://github.com/mthom/scryer-prolog/releases/download/v0.9.2/scryer-prolog_macos-11.zip) |
| Linux | [Download](https://github.com/mthom/scryer-prolog/releases/download/v0.9.2/scryer-prolog_ubuntu-20.04.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. If you're in Linux, maybe your distribution already has an Scryer Prolog package.

100
README.md
View File

@@ -105,7 +105,14 @@ strings.
## Installing Scryer Prolog ## Installing Scryer Prolog
### Native Install ### Binaries
Precompiled binaries for several platforms are available for download
at:
**https://github.com/mthom/scryer-prolog/releases/tag/v0.9.2**
### Native Compilation
First, install the latest stable version of First, install the latest stable version of
[Rust](https://www.rust-lang.org/en-US/install.html) using your [Rust](https://www.rust-lang.org/en-US/install.html) using your
@@ -143,7 +150,78 @@ light.exe scryer-prolog.wixobj
``` ```
It will generate a very basic MSI file which installs the main executable and a shortcut in the Start Menu. It can be installed with a double-click. To uninstall, go to the Control Panel and uninstall as usual. It will generate a very basic MSI file which installs the main executable and a shortcut in the Start Menu. It can be installed with a double-click. To uninstall, go to the Control Panel and uninstall as usual.
Scryer Prolog must be built with **Rust 1.63 and up**. Scryer Prolog must be built with **Rust 1.70 and up**.
### Building WebAssembly
Scryer Prolog has basic WebAssembly support. You can follow `wasm-pack`'s [official instructions](https://rustwasm.github.io/docs/wasm-pack/quickstart.html) to install `wasm-pack` and build it in any way you like.
However, none of the [default features](https://doc.rust-lang.org/cargo/reference/features.html#the-default-feature) are currently supported. The preferred way of disabling them is passing [extra options](https://rustwasm.github.io/wasm-pack/book/commands/build.html#extra-options) to `wasm-pack`.
For example, if you want a minimal working package without using any bundler like `webpack`, you can do this:
```
wasm-pack build --target web -- --no-default-features
```
Then a `pkg` directory will be created, containing everything you need for a webapp. You can test whether the package is successfully built by creating an html file, adapted from `wasm-bindgen`'s [official example](https://rustwasm.github.io/wasm-bindgen/examples/without-a-bundler.html) like this:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Scryer Prolog - Sudoku Solver Example</title>
<script type="module">
import init, { eval_code } from './pkg/scryer_prolog.js';
const run = async () => {
await init("./pkg/scryer_prolog_bg.wasm");
let code = `
:- use_module(library(format)).
:- use_module(library(clpz)).
:- use_module(library(lists)).
sudoku(Rows) :-
length(Rows, 9), maplist(same_length(Rows), Rows),
append(Rows, Vs), Vs ins 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct, Columns),
Rows = [As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is],
blocks(As, Bs, Cs),
blocks(Ds, Es, Fs),
blocks(Gs, Hs, Is).
blocks([], [], []).
blocks([N1,N2,N3|Ns1], [N4,N5,N6|Ns2], [N7,N8,N9|Ns3]) :-
all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]),
blocks(Ns1, Ns2, Ns3).
problem(1, [[_,_,_,_,_,_,_,_,_],
[_,_,_,_,_,3,_,8,5],
[_,_,1,_,2,_,_,_,_],
[_,_,_,5,_,7,_,_,_],
[_,_,4,_,_,_,1,_,_],
[_,9,_,_,_,_,_,_,_],
[5,_,_,_,_,_,_,7,3],
[_,_,2,_,1,_,_,_,_],
[_,_,_,_,4,_,_,_,9]]).
main :-
problem(1, Rows), sudoku(Rows), maplist(portray_clause, Rows).
:- initialization(main).
`;
const result = eval_code(code);
document.write(`<p>Sudoku solver returns:</p><pre>${result}</pre>`);
}
run();
</script>
</head>
<body></body>
</html>
```
Then you can serve it with your favorite http server like `python -m http.server` or `npx serve`, and access the page with your browser.
### Docker Install ### Docker Install
@@ -285,14 +363,14 @@ innovations of Scryer Prolog. This means that terms which appear as
lists of characters to Prolog programs are stored in packed lists of characters to Prolog programs are stored in packed
UTF-8&nbsp;encoding by the engine. UTF-8&nbsp;encoding by the engine.
Without this innovation, storing a list of characters in memory Without this innovation, storing a list of characters in memory would
would use one memory&nbsp;cell per character, one memory&nbsp;cell per use one WAM memory&nbsp;cell per character, one cell per list
list constructor, and one memory&nbsp;cell for each tail that occurs constructor, and one cell for each tail that occurs in the list. Since
in the list. Since one memory&nbsp;cell takes 8&nbsp;bytes on 64-bit one cell takes 8&nbsp;bytes in the WAM as implemented by
machines, the packed representation used by Scryer&nbsp;Prolog yields Scryer&nbsp;Prolog, the packed representation yields an up&nbsp;to
an up&nbsp;to **24-fold&nbsp;reduction** of memory usage, and **24-fold&nbsp;reduction** of memory usage, and corresponding
corresponding reduction of memory&nbsp;accesses when creating and reduction of memory&nbsp;accesses when creating and processing
processing strings. strings.
Scryer Prolog's compact internal string representation makes it Scryer Prolog's compact internal string representation makes it
ideally suited for the use case Prolog was originally developed for: ideally suited for the use case Prolog was originally developed for:
@@ -546,7 +624,7 @@ The modules that ship with Scryer&nbsp;Prolog are also called
Probabilistic predicates and random number generators. Probabilistic predicates and random number generators.
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to * [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
read answers from web&nbsp;servers. HTTPS is also supported. read answers from web&nbsp;servers. HTTPS is also supported.
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Hyper](https://hyper.rs) as a backend. Supports some query and form handling. * [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Warp](https://github.com/seanmonstar/warp) as a backend. Supports some query and form handling.
* [`sgml`](src/lib/sgml.pl) * [`sgml`](src/lib/sgml.pl)
`load_html/3` and `load_xml/3` represent HTML and XML&nbsp;documents `load_html/3` and `load_xml/3` represent HTML and XML&nbsp;documents
as Prolog&nbsp;terms for convenient and efficient reasoning. Use as Prolog&nbsp;terms for convenient and efficient reasoning. Use

View File

@@ -99,6 +99,8 @@ enum BuiltInClauseType {
Ground, Ground,
#[strum_discriminants(strum(props(Arity = "2", Name = "is")))] #[strum_discriminants(strum(props(Arity = "2", Name = "is")))]
Is(RegType, ArithmeticTerm), Is(RegType, ArithmeticTerm),
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_number")))]
GetNumber(ArithmeticTerm),
#[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))] #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))]
KeySort, KeySort,
#[strum_discriminants(strum(props(Arity = "2", Name = "sort")))] #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))]
@@ -304,7 +306,7 @@ enum SystemClauseType {
GetBValue, GetBValue,
#[strum_discriminants(strum(props(Arity = "3", Name = "$get_cont_chunk")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$get_cont_chunk")))]
GetContinuationChunk, GetContinuationChunk,
#[strum_discriminants(strum(props(Arity = "7", Name = "$get_next_op_db_ref")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$get_next_op_db_ref")))]
GetNextOpDBRef, GetNextOpDBRef,
#[strum_discriminants(strum(props(Arity = "3", Name = "$lookup_db_ref")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$lookup_db_ref")))]
LookupDBRef, LookupDBRef,
@@ -494,22 +496,28 @@ enum SystemClauseType {
CryptoDataHKDF, CryptoDataHKDF,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
CryptoPasswordHash, CryptoPasswordHash,
#[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))]
CryptoDataEncrypt,
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
CryptoCurveScalarMult, CryptoCurveScalarMult,
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
Ed25519Sign,
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
Ed25519Verify,
#[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
Ed25519NewKeyPair,
#[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
Ed25519KeyPairPublicKey,
#[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))]
Curve25519ScalarMult, Curve25519ScalarMult,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))]
CryptoDataEncrypt,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
Ed25519Sign,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
Ed25519Verify,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
Ed25519NewKeyPair,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
Ed25519KeyPairPublicKey,
#[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))] #[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
FirstNonOctet, FirstNonOctet,
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
@@ -550,7 +558,7 @@ enum SystemClauseType {
DeterministicLengthRundown, DeterministicLengthRundown,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))] #[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
HttpOpen, HttpOpen,
#[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))] #[strum_discriminants(strum(props(Arity = "5", Name = "$http_listen")))]
HttpListen, HttpListen,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))] #[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
HttpAccept, HttpAccept,
@@ -566,7 +574,7 @@ enum SystemClauseType {
PredicateDefined, PredicateDefined,
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
StripModule, StripModule,
#[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))] #[strum_discriminants(strum(props(Arity = "5", Name = "$compile_inline_or_expanded_goal")))]
CompileInlineOrExpandedGoal, CompileInlineOrExpandedGoal,
#[strum_discriminants(strum(props(Arity = "arity", Name = "$fast_call")))] #[strum_discriminants(strum(props(Arity = "arity", Name = "$fast_call")))]
FastCallN(usize), FastCallN(usize),
@@ -588,8 +596,13 @@ enum SystemClauseType {
UnattributedVar, UnattributedVar,
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
GetDBRefs, GetDBRefs,
#[strum_discriminants(strum(props(Arity = "2", Name = "$keysort_with_constant_var_ordering")))] #[strum_discriminants(strum(props(
Arity = "2",
Name = "$keysort_with_constant_var_ordering"
)))]
KeySortWithConstantVarOrdering, KeySortWithConstantVarOrdering,
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
InferenceLimitExceeded,
REPL(REPLCodePtr), REPL(REPLCodePtr),
} }
@@ -647,6 +660,8 @@ enum InstructionTemplate {
// cut instruction // cut instruction
#[strum_discriminants(strum(props(Arity = "1", Name = "cut")))] #[strum_discriminants(strum(props(Arity = "1", Name = "cut")))]
Cut(RegType), Cut(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "cut_prev")))]
CutPrev(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))] #[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))]
GetLevel(RegType), GetLevel(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "get_prev_level")))] #[strum_discriminants(strum(props(Arity = "1", Name = "get_prev_level")))]
@@ -751,20 +766,6 @@ enum InstructionTemplate {
Neg(ArithmeticTerm, usize), Neg(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "plus")))] #[strum_discriminants(strum(props(Arity = "1", Name = "plus")))]
Plus(ArithmeticTerm, usize), Plus(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "acosh")))]
ACosh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "asinh")))]
ASinh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "atanh")))]
ATanh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "cosh")))]
Cosh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "sinh")))]
Sinh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "tanh")))]
Tanh(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "log10")))]
Log10(ArithmeticTerm, usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "bitwise_complement")))] #[strum_discriminants(strum(props(Arity = "1", Name = "bitwise_complement")))]
BitwiseComplement(ArithmeticTerm, usize), BitwiseComplement(ArithmeticTerm, usize),
// control instructions // control instructions
@@ -799,7 +800,7 @@ enum InstructionTemplate {
} }
fn derive_input(ty: &Type) -> Option<DeriveInput> { fn derive_input(ty: &Type) -> Option<DeriveInput> {
let clause_type: Type = parse_quote!{ ClauseType }; let clause_type: Type = parse_quote! { ClauseType };
let built_in_clause_type: Type = parse_quote! { BuiltInClauseType }; let built_in_clause_type: Type = parse_quote! { BuiltInClauseType };
let inlined_clause_type: Type = parse_quote! { InlinedClauseType }; let inlined_clause_type: Type = parse_quote! { InlinedClauseType };
let system_clause_type: Type = parse_quote! { SystemClauseType }; let system_clause_type: Type = parse_quote! { SystemClauseType };
@@ -845,7 +846,8 @@ fn add_discriminant_data<DiscriminantT>(
prefix: &'static str, prefix: &'static str,
variant_data: &mut Vec<(&'static str, Arity, Variant)>, variant_data: &mut Vec<(&'static str, Arity, Variant)>,
) -> (&'static str, Arity) ) -> (&'static str, Arity)
where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug where
DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug,
{ {
let name = prop_from_ident::<DiscriminantT>(&variant.ident, "Name"); let name = prop_from_ident::<DiscriminantT>(&variant.ident, "Name");
let arity = Arity::from(prop_from_ident::<DiscriminantT>(&variant.ident, "Arity")); let arity = Arity::from(prop_from_ident::<DiscriminantT>(&variant.ident, "Arity"));
@@ -946,7 +948,9 @@ fn generate_instruction_preface() -> TokenStream {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum IndexedChoiceInstruction { pub enum IndexedChoiceInstruction {
Retry(usize), Retry(usize),
DefaultRetry(usize),
Trust(usize), Trust(usize),
DefaultTrust(usize),
Try(usize), Try(usize),
} }
@@ -956,6 +960,8 @@ fn generate_instruction_preface() -> TokenStream {
&IndexedChoiceInstruction::Retry(offset) => offset, &IndexedChoiceInstruction::Retry(offset) => offset,
&IndexedChoiceInstruction::Trust(offset) => offset, &IndexedChoiceInstruction::Trust(offset) => offset,
&IndexedChoiceInstruction::Try(offset) => offset, &IndexedChoiceInstruction::Try(offset) => offset,
&IndexedChoiceInstruction::DefaultRetry(offset) => offset,
&IndexedChoiceInstruction::DefaultTrust(offset) => offset,
} }
} }
@@ -970,6 +976,12 @@ fn generate_instruction_preface() -> TokenStream {
&IndexedChoiceInstruction::Retry(offset) => { &IndexedChoiceInstruction::Retry(offset) => {
functor!(atom!("retry"), [fixnum(offset)]) functor!(atom!("retry"), [fixnum(offset)])
} }
&IndexedChoiceInstruction::DefaultTrust(offset) => {
functor!(atom!("default_trust"), [fixnum(offset)])
}
&IndexedChoiceInstruction::DefaultRetry(offset) => {
functor!(atom!("default_retry"), [fixnum(offset)])
}
} }
} }
} }
@@ -1323,6 +1335,10 @@ fn generate_instruction_preface() -> TokenStream {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut"), [str(h, 0)], [rt_stub]) functor!(atom!("cut"), [str(h, 0)], [rt_stub])
} }
&Instruction::CutPrev(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut_prev"), [str(h, 0)], [rt_stub])
}
&Instruction::GetLevel(r) => { &Instruction::GetLevel(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
@@ -1425,30 +1441,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ATan(ref at, t) => { &Instruction::ATan(ref at, t) => {
arith_instr_unary_functor(h, atom!("atan"), arena, at, t) arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
} }
&Instruction::ACosh(ref at, t) => {
arith_instr_unary_functor(h, atom!("acosh"), arena, at, t)
}
&Instruction::ASinh(ref at, t) => {
arith_instr_unary_functor(h, atom!("asinh"), arena, at, t)
}
&Instruction::ATanh(ref at, t) => {
arith_instr_unary_functor(h, atom!("atanh"), arena, at, t)
}
&Instruction::Cosh(ref at, t) => {
arith_instr_unary_functor(h, atom!("cosh"), arena, at, t)
}
&Instruction::Sinh(ref at, t) => {
arith_instr_unary_functor(h, atom!("sinh"), arena, at, t)
}
&Instruction::Tanh(ref at, t) => {
arith_instr_unary_functor(h, atom!("tanh"), arena, at, t)
}
&Instruction::Sqrt(ref at, t) => { &Instruction::Sqrt(ref at, t) => {
arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
} }
&Instruction::Log10(ref at, t) => {
arith_instr_unary_functor(h, atom!("log10"), arena, at, t)
}
&Instruction::Abs(ref at, t) => { &Instruction::Abs(ref at, t) => {
arith_instr_unary_functor(h, atom!("abs"), arena, at, t) arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
} }
@@ -1553,7 +1548,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallFunctor | &Instruction::CallFunctor |
&Instruction::CallGround | &Instruction::CallGround |
&Instruction::CallKeySort | &Instruction::CallKeySort |
&Instruction::CallSort => { &Instruction::CallSort |
&Instruction::CallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)]) functor!(atom!("call"), [atom(name), fixnum(arity)])
} }
@@ -1578,7 +1574,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteGround | &Instruction::ExecuteGround |
&Instruction::ExecuteIs(..) | &Instruction::ExecuteIs(..) |
&Instruction::ExecuteKeySort | &Instruction::ExecuteKeySort |
&Instruction::ExecuteSort => { &Instruction::ExecuteSort |
&Instruction::ExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)]) functor!(atom!("execute"), [atom(name), fixnum(arity)])
} }
@@ -1603,7 +1600,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultCallGround | &Instruction::DefaultCallGround |
&Instruction::DefaultCallIs(..) | &Instruction::DefaultCallIs(..) |
&Instruction::DefaultCallKeySort | &Instruction::DefaultCallKeySort |
&Instruction::DefaultCallSort => { &Instruction::DefaultCallSort |
&Instruction::DefaultCallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("call_default"), [atom(name), fixnum(arity)]) functor!(atom!("call_default"), [atom(name), fixnum(arity)])
} }
@@ -1628,33 +1626,36 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultExecuteGround | &Instruction::DefaultExecuteGround |
&Instruction::DefaultExecuteIs(..) | &Instruction::DefaultExecuteIs(..) |
&Instruction::DefaultExecuteKeySort | &Instruction::DefaultExecuteKeySort |
&Instruction::DefaultExecuteSort => { &Instruction::DefaultExecuteSort |
&Instruction::DefaultExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
} }
&Instruction::CallIsAtom(_) | &Instruction::CallIsAtom(r) |
&Instruction::CallIsAtomic(_) | &Instruction::CallIsAtomic(r) |
&Instruction::CallIsCompound(_) | &Instruction::CallIsCompound(r) |
&Instruction::CallIsInteger(_) | &Instruction::CallIsInteger(r) |
&Instruction::CallIsNumber(_) | &Instruction::CallIsNumber(r) |
&Instruction::CallIsRational(_) | &Instruction::CallIsRational(r) |
&Instruction::CallIsFloat(_) | &Instruction::CallIsFloat(r) |
&Instruction::CallIsNonVar(_) | &Instruction::CallIsNonVar(r) |
&Instruction::CallIsVar(_) => { &Instruction::CallIsVar(r) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)]) let rt_stub = reg_type_into_functor(r);
functor!(atom!("call"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
} }
&Instruction::ExecuteIsAtom(_) | &Instruction::ExecuteIsAtom(r) |
&Instruction::ExecuteIsAtomic(_) | &Instruction::ExecuteIsAtomic(r) |
&Instruction::ExecuteIsCompound(_) | &Instruction::ExecuteIsCompound(r) |
&Instruction::ExecuteIsInteger(_) | &Instruction::ExecuteIsInteger(r) |
&Instruction::ExecuteIsNumber(_) | &Instruction::ExecuteIsNumber(r) |
&Instruction::ExecuteIsRational(_) | &Instruction::ExecuteIsRational(r) |
&Instruction::ExecuteIsFloat(_) | &Instruction::ExecuteIsFloat(r) |
&Instruction::ExecuteIsNonVar(_) | &Instruction::ExecuteIsNonVar(r) |
&Instruction::ExecuteIsVar(_) => { &Instruction::ExecuteIsVar(r) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)]) let rt_stub = reg_type_into_functor(r);
functor!(atom!("execute"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
} }
// //
&Instruction::CallAtomChars | &Instruction::CallAtomChars |
@@ -1683,7 +1684,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallMakeDirectoryPath | &Instruction::CallMakeDirectoryPath |
&Instruction::CallDeleteFile | &Instruction::CallDeleteFile |
&Instruction::CallRenameFile | &Instruction::CallRenameFile |
&Instruction::CallFileCopy | &Instruction::CallFileCopy |
&Instruction::CallWorkingDirectory | &Instruction::CallWorkingDirectory |
&Instruction::CallDeleteDirectory | &Instruction::CallDeleteDirectory |
&Instruction::CallPathCanonical | &Instruction::CallPathCanonical |
@@ -1701,6 +1702,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallUnattributedVar | &Instruction::CallUnattributedVar |
&Instruction::CallGetDBRefs | &Instruction::CallGetDBRefs |
&Instruction::CallKeySortWithConstantVarOrdering | &Instruction::CallKeySortWithConstantVarOrdering |
&Instruction::CallInferenceLimitExceeded |
&Instruction::CallFetchGlobalVar | &Instruction::CallFetchGlobalVar |
&Instruction::CallFirstStream | &Instruction::CallFirstStream |
&Instruction::CallFlushOutput | &Instruction::CallFlushOutput |
@@ -1777,9 +1779,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallHttpListen | &Instruction::CallHttpListen |
&Instruction::CallHttpAccept | &Instruction::CallHttpAccept |
&Instruction::CallHttpAnswer | &Instruction::CallHttpAnswer |
&Instruction::CallLoadForeignLib | &Instruction::CallLoadForeignLib |
&Instruction::CallForeignCall | &Instruction::CallForeignCall |
&Instruction::CallDefineForeignStruct | &Instruction::CallDefineForeignStruct |
&Instruction::CallPredicateDefined | &Instruction::CallPredicateDefined |
&Instruction::CallStripModule | &Instruction::CallStripModule |
&Instruction::CallCurrentTime | &Instruction::CallCurrentTime |
@@ -1822,13 +1824,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallCryptoDataHash | &Instruction::CallCryptoDataHash |
&Instruction::CallCryptoDataHKDF | &Instruction::CallCryptoDataHKDF |
&Instruction::CallCryptoPasswordHash | &Instruction::CallCryptoPasswordHash |
&Instruction::CallCryptoDataEncrypt |
&Instruction::CallCryptoDataDecrypt |
&Instruction::CallCryptoCurveScalarMult | &Instruction::CallCryptoCurveScalarMult |
&Instruction::CallEd25519Sign |
&Instruction::CallEd25519Verify |
&Instruction::CallEd25519NewKeyPair |
&Instruction::CallEd25519KeyPairPublicKey |
&Instruction::CallCurve25519ScalarMult | &Instruction::CallCurve25519ScalarMult |
&Instruction::CallFirstNonOctet | &Instruction::CallFirstNonOctet |
&Instruction::CallLoadHTML | &Instruction::CallLoadHTML |
@@ -1885,6 +1881,17 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("call"), [atom(name), fixnum(arity)]) functor!(atom!("call"), [atom(name), fixnum(arity)])
} }
// //
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataEncrypt |
&Instruction::CallCryptoDataDecrypt |
&Instruction::CallEd25519Sign |
&Instruction::CallEd25519Verify |
&Instruction::CallEd25519NewKeyPair |
&Instruction::CallEd25519KeyPairPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
}
//
&Instruction::ExecuteAtomChars | &Instruction::ExecuteAtomChars |
&Instruction::ExecuteAtomCodes | &Instruction::ExecuteAtomCodes |
&Instruction::ExecuteAtomLength | &Instruction::ExecuteAtomLength |
@@ -1911,7 +1918,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteMakeDirectoryPath | &Instruction::ExecuteMakeDirectoryPath |
&Instruction::ExecuteDeleteFile | &Instruction::ExecuteDeleteFile |
&Instruction::ExecuteRenameFile | &Instruction::ExecuteRenameFile |
&Instruction::ExecuteFileCopy | &Instruction::ExecuteFileCopy |
&Instruction::ExecuteWorkingDirectory | &Instruction::ExecuteWorkingDirectory |
&Instruction::ExecuteDeleteDirectory | &Instruction::ExecuteDeleteDirectory |
&Instruction::ExecutePathCanonical | &Instruction::ExecutePathCanonical |
@@ -1929,6 +1936,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteUnattributedVar | &Instruction::ExecuteUnattributedVar |
&Instruction::ExecuteGetDBRefs | &Instruction::ExecuteGetDBRefs |
&Instruction::ExecuteKeySortWithConstantVarOrdering | &Instruction::ExecuteKeySortWithConstantVarOrdering |
&Instruction::ExecuteInferenceLimitExceeded |
&Instruction::ExecuteFetchGlobalVar | &Instruction::ExecuteFetchGlobalVar |
&Instruction::ExecuteFirstStream | &Instruction::ExecuteFirstStream |
&Instruction::ExecuteFlushOutput | &Instruction::ExecuteFlushOutput |
@@ -2005,9 +2013,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteHttpListen | &Instruction::ExecuteHttpListen |
&Instruction::ExecuteHttpAccept | &Instruction::ExecuteHttpAccept |
&Instruction::ExecuteHttpAnswer | &Instruction::ExecuteHttpAnswer |
&Instruction::ExecuteLoadForeignLib | &Instruction::ExecuteLoadForeignLib |
&Instruction::ExecuteForeignCall | &Instruction::ExecuteForeignCall |
&Instruction::ExecuteDefineForeignStruct | &Instruction::ExecuteDefineForeignStruct |
&Instruction::ExecutePredicateDefined | &Instruction::ExecutePredicateDefined |
&Instruction::ExecuteStripModule | &Instruction::ExecuteStripModule |
&Instruction::ExecuteCurrentTime | &Instruction::ExecuteCurrentTime |
@@ -2050,13 +2058,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteCryptoDataHash | &Instruction::ExecuteCryptoDataHash |
&Instruction::ExecuteCryptoDataHKDF | &Instruction::ExecuteCryptoDataHKDF |
&Instruction::ExecuteCryptoPasswordHash | &Instruction::ExecuteCryptoPasswordHash |
&Instruction::ExecuteCryptoDataEncrypt |
&Instruction::ExecuteCryptoDataDecrypt |
&Instruction::ExecuteCryptoCurveScalarMult | &Instruction::ExecuteCryptoCurveScalarMult |
&Instruction::ExecuteEd25519Sign |
&Instruction::ExecuteEd25519Verify |
&Instruction::ExecuteEd25519NewKeyPair |
&Instruction::ExecuteEd25519KeyPairPublicKey |
&Instruction::ExecuteCurve25519ScalarMult | &Instruction::ExecuteCurve25519ScalarMult |
&Instruction::ExecuteFirstNonOctet | &Instruction::ExecuteFirstNonOctet |
&Instruction::ExecuteLoadHTML | &Instruction::ExecuteLoadHTML |
@@ -2113,6 +2115,17 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("execute"), [atom(name), fixnum(arity)]) functor!(atom!("execute"), [atom(name), fixnum(arity)])
} }
// //
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataEncrypt |
&Instruction::ExecuteCryptoDataDecrypt |
&Instruction::ExecuteEd25519Sign |
&Instruction::ExecuteEd25519Verify |
&Instruction::ExecuteEd25519NewKeyPair |
&Instruction::ExecuteEd25519KeyPairPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
}
//
&Instruction::Deallocate => { &Instruction::Deallocate => {
functor!(atom!("deallocate")) functor!(atom!("deallocate"))
} }
@@ -2284,7 +2297,8 @@ pub fn generate_instructions_rs() -> TokenStream {
instr_data.generate_instruction_enum_loop(input); instr_data.generate_instruction_enum_loop(input);
let instr_variants: Vec<_> = instr_data.instr_variants let instr_variants: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.cloned() .cloned()
.map(|(_, _, _, variant)| variant) .map(|(_, _, _, variant)| variant)
@@ -2323,7 +2337,8 @@ pub fn generate_instructions_rs() -> TokenStream {
for (name, arity, variant) in instr_data.compare_number_variants { for (name, arity, variant) in instr_data.compare_number_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
let ty = field.ty; let ty = field.ty;
@@ -2362,29 +2377,23 @@ pub fn generate_instructions_rs() -> TokenStream {
let ident = variant.ident; let ident = variant.ident;
let instr_ident = format_ident!("Call{}", ident); let instr_ident = format_ident!("Call{}", ident);
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
clause_type_to_instr_arms.push( clause_type_to_instr_arms.push(quote! {
quote! { ClauseType::Inlined(
ClauseType::Inlined( InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#placeholder_ids),*))
InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#placeholder_ids),*)) ) => Instruction::#instr_ident(#(*#placeholder_ids),*)
) => Instruction::#instr_ident(#(*#placeholder_ids),*) });
}
);
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
is_inlined_arms.push( is_inlined_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
} }
for (name, arity, variant) in instr_data.compare_term_variants { for (name, arity, variant) in instr_data.compare_term_variants {
@@ -2396,36 +2405,31 @@ pub fn generate_instructions_rs() -> TokenStream {
) )
}); });
clause_type_name_arms.push( clause_type_name_arms.push(quote! {
quote! { ClauseType::BuiltIn(
ClauseType::BuiltIn( BuiltInClauseType::CompareTerm(CompareTerm::#ident)
BuiltInClauseType::CompareTerm(CompareTerm::#ident) ) => atom!(#name)
) => atom!(#name) });
}
);
let ident = variant.ident; let ident = variant.ident;
let instr_ident = format_ident!("Call{}", ident); let instr_ident = format_ident!("Call{}", ident);
clause_type_to_instr_arms.push( clause_type_to_instr_arms.push(quote! {
quote! { ClauseType::BuiltIn(
ClauseType::BuiltIn( BuiltInClauseType::CompareTerm(CompareTerm::#ident)
BuiltInClauseType::CompareTerm(CompareTerm::#ident) ) => Instruction::#instr_ident
) => Instruction::#instr_ident });
}
);
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
} }
for (name, arity, variant) in instr_data.builtin_type_variants { for (name, arity, variant) in instr_data.builtin_type_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
let ty = field.ty; let ty = field.ty;
@@ -2464,7 +2468,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let ident = variant.ident; let ident = variant.ident;
let instr_ident = format_ident!("Call{}", ident); let instr_ident = format_ident!("Call{}", ident);
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
@@ -2482,17 +2486,16 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
}); });
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
} }
for (name, arity, variant) in instr_data.inlined_type_variants { for (name, arity, variant) in instr_data.inlined_type_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
if field.ty.type_id() == TypeId::of::<usize>() { if field.ty.type_id() == TypeId::of::<usize>() {
@@ -2535,35 +2538,30 @@ pub fn generate_instructions_rs() -> TokenStream {
let ident = variant.ident; let ident = variant.ident;
let instr_ident = format_ident!("Call{}", ident); let instr_ident = format_ident!("Call{}", ident);
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
clause_type_to_instr_arms.push( clause_type_to_instr_arms.push(quote! {
quote! { ClauseType::Inlined(
ClauseType::Inlined( InlinedClauseType::#ident(#(#placeholder_ids),*)
InlinedClauseType::#ident(#(#placeholder_ids),*) ) => Instruction::#instr_ident(*#(#placeholder_ids),*)
) => Instruction::#instr_ident(*#(#placeholder_ids),*) });
}
);
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
is_inlined_arms.push( is_inlined_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
} }
for (name, arity, variant) in instr_data.system_clause_type_variants { for (name, arity, variant) in instr_data.system_clause_type_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
if field.ty == parse_quote! { usize } { if field.ty == parse_quote! { usize } {
@@ -2631,7 +2629,7 @@ pub fn generate_instructions_rs() -> TokenStream {
ident.clone() ident.clone()
}; };
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
@@ -2649,23 +2647,22 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
}); });
is_inbuilt_arms.push( is_inbuilt_arms.push(if let Arity::Ident("arity") = &arity {
if let Arity::Ident("arity") = &arity { quote! {
quote! { (atom!(#name), _arity) => true
(atom!(#name), _arity) => true
}
} else {
quote! {
(atom!(#name), #arity) => true
}
} }
); } else {
quote! {
(atom!(#name), #arity) => true
}
});
} }
for (name, arity, variant) in instr_data.repl_code_ptr_variants { for (name, arity, variant) in instr_data.repl_code_ptr_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
if field.ty.type_id() == TypeId::of::<usize>() { if field.ty.type_id() == TypeId::of::<usize>() {
@@ -2708,7 +2705,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let ident = variant.ident; let ident = variant.ident;
let instr_ident = format_ident!("Call{}", ident); let instr_ident = format_ident!("Call{}", ident);
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
@@ -2726,11 +2723,9 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
}); });
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), #arity) => true
(atom!(#name), #arity) => true });
}
);
} }
for (name, arity, variant) in instr_data.clause_type_variants { for (name, arity, variant) in instr_data.clause_type_variants {
@@ -2752,7 +2747,8 @@ pub fn generate_instructions_rs() -> TokenStream {
continue; continue;
} }
let variant_fields: Vec<_> = variant.fields let variant_fields: Vec<_> = variant
.fields
.into_iter() .into_iter()
.map(|field| { .map(|field| {
if field.ty == parse_quote! { usize } { if field.ty == parse_quote! { usize } {
@@ -2786,7 +2782,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let ident = variant.ident; let ident = variant.ident;
let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) let placeholder_ids: Vec<_> = (0..variant_fields.len())
.map(|n| format_ident!("f_{}", n)) .map(|n| format_ident!("f_{}", n))
.collect(); .collect();
@@ -2801,14 +2797,13 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
}); });
is_inbuilt_arms.push( is_inbuilt_arms.push(quote! {
quote! { (atom!(#name), _arity) => true
(atom!(#name), _arity) => true });
}
);
} }
let to_execute_arms: Vec<_> = instr_data.instr_variants let to_execute_arms: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.cloned() .cloned()
.filter_map(|(_, _, _, variant)| { .filter_map(|(_, _, _, variant)| {
@@ -2821,12 +2816,11 @@ pub fn generate_instructions_rs() -> TokenStream {
0 0
}; };
let placeholder_ids: Vec<_> = (0 .. enum_arity) let placeholder_ids: Vec<_> =
.map(|n| format_ident!("f_{}", n)) (0..enum_arity).map(|n| format_ident!("f_{}", n)).collect();
.collect();
if variant_string.starts_with("Call") { if variant_string.starts_with("Call") {
let execute_ident = format_ident!("Execute{}", variant_string["Call".len() ..]); let execute_ident = format_ident!("Execute{}", variant_string["Call".len()..]);
Some(if enum_arity == 0 { Some(if enum_arity == 0 {
quote! { quote! {
@@ -2841,7 +2835,7 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
} else if variant_string.starts_with("DefaultCall") { } else if variant_string.starts_with("DefaultCall") {
let execute_ident = let execute_ident =
format_ident!("DefaultExecute{}", variant_string["DefaultCall".len() ..]); format_ident!("DefaultExecute{}", variant_string["DefaultCall".len()..]);
Some(if enum_arity == 0 { Some(if enum_arity == 0 {
quote! { quote! {
@@ -2860,7 +2854,8 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
.collect(); .collect();
let is_execute_arms: Vec<_> = instr_data.instr_variants let is_execute_arms: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.cloned() .cloned()
.filter_map(|(_, _, _, variant)| { .filter_map(|(_, _, _, variant)| {
@@ -2903,7 +2898,8 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
.collect(); .collect();
let to_default_arms: Vec<_> = instr_data.instr_variants let to_default_arms: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.cloned() .cloned()
.filter_map(|(_, _, countable_inference, variant)| { .filter_map(|(_, _, countable_inference, variant)| {
@@ -2920,9 +2916,8 @@ pub fn generate_instructions_rs() -> TokenStream {
0 0
}; };
let placeholder_ids: Vec<_> = (0 .. enum_arity) let placeholder_ids: Vec<_> =
.map(|n| format_ident!("f_{}", n)) (0..enum_arity).map(|n| format_ident!("f_{}", n)).collect();
.collect();
Some(if enum_arity == 0 { Some(if enum_arity == 0 {
quote! { quote! {
@@ -2941,7 +2936,8 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
.collect(); .collect();
let control_flow_arms: Vec<_> = instr_data.instr_variants let control_flow_arms: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.cloned() .cloned()
.filter_map(|(_, _, _, variant)| { .filter_map(|(_, _, _, variant)| {
@@ -2969,7 +2965,8 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
.collect(); .collect();
let instr_macro_arms: Vec<_> = instr_data.instr_variants let instr_macro_arms: Vec<_> = instr_data
.instr_variants
.iter() .iter()
.rev() // produce default, execute & default & execute cases first. .rev() // produce default, execute & default & execute cases first.
.cloned() .cloned()
@@ -2978,7 +2975,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let variant_string = variant.ident.to_string(); let variant_string = variant.ident.to_string();
let arity = match arity { let arity = match arity {
Arity::Static(arity) => arity, Arity::Static(arity) => arity,
_ => 1 _ => 1,
}; };
Some(if variant_string.starts_with("Execute") { Some(if variant_string.starts_with("Execute") {
@@ -3055,9 +3052,10 @@ pub fn generate_instructions_rs() -> TokenStream {
}) })
.collect(); .collect();
let name_and_arity_arms: Vec<_> = instr_data.instr_variants let name_and_arity_arms: Vec<_> = instr_data
.instr_variants
.into_iter() .into_iter()
.map(|(name,arity,_,variant)| { .map(|(name, arity, _, variant)| {
let ident = &variant.ident; let ident = &variant.ident;
let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
@@ -3287,8 +3285,10 @@ pub fn generate_instructions_rs() -> TokenStream {
fn is_callable(id: &Ident) -> bool { fn is_callable(id: &Ident) -> bool {
let id = id.to_string(); let id = id.to_string();
id.starts_with("Call") || id.starts_with("Execute") || id.starts_with("DefaultCall") || id.starts_with("Call")
id.starts_with("DefaultExecute") || id.starts_with("Execute")
|| id.starts_with("DefaultCall")
|| id.starts_with("DefaultExecute")
} }
fn is_non_default_callable(id: &Ident) -> bool { fn is_non_default_callable(id: &Ident) -> bool {
@@ -3309,7 +3309,8 @@ fn create_instr_variant(id: Ident, mut variant: Variant) -> Variant {
} }
fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str
where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug where
DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug,
{ {
let disc = match DiscriminantT::from_str(id.to_string().as_str()) { let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
Ok(disc) => disc, Ok(disc) => disc,
@@ -3329,7 +3330,7 @@ fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum Arity { enum Arity {
Static(usize), Static(usize),
Ident(&'static str) Ident(&'static str),
} }
impl From<&'static str> for Arity { impl From<&'static str> for Arity {
@@ -3421,9 +3422,13 @@ impl InstructionData {
(name, arity, CountableInference::NotCounted) (name, arity, CountableInference::NotCounted)
} else if id == "InstructionTemplate" { } else if id == "InstructionTemplate" {
( prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Name"), (
Arity::from(prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Arity")), prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Name"),
CountableInference::NotCounted Arity::from(prop_from_ident::<InstructionTemplateDiscriminants>(
&variant.ident,
"Arity",
)),
CountableInference::NotCounted,
) )
} else if id == "ClauseType" { } else if id == "ClauseType" {
let (name, arity) = add_discriminant_data::<ClauseTypeDiscriminants>( let (name, arity) = add_discriminant_data::<ClauseTypeDiscriminants>(
@@ -3440,19 +3445,16 @@ impl InstructionData {
let v_string = variant.ident.to_string(); let v_string = variant.ident.to_string();
let v_ident = if v_string.starts_with("Call") { let v_ident = if v_string.starts_with("Call") {
format_ident!("{}", v_string["Call".len() ..]) format_ident!("{}", v_string["Call".len()..])
} else { } else {
variant.ident.clone() variant.ident.clone()
}; };
let generated_variant = create_instr_variant( let generated_variant =
format_ident!("{}{}", prefix, v_ident), create_instr_variant(format_ident!("{}{}", prefix, v_ident), variant.clone());
variant.clone(),
);
self.instr_variants.push( self.instr_variants
(name, arity, countable_inference, generated_variant) .push((name, arity, countable_inference, generated_variant));
);
} }
fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) { fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) {
@@ -3474,10 +3476,10 @@ impl InstructionData {
self.label_variant(&input.ident, "Call", variant.clone()); self.label_variant(&input.ident, "Call", variant.clone());
self.label_variant(&input.ident, "Execute", variant.clone()); self.label_variant(&input.ident, "Execute", variant.clone());
if input.ident == "BuiltInClauseType" || if input.ident == "BuiltInClauseType"
input.ident == "CompareNumber" || || input.ident == "CompareNumber"
input.ident == "CompareTerm" || || input.ident == "CompareTerm"
input.ident == "ClauseType" || input.ident == "ClauseType"
{ {
self.label_variant(&input.ident, "DefaultCall", variant.clone()); self.label_variant(&input.ident, "DefaultCall", variant.clone());
self.label_variant(&input.ident, "DefaultExecute", variant); self.label_variant(&input.ident, "DefaultExecute", variant);

View File

@@ -1,7 +1,7 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use syn::*;
use syn::parse::*; use syn::parse::*;
use syn::visit::*; use syn::visit::*;
use syn::*;
use indexmap::IndexSet; use indexmap::IndexSet;
@@ -11,7 +11,9 @@ struct StaticStrVisitor {
impl StaticStrVisitor { impl StaticStrVisitor {
fn new() -> Self { fn new() -> Self {
Self { static_strs: IndexSet::new() } Self {
static_strs: IndexSet::new(),
}
} }
} }

491
flamegraph.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.8 MiB

0
log.txt Normal file
View File

View File

@@ -4,25 +4,31 @@ use crate::machine::loader::LiveLoadState;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::raw_block::*; use crate::raw_block::*;
use crate::rcu::Rcu;
use crate::rcu::RcuRef;
use crate::read::*; use crate::read::*;
use ordered_float::OrderedFloat;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
use std::alloc; use std::alloc;
use std::cell::UnsafeCell;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::net::TcpListener; use std::net::TcpListener;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use std::sync::RwLock;
#[macro_export] #[macro_export]
macro_rules! arena_alloc { macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { ArenaAllocated::alloc($arena, result) } unsafe {
ArenaAllocated::alloc($arena, result)
}
}}; }};
} }
@@ -31,24 +37,36 @@ macro_rules! float_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { $arena.f64_tbl.build_with(result) } unsafe {
$arena.f64_tbl.build_with(result).as_ptr()
}
}}; }};
} }
#[cfg(test)] use std::sync::Arc;
use std::cell::RefCell; use std::sync::Mutex;
use std::sync::Weak;
const F64_TABLE_INIT_SIZE: usize = 1 << 16; const F64_TABLE_INIT_SIZE: usize = 1 << 16;
const F64_TABLE_ALIGN: usize = 8; const F64_TABLE_ALIGN: usize = 8;
#[cfg(test)] #[inline(always)]
thread_local! { fn global_f64table() -> &'static RwLock<Weak<F64Table>> {
static F64_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut()); #[cfg(feature = "rust_beta_channel")]
{
// const Weak::new will be stabilized in 1.73 which is currently in beta,
// till then we need a OnceLock for initialization
static GLOBAL_ATOM_TABLE: RwLock<Weak<F64Table>> = RwLock::const_new(Weak::new());
&GLOBAL_ATOM_TABLE
}
#[cfg(not(feature = "rust_beta_channel"))]
{
use std::sync::OnceLock;
static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<F64Table>>> = OnceLock::new();
GLOBAL_ATOM_TABLE.get_or_init(|| RwLock::new(Weak::new()))
}
} }
#[cfg(not(test))]
static mut F64_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
impl RawBlockTraits for F64Table { impl RawBlockTraits for F64Table {
#[inline] #[inline]
fn init_size() -> usize { fn init_size() -> usize {
@@ -63,69 +81,87 @@ impl RawBlockTraits for F64Table {
#[derive(Debug)] #[derive(Debug)]
pub struct F64Table { pub struct F64Table {
block: RawBlock<F64Table>, block: Rcu<RawBlock<F64Table>>,
} update: Mutex<()>,
impl Drop for F64Table {
fn drop(&mut self) {
self.block.deallocate();
}
}
#[cfg(test)]
fn set_f64_tbl_buf_base(ptr: *const u8) {
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| {
*f64_table_buf_base.borrow_mut() = ptr;
});
}
#[cfg(test)]
pub(crate) fn get_f64_tbl_buf_base() -> *const u8 {
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| *f64_table_buf_base.borrow())
}
#[cfg(not(test))]
fn set_f64_tbl_buf_base(ptr: *const u8) {
unsafe {
F64_TABLE_BUF_BASE = ptr;
}
}
#[cfg(not(test))]
pub(crate) fn get_f64_tbl_buf_base() -> *const u8 {
unsafe { F64_TABLE_BUF_BASE }
} }
#[inline(always)] #[inline(always)]
pub fn lookup_float(offset: usize) -> *mut OrderedFloat<f64> { pub fn lookup_float(
let base = get_f64_tbl_buf_base() as usize; offset: F64Offset,
(base + offset) as *mut _ ) -> RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>> {
let f64table = global_f64table()
.read()
.unwrap()
.upgrade()
.expect("We should only be looking up floats while there is a float table");
RcuRef::try_map(f64table.block.active_epoch(), |raw_block| unsafe {
raw_block
.base
.offset(offset.0 as isize)
.cast_mut()
.cast::<UnsafeCell<OrderedFloat<f64>>>()
.as_ref()
})
.expect("The offset should result in a non-null pointer")
} }
impl F64Table { impl F64Table {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Arc<Self> {
let table = Self { block: RawBlock::new() }; let upgraded = global_f64table().read().unwrap().upgrade();
set_f64_tbl_buf_base(table.block.base); // don't inline upgraded, otherwise temporary will be dropped too late in case of None
table if let Some(atom_table) = upgraded {
atom_table
} else {
let mut guard = global_f64table().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 {
block: Rcu::new(RawBlock::new()),
update: Mutex::new(()),
});
*guard = Arc::downgrade(&atom_table);
atom_table
}
}
} }
pub unsafe fn build_with(&mut self, value: f64) -> F64Ptr { pub unsafe fn build_with(&self, value: f64) -> F64Offset {
let update_guard = self.update.lock();
// we don't have an index table for lookups as AtomTable does so
// just get the epoch after we take the upgrade lock
let mut block_epoch = self.block.active_epoch();
let mut ptr; let mut ptr;
loop { loop {
ptr = self.block.alloc(mem::size_of::<f64>()); ptr = block_epoch.alloc(mem::size_of::<f64>());
if ptr.is_null() { if ptr.is_null() {
self.block.grow(); let new_block = block_epoch.grow_new().unwrap();
set_f64_tbl_buf_base(self.block.base); self.block.replace(new_block);
block_epoch = self.block.active_epoch();
} else { } else {
break; break;
} }
} }
ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value)); ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
F64Ptr(ptr::NonNull::new_unchecked(ptr as *mut _))
let float = F64Offset {
0: ptr as usize - block_epoch.base as usize,
};
// atometable would have to update the index table at this point
// expicit drop to ensure we don't accidentally drop it early
drop(update_guard);
float
} }
} }
@@ -134,14 +170,13 @@ impl F64Table {
pub enum ArenaHeaderTag { pub enum ArenaHeaderTag {
Integer = 0b10, Integer = 0b10,
Rational = 0b11, Rational = 0b11,
OssifiedOpDir = 0b0000100,
LiveLoadState = 0b0001000, LiveLoadState = 0b0001000,
InactiveLoadState = 0b1011000, InactiveLoadState = 0b1011000,
InputFileStream = 0b10000, InputFileStream = 0b10000,
OutputFileStream = 0b10100, OutputFileStream = 0b10100,
NamedTcpStream = 0b011100, NamedTcpStream = 0b011100,
NamedTlsStream = 0b100000, NamedTlsStream = 0b100000,
HttpReadStream = 0b100001, HttpReadStream = 0b100001,
HttpWriteStream = 0b100010, HttpWriteStream = 0b100010,
ReadlineStream = 0b110000, ReadlineStream = 0b110000,
StaticStringStream = 0b110100, StaticStringStream = 0b110100,
@@ -276,7 +311,9 @@ impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
#[inline] #[inline]
pub fn set_tag(&mut self, tag: ArenaHeaderTag) { pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
unsafe { (*self.header_ptr_mut()).set_tag(tag); } unsafe {
(*self.header_ptr_mut()).set_tag(tag);
}
} }
#[inline] #[inline]
@@ -313,10 +350,10 @@ pub trait ArenaAllocated: Sized {
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated { unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>(); let size = value.size() + mem::size_of::<AllocSlab>();
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
let align = mem::align_of::<AllocSlab>() * 2; let align = mem::align_of::<AllocSlab>() * 2;
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
let align = mem::align_of::<AllocSlab>(); let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align); let layout = alloc::Layout::from_size_align_unchecked(size, align);
@@ -334,12 +371,18 @@ pub trait ArenaAllocated: Sized {
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Debug)]
pub struct F64Ptr(pub ptr::NonNull<OrderedFloat<f64>>); pub struct F64Ptr(RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>>);
impl Clone for F64Ptr {
fn clone(&self) -> Self {
Self(RcuRef::clone(&self.0))
}
}
impl PartialEq for F64Ptr { impl PartialEq for F64Ptr {
fn eq(&self, other: &F64Ptr) -> bool { fn eq(&self, other: &F64Ptr) -> bool {
self.0 == other.0 || &**self == &**other RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref()
} }
} }
@@ -375,28 +418,26 @@ impl Deref for F64Ptr {
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { &*self.0.as_ptr() } unsafe { &*self.0.get().as_ref().unwrap() }
} }
} }
impl DerefMut for F64Ptr { impl DerefMut for F64Ptr {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.0.as_ptr() } unsafe { &mut *self.0.get().as_mut().unwrap() }
} }
} }
impl F64Ptr { impl F64Ptr {
#[inline(always)] #[inline(always)]
pub fn from_offset(offset: usize) -> Self { pub fn from_offset(offset: F64Offset) -> Self {
unsafe { Self(lookup_float(offset))
F64Ptr(ptr::NonNull::new_unchecked(lookup_float(offset)))
}
} }
#[inline(always)] #[inline(always)]
pub fn as_offset(&self) -> F64Offset { pub fn as_offset(&self) -> F64Offset {
F64Offset(self.0.as_ptr() as usize - get_f64_tbl_buf_base() as usize) F64Offset(self.0.get() as usize - RcuRef::get_root(&self.0).base as usize)
} }
} }
@@ -416,7 +457,7 @@ impl F64Offset {
#[inline(always)] #[inline(always)]
pub fn as_ptr(self) -> F64Ptr { pub fn as_ptr(self) -> F64Ptr {
F64Ptr::from_offset(self.0) F64Ptr::from_offset(self)
} }
#[inline(always)] #[inline(always)]
@@ -505,28 +546,6 @@ impl ArenaAllocated for Rational {
} }
} }
impl ArenaAllocated for OssifiedOpDir {
type PtrToAllocated = TypedArenaPtr<OssifiedOpDir>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::OssifiedOpDir
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for LiveLoadState { impl ArenaAllocated for LiveLoadState {
type PtrToAllocated = TypedArenaPtr<LiveLoadState>; type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
@@ -577,20 +596,20 @@ impl ArenaAllocated for HttpListener {
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpListener ArenaHeaderTag::HttpListener
} }
#[inline] #[inline]
fn size(&self) -> usize { fn size(&self) -> usize {
mem::size_of::<Self>() mem::size_of::<Self>()
} }
#[inline] #[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe { unsafe {
ptr::write(dst, self); ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self) TypedArenaPtr::new(dst as *mut Self)
} }
} }
} }
@@ -600,20 +619,20 @@ impl ArenaAllocated for HttpResponse {
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpResponse ArenaHeaderTag::HttpResponse
} }
#[inline] #[inline]
fn size(&self) -> usize { fn size(&self) -> usize {
mem::size_of::<Self>() mem::size_of::<Self>()
} }
#[inline] #[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe { unsafe {
ptr::write(dst, self); ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self) TypedArenaPtr::new(dst as *mut Self)
} }
} }
} }
@@ -664,7 +683,7 @@ impl ArenaAllocated for IndexPtr {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct AllocSlab { struct AllocSlab {
next: *mut AllocSlab, next: *mut AllocSlab,
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
_padding: u32, _padding: u32,
header: ArenaHeader, header: ArenaHeader,
} }
@@ -672,7 +691,7 @@ struct AllocSlab {
#[derive(Debug)] #[derive(Debug)]
pub struct Arena { pub struct Arena {
base: *mut AllocSlab, base: *mut AllocSlab,
pub f64_tbl: F64Table, pub f64_tbl: Arc<F64Table>,
} }
unsafe impl Send for Arena {} unsafe impl Send for Arena {}
@@ -681,7 +700,10 @@ unsafe impl Sync for Arena {}
impl Arena { impl Arena {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() } Arena {
base: ptr::null_mut(),
f64_tbl: F64Table::new(),
}
} }
} }
@@ -712,10 +734,10 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>());
} }
ArenaHeaderTag::HttpWriteStream => { ArenaHeaderTag::HttpWriteStream => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>());
} }
ArenaHeaderTag::ReadlineStream => { ArenaHeaderTag::ReadlineStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
} }
@@ -725,35 +747,32 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
ArenaHeaderTag::ByteStream => { ArenaHeaderTag::ByteStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>());
} }
ArenaHeaderTag::OssifiedOpDir => {
ptr::drop_in_place(value.payload_offset::<OssifiedOpDir>());
}
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => { ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
ptr::drop_in_place(value.payload_offset::<LiveLoadState>()); ptr::drop_in_place(value.payload_offset::<LiveLoadState>());
} }
ArenaHeaderTag::Dropped => { ArenaHeaderTag::Dropped => {}
}
ArenaHeaderTag::TcpListener => { ArenaHeaderTag::TcpListener => {
ptr::drop_in_place(value.payload_offset::<TcpListener>()); ptr::drop_in_place(value.payload_offset::<TcpListener>());
} }
ArenaHeaderTag::HttpListener => { ArenaHeaderTag::HttpListener => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<HttpListener>()); ptr::drop_in_place(value.payload_offset::<HttpListener>());
} }
ArenaHeaderTag::HttpResponse => { ArenaHeaderTag::HttpResponse => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<HttpResponse>()); ptr::drop_in_place(value.payload_offset::<HttpResponse>());
} }
ArenaHeaderTag::StandardOutputStream => { ArenaHeaderTag::StandardOutputStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
} }
ArenaHeaderTag::StandardErrorStream => { ArenaHeaderTag::StandardErrorStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
} }
ArenaHeaderTag::NullStream | ArenaHeaderTag::IndexPtrUndefined | ArenaHeaderTag::NullStream
ArenaHeaderTag::IndexPtrDynamicUndefined | ArenaHeaderTag::IndexPtrDynamicIndex | | ArenaHeaderTag::IndexPtrUndefined
ArenaHeaderTag::IndexPtrIndex => { | ArenaHeaderTag::IndexPtrDynamicUndefined
} | ArenaHeaderTag::IndexPtrDynamicIndex
| ArenaHeaderTag::IndexPtrIndex => {}
} }
} }
@@ -801,23 +820,25 @@ const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::ops::Deref;
use crate::machine::mock_wam::*; use crate::machine::mock_wam::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use ordered_float::OrderedFloat;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
#[test] #[test]
fn float_ptr_cast() { fn float_ptr_cast() {
let mut wam = MockWAM::new(); let wam = MockWAM::new();
let f = 0f64; let f = 0f64;
let fp = float_alloc!(f, wam.machine_st.arena); let fp = float_alloc!(f, wam.machine_st.arena);
let mut cell = HeapCellValue::from(fp); let mut cell = HeapCellValue::from(fp.clone());
assert_eq!(cell.get_tag(), HeapCellValueTag::F64); assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
assert_eq!(cell.get_mark_bit(), false); assert_eq!(cell.get_mark_bit(), false);
assert_eq!(*fp, OrderedFloat(f)); assert_eq!(fp.deref(), &OrderedFloat(f));
cell.set_mark_bit(true); cell.set_mark_bit(true);
@@ -834,12 +855,12 @@ mod tests {
#[test] #[test]
fn heap_cell_value_const_cast() { fn heap_cell_value_const_cast() {
let mut wam = MockWAM::new(); let mut wam = MockWAM::new();
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
let const_value = HeapCellValue::from(ConsPtr::build_with( let const_value = HeapCellValue::from(ConsPtr::build_with(
0x0000_0431 as *const _, 0x0000_0431 as *const _,
ConsPtrMaskTag::Cons, ConsPtrMaskTag::Cons,
)); ));
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
let const_value = HeapCellValue::from(ConsPtr::build_with( let const_value = HeapCellValue::from(ConsPtr::build_with(
0x0000_5555_ff00_0431 as *const _, 0x0000_5555_ff00_0431 as *const _,
ConsPtrMaskTag::Cons, ConsPtrMaskTag::Cons,
@@ -847,7 +868,10 @@ mod tests {
match const_value.to_untyped_arena_ptr() { match const_value.to_untyped_arena_ptr() {
Some(arena_ptr) => { Some(arena_ptr) => {
assert_eq!(arena_ptr.into_bytes(), const_value.to_untyped_arena_ptr_bytes()); assert_eq!(
arena_ptr.into_bytes(),
const_value.to_untyped_arena_ptr_bytes()
);
} }
None => { None => {
assert!(false); assert!(false);
@@ -860,7 +884,10 @@ mod tests {
match stream_cell.to_untyped_arena_ptr() { match stream_cell.to_untyped_arena_ptr() {
Some(arena_ptr) => { Some(arena_ptr) => {
assert_eq!(arena_ptr.into_bytes(), stream_cell.to_untyped_arena_ptr_bytes()); assert_eq!(
arena_ptr.into_bytes(),
stream_cell.to_untyped_arena_ptr_bytes()
);
} }
None => { None => {
assert!(false); assert!(false);
@@ -875,8 +902,7 @@ mod tests {
// integer // integer
let big_int: Integer = 2 * Integer::from(1u64 << 63); let big_int: Integer = 2 * Integer::from(1u64 << 63);
let big_int_ptr: TypedArenaPtr<Integer> = let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
arena_alloc!(big_int, &mut wam.machine_st.arena);
assert!(!big_int_ptr.as_ptr().is_null()); assert!(!big_int_ptr.as_ptr().is_null());
@@ -951,8 +977,8 @@ mod tests {
let f_atom = atom!("f"); let f_atom = atom!("f");
let g_atom = atom!("g"); let g_atom = atom!("g");
assert_eq!(f_atom.as_str(), "f"); assert_eq!(&*f_atom.as_str(), "f");
assert_eq!(g_atom.as_str(), "g"); assert_eq!(&*g_atom.as_str(), "g");
let f_atom_cell = atom_as_cell!(f_atom); let f_atom_cell = atom_as_cell!(f_atom);
let g_atom_cell = atom_as_cell!(g_atom); let g_atom_cell = atom_as_cell!(g_atom);
@@ -962,7 +988,7 @@ mod tests {
match f_atom_cell.to_atom() { match f_atom_cell.to_atom() {
Some(atom) => { Some(atom) => {
assert_eq!(f_atom, atom); assert_eq!(f_atom, atom);
assert_eq!(atom.as_str(), "f"); assert_eq!(&*atom.as_str(), "f");
} }
None => { None => {
assert!(false); assert!(false);
@@ -973,7 +999,7 @@ mod tests {
(HeapCellValueTag::Atom, (atom, arity)) => { (HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(f_atom, atom); assert_eq!(f_atom, atom);
assert_eq!(arity, 0); assert_eq!(arity, 0);
assert_eq!(atom.as_str(), "f"); assert_eq!(&*atom.as_str(), "f");
} }
_ => { unreachable!() } _ => { unreachable!() }
); );
@@ -982,21 +1008,22 @@ mod tests {
(HeapCellValueTag::Atom, (atom, arity)) => { (HeapCellValueTag::Atom, (atom, arity)) => {
assert_eq!(g_atom, atom); assert_eq!(g_atom, atom);
assert_eq!(arity, 0); assert_eq!(arity, 0);
assert_eq!(atom.as_str(), "g"); assert_eq!(&*atom.as_str(), "g");
} }
_ => { unreachable!() } _ => { unreachable!() }
); );
// complete string // complete string
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl); let pstr_var_cell =
put_partial_string(&mut wam.machine_st.heap, "ronan", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr); assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr);
match pstr_cell.to_pstr() { match pstr_cell.to_pstr() {
Some(pstr) => { Some(pstr) => {
assert_eq!(pstr.as_str_from(0), "ronan"); assert_eq!(&*pstr.as_str_from(0), "ronan");
} }
None => { None => {
assert!(false); assert!(false);
@@ -1006,7 +1033,7 @@ mod tests {
read_heap_cell!(pstr_cell, read_heap_cell!(pstr_cell,
(HeapCellValueTag::PStr, pstr_atom) => { (HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom); let pstr = PartialString::from(pstr_atom);
assert_eq!(pstr.as_str_from(0), "ronan"); assert_eq!(&*pstr.as_str_from(0), "ronan");
} }
_ => { unreachable!() } _ => { unreachable!() }
); );
@@ -1115,7 +1142,7 @@ mod tests {
read_heap_cell!(cell, read_heap_cell!(cell,
(HeapCellValueTag::Atom, (el, _arity)) => { (HeapCellValueTag::Atom, (el, _arity)) => {
assert_eq!(el.flat_index(), empty_list_as_cell!().get_value()); assert_eq!(el.flat_index(), empty_list_as_cell!().get_value());
assert_eq!(el.as_str(), "[]"); assert_eq!(&*el.as_str(), "[]");
} }
_ => { unreachable!() } _ => { unreachable!() }
); );

View File

@@ -14,6 +14,8 @@ use crate::parser::dashu::{Integer, Rational};
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use dashu::base::Abs; use dashu::base::Abs;
use dashu::base::BitTest;
use num_order::NumOrd;
use ordered_float::*; use ordered_float::*;
use std::cell::Cell; use std::cell::Cell;
@@ -158,13 +160,13 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))), Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number( Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::E)) Number::Float(OrderedFloat(std::f64::consts::E)),
)), )),
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number( Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::PI)) Number::Float(OrderedFloat(std::f64::consts::PI)),
)), )),
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number( Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::EPSILON)) Number::Float(OrderedFloat(std::f64::EPSILON)),
)), )),
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)), _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
} }
@@ -195,13 +197,6 @@ impl<'a> ArithmeticEvaluator<'a> {
atom!("sin") => Ok(Instruction::Sin(a1, t)), atom!("sin") => Ok(Instruction::Sin(a1, t)),
atom!("tan") => Ok(Instruction::Tan(a1, t)), atom!("tan") => Ok(Instruction::Tan(a1, t)),
atom!("log") => Ok(Instruction::Log(a1, t)), atom!("log") => Ok(Instruction::Log(a1, t)),
atom!("asinh") => Ok(Instruction::ASinh(a1, t)),
atom!("acosh") => Ok(Instruction::ACosh(a1, t)),
atom!("atanh") => Ok(Instruction::ATanh(a1, t)),
atom!("sinh") => Ok(Instruction::Sinh(a1, t)),
atom!("cosh") => Ok(Instruction::Cosh(a1, t)),
atom!("tanh") => Ok(Instruction::Tanh(a1, t)),
atom!("log10") => Ok(Instruction::Log10(a1, t)),
atom!("exp") => Ok(Instruction::Exp(a1, t)), atom!("exp") => Ok(Instruction::Exp(a1, t)),
atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)), atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
atom!("acos") => Ok(Instruction::ACos(a1, t)), atom!("acos") => Ok(Instruction::ACos(a1, t)),
@@ -326,23 +321,14 @@ impl<'a> ArithmeticEvaluator<'a> {
let var_num = name.to_var_num().unwrap(); let var_num = name.to_var_num().unwrap();
let r = if lvl == Level::Shallow { let r = if lvl == Level::Shallow {
self.marker.mark_non_callable( self.marker
var_num, .mark_non_callable(var_num, arg, term_loc, cell, &mut code)
arg,
term_loc,
cell,
&mut code,
)
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 { } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
let r = self.marker.get_binding(var_num); let r = self.marker.get_binding(var_num);
if r.reg_num() == 0 { if r.reg_num() == 0 {
self.marker.mark_var::<QueryInstruction>( self.marker.mark_var::<QueryInstruction>(
var_num, var_num, lvl, cell, term_loc, &mut code,
lvl,
cell,
term_loc,
&mut code,
); );
cell.get().norm() cell.get().norm()
} else { } else {
@@ -370,8 +356,9 @@ impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number { pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
match n { match n {
&Number::Integer(i) => { &Number::Integer(i) => {
if let Some(n) = i.to_i64() { let result = (&*i).try_into();
fixnum!(Number, n, arena) if let Ok(value) = result{
fixnum!(Number, value, arena)
} else { } else {
*n *n
} }
@@ -392,8 +379,8 @@ pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
&Number::Rational(ref r) => { &Number::Rational(ref r) => {
let (_, floor) = (r.fract(), r.floor()); let (_, floor) = (r.fract(), r.floor());
if let Some(floor) = floor.to_i64() { if let Ok(value) = (&floor).try_into() {
fixnum!(Number, floor, arena) fixnum!(Number, value, arena)
} else { } else {
Number::Integer(arena_alloc!(floor, arena)) Number::Integer(arena_alloc!(floor, arena))
} }
@@ -434,7 +421,7 @@ fn classify_float(f: f64) -> Result<f64, EvalError> {
} }
} }
FpCategory::Nan => Err(EvalError::Undefined), FpCategory::Nan => Err(EvalError::Undefined),
_ => Ok(f) _ => Ok(f),
} }
} }
@@ -542,15 +529,19 @@ impl PartialEq for Number {
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) { match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2), (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2), (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().num_eq(&**n2),
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).num_eq(&n2.get_num()),
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2), (&Number::Fixnum(n1), &Number::Rational(ref n2)) => Integer::from(n1.get_num()).num_eq(&**n2),
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), (&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::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::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::Integer(ref n2)) => n1.eq(n2),
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).eq(n2), (&Number::Integer(ref n1), Number::Float(n2)) => {
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64().value())), 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)) => { (&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
#[cfg(feature = "num")] #[cfg(feature = "num")]
{ {
@@ -558,7 +549,7 @@ impl PartialEq for Number {
} }
#[cfg(not(feature = "num"))] #[cfg(not(feature = "num"))]
{ {
&**n1 == &**n2 (&**n1).num_eq(&**n2)
} }
} }
(&Number::Rational(ref n1), &Number::Integer(ref n2)) => { (&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
@@ -568,11 +559,15 @@ impl PartialEq for Number {
} }
#[cfg(not(feature = "num"))] #[cfg(not(feature = "num"))]
{ {
&**n1 == &**n2 (&**n1).num_eq(&**n2)
} }
} }
(&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).eq(&n2), (&Number::Rational(ref n1), &Number::Float(n2)) => {
(&Number::Float(n1), &Number::Rational(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64().value())), 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::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2), (&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2),
} }
@@ -594,8 +589,8 @@ impl PartialOrd<usize> for Number {
(n as usize).partial_cmp(rhs) (n as usize).partial_cmp(rhs)
} }
} }
Number::Integer(n) => (&**n).partial_cmp(rhs), Number::Integer(n) => Some((&**n).num_cmp(rhs)),
Number::Rational(r) => (&**r).partial_cmp(rhs), Number::Rational(r) => Some((&**r).num_cmp(&Integer::from(*rhs))),
Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)), Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
} }
} }
@@ -614,8 +609,8 @@ impl PartialEq<usize> for Number {
(n as usize).eq(rhs) (n as usize).eq(rhs)
} }
} }
Number::Integer(n) => (&**n).eq(rhs), Number::Integer(n) => (&**n).num_eq(rhs),
Number::Rational(r) => (&**r).eq(rhs), Number::Rational(r) => (&**r).num_eq(&Integer::from(*rhs)),
Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)), Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
} }
} }
@@ -641,7 +636,9 @@ impl Ord for Number {
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)), (&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::Integer(n2)) => (*n1).cmp(&*n2),
(&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).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::Float(n1), &Number::Integer(ref n2)) => {
n1.cmp(&OrderedFloat(n2.to_f64().value()))
}
(&Number::Integer(n1), &Number::Rational(n2)) => { (&Number::Integer(n1), &Number::Rational(n2)) => {
#[cfg(feature = "num")] #[cfg(feature = "num")]
{ {
@@ -649,7 +646,7 @@ impl Ord for Number {
} }
#[cfg(not(feature = "num"))] #[cfg(not(feature = "num"))]
{ {
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less) (&*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
} }
} }
(&Number::Rational(n1), &Number::Integer(n2)) => { (&Number::Rational(n1), &Number::Integer(n2)) => {
@@ -659,11 +656,15 @@ impl Ord for Number {
} }
#[cfg(not(feature = "num"))] #[cfg(not(feature = "num"))]
{ {
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less) (&*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
} }
} }
(&Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).cmp(&n2), (&Number::Rational(n1), &Number::Float(n2)) => {
(&Number::Float(n1), &Number::Rational(n2)) => n1.cmp(&OrderedFloat(n2.to_f64().value())), 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::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
(&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2), (&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
} }
@@ -704,16 +705,16 @@ impl TryFrom<HeapCellValue> for Number {
// Computes n ^ power. Ignores the sign of power. // Computes n ^ power. Ignores the sign of power.
pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer { pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
let mut power = Integer::from(power.abs()); let mut power = power.abs();
if power == 0 { if power.is_zero() {
return Integer::from(1); return Integer::ONE;
} }
let mut oddand = Integer::from(1); let mut oddand = Integer::ONE;
while power > 1 { while power.num_gt(&1) {
if power.is_odd() { if power.bit(0) {
oddand *= &n; oddand *= &n;
} }

View File

@@ -1,14 +1,19 @@
use crate::parser::ast::MAX_ARITY; use crate::parser::ast::MAX_ARITY;
use crate::raw_block::*; use crate::raw_block::*;
use crate::rcu::{Rcu, RcuRef};
use crate::types::*; use crate::types::*;
use std::borrow::Borrow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::ops::Deref;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use std::str; use std::str;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use std::sync::Weak;
use indexmap::IndexSet; use indexmap::IndexSet;
@@ -33,65 +38,43 @@ impl<'a> From<&'a Atom> for Atom {
impl From<bool> for Atom { impl From<bool> for Atom {
#[inline] #[inline]
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
if value { atom!("true") } else { atom!("false") } if value {
atom!("true")
} else {
atom!("false")
}
}
}
impl indexmap::Equivalent<Atom> for str {
fn equivalent(&self, key: &Atom) -> bool {
&*key.as_str() == self
} }
} }
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16; const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
const ATOM_TABLE_ALIGN: usize = 8; const ATOM_TABLE_ALIGN: usize = 8;
#[cfg(test)] #[inline(always)]
thread_local! { fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {
static ATOM_TABLE_BUF_BASE: std::cell::RefCell<*const u8> = std::cell::RefCell::new(ptr::null_mut()); #[cfg(feature = "rust_beta_channel")]
}
#[cfg(not(test))]
static ATOM_TABLE_BUF_BASE: std::sync::atomic::AtomicPtr<u8> =
std::sync::atomic::AtomicPtr::new(ptr::null_mut());
fn set_atom_tbl_buf_base(old_ptr: *const u8, new_ptr: *const u8) -> Result<(), *const u8> {
#[cfg(test)]
{ {
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| { // const Weak::new will be stabilized in 1.73 which is currently in beta,
let mut borrow = atom_table_buf_base.borrow_mut(); // till then we need a OnceLock for initialization
if *borrow != old_ptr { static GLOBAL_ATOM_TABLE: RwLock<Weak<AtomTable>> = RwLock::const_new(Weak::new());
Err(*borrow) &GLOBAL_ATOM_TABLE
} else { }
*borrow = new_ptr; #[cfg(not(feature = "rust_beta_channel"))]
Ok(())
}
})?;
};
#[cfg(not(test))]
{ {
ATOM_TABLE_BUF_BASE use std::sync::OnceLock;
.compare_exchange( static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<AtomTable>>> = OnceLock::new();
old_ptr.cast_mut(), GLOBAL_ATOM_TABLE.get_or_init(|| RwLock::new(Weak::new()))
new_ptr.cast_mut(),
std::sync::atomic::Ordering::Relaxed,
std::sync::atomic::Ordering::Relaxed,
)
.map_err(|ptr| ptr.cast_const())
}?;
Ok(())
}
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
#[cfg(test)]
{
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow())
}
#[cfg(not(test))]
{
ATOM_TABLE_BUF_BASE.load(std::sync::atomic::Ordering::Relaxed)
} }
} }
#[test] #[inline(always)]
#[should_panic(expected = "Overwriting atom table base pointer")] fn arc_atom_table() -> Option<Arc<AtomTable>> {
fn atomtable_is_not_concurrency_safe() { global_atom_table().read().unwrap().upgrade()
let _table_a = AtomTable::new();
let _table_b = AtomTable::new();
} }
impl RawBlockTraits for AtomTable { impl RawBlockTraits for AtomTable {
@@ -109,9 +92,11 @@ impl RawBlockTraits for AtomTable {
#[bitfield] #[bitfield]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct AtomHeader { struct AtomHeader {
#[allow(unused)] m: bool, #[allow(unused)]
m: bool,
len: B50, len: B50,
#[allow(unused)] padding: B13, #[allow(unused)]
padding: B13,
} }
impl AtomHeader { impl AtomHeader {
@@ -120,13 +105,6 @@ impl AtomHeader {
} }
} }
impl Borrow<str> for Atom {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl Hash for Atom { impl Hash for Atom {
#[inline] #[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) { fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -142,29 +120,76 @@ macro_rules! is_char {
}; };
} }
impl Atom { pub enum AtomString<'a> {
#[inline] Static(&'a str),
pub fn buf(self) -> *const u8 { Dynamic(AtomTableRef<str>),
let ptr = self.as_ptr(); }
if ptr.is_null() { impl AtomString<'_> {
return ptr::null(); pub fn map<F>(self, f: F) -> Self
where
for<'a> F: FnOnce(&'a str) -> &'a str,
{
match self {
Self::Static(reference) => Self::Static(f(reference)),
Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
} }
}
}
(ptr as usize + mem::size_of::<AtomHeader>()) as *const u8 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::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(always)] #[inline(always)]
pub fn is_static(self) -> bool { pub fn is_static(self) -> bool {
(self.index as usize) < STRINGS.len() << 3 (self.index as usize) < STRINGS.len() << 3
} }
#[inline(always)] #[inline(always)]
pub fn as_ptr(self) -> *const u8 { pub fn as_ptr(self) -> Option<AtomTableRef<u8>> {
if self.is_static() { if self.is_static() {
ptr::null() None
} else { } else {
(get_atom_tbl_buf_base() as usize + (self.index as usize) - (STRINGS.len() << 3)) as *const u8 let atom_table =
arc_atom_table().expect("We should only have an Atom while there is an AtomTable");
unsafe {
AtomTableRef::try_map(atom_table.buf(), |buf| {
(buf as *const u8)
.offset(((self.index as usize) - (STRINGS.len() << 3)) as isize)
.as_ref()
})
}
} }
} }
@@ -178,7 +203,9 @@ impl Atom {
if self.is_static() { if self.is_static() {
STRINGS[(self.index >> 3) as usize].len() STRINGS[(self.index >> 3) as usize].len()
} else { } else {
unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ } let ptr = self.as_ptr().unwrap();
let ptr = ptr.deref() as *const u8 as *const AtomHeader;
unsafe { ptr::read(ptr) }.len() as _
} }
} }
@@ -194,41 +221,44 @@ impl Atom {
let c1 = it.next(); let c1 = it.next();
let c2 = it.next(); let c2 = it.next();
if c2.is_none() { c1 } else { None } if c2.is_none() {
} c1
} else {
#[inline] None
pub fn chars(&self) -> str::Chars {
self.as_str().chars()
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe {
let ptr = self.as_ptr();
if ptr.is_null() {
return STRINGS[(self.index >> 3) as usize];
}
let header = ptr::read::<AtomHeader>(ptr as *const _);
let len = header.len() as usize;
let buf = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
str::from_utf8_unchecked(slice::from_raw_parts(buf, len))
} }
} }
pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self { #[inline]
pub fn as_str(&self) -> AtomString<'static> {
if self.is_static() {
AtomString::Static(STRINGS[(self.index >> 3) as usize])
} else {
if let Some(ptr) = self.as_ptr() {
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| {
let header =
unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
let len = header.len() as usize;
let buf =
unsafe { (ptr as *const u8).offset(mem::size_of::<AtomHeader>() as isize) };
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) }
}))
} else {
AtomString::Static(&STRINGS[(self.index >> 3) as usize])
}
}
}
pub fn defrock_brackets(&self, atom_tbl: &AtomTable) -> Self {
let s = self.as_str(); let s = self.as_str();
let s = if s.starts_with('(') && s.ends_with(')') { let sub_str = if s.starts_with('(') && s.ends_with(')') {
&s['('.len_utf8()..s.len() - ')'.len_utf8()] &s['('.len_utf8()..s.len() - ')'.len_utf8()]
} else { } else {
return *self; return *self;
}; };
atom_tbl.build_with(s) AtomTable::build_with(&atom_tbl, &sub_str)
} }
} }
@@ -248,116 +278,156 @@ impl PartialOrd for Atom {
impl Ord for Atom { impl Ord for Atom {
#[inline] #[inline]
fn cmp(&self, other: &Atom) -> Ordering { fn cmp(&self, other: &Atom) -> Ordering {
self.as_str().cmp(other.as_str()) self.as_str().cmp(&*other.as_str())
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct AtomTable { pub struct InnerAtomTable {
block: RawBlock<AtomTable>, block: RawBlock<AtomTable>,
pub table: IndexSet<Atom>, pub table: Rcu<IndexSet<Atom>>,
} }
#[cold] #[derive(Debug)]
fn atom_table_base_pointer_mismatch(expected: *const u8, got: *const u8) -> ! { pub struct AtomTable {
assert_eq!(expected, got, "Overwriting atom table base pointer, expected old value to be {expected:p}, but found {got:p}"); inner: Rcu<InnerAtomTable>,
unreachable!("This should only be called in a case of a mismatch as such the assert_eq should have failed!") // this lock is taking during resizing
update: Mutex<()>,
} }
impl Drop for AtomTable { pub type AtomTableRef<M> = RcuRef<InnerAtomTable, M>;
fn drop(&mut self) {
if let Err(got) = set_atom_tbl_buf_base(self.block.base, ptr::null()) { impl InnerAtomTable {
atom_table_base_pointer_mismatch(self.block.base, got); #[inline(always)]
} fn lookup_str(self: &InnerAtomTable, string: &str) -> Option<Atom> {
self.block.deallocate(); STATIC_ATOMS_MAP
.get(string)
.cloned()
.or_else(|| self.table.active_epoch().get(string).cloned())
} }
} }
impl AtomTable { impl AtomTable {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Arc<Self> {
let mut block = RawBlock::new(); 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 Err(got) = set_atom_tbl_buf_base(ptr::null(), block.base) { if let Some(atom_table) = upgraded {
block.deallocate(); atom_table
atom_table_base_pointer_mismatch(ptr::null(), got); } else {
} let mut guard = global_atom_table().write().unwrap();
// try to upgrade again in case we lost the race on the write lock
Self { if let Some(atom_table) = guard.upgrade() {
block, atom_table
table: IndexSet::new(), } else {
let atom_table = Arc::new(Self {
inner: Rcu::new(InnerAtomTable {
block: RawBlock::new(),
table: Rcu::new(IndexSet::new()),
}),
update: Mutex::new(()),
});
*guard = Arc::downgrade(&atom_table);
atom_table
}
} }
} }
#[inline] #[inline]
pub fn buf(&self) -> *const u8 { pub fn buf(&self) -> AtomTableRef<u8> {
self.block.base as *const u8 AtomTableRef::<InnerAtomTable>::map(self.inner.active_epoch(), |inner| {
unsafe { inner.block.base.as_ref() }.unwrap()
})
} }
#[inline] pub fn active_table(&self) -> RcuRef<IndexSet<Atom>, IndexSet<Atom>> {
pub fn top(&self) -> *const u8 { self.inner.active_epoch().table.active_epoch()
self.block.top
} }
#[inline(always)] pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
fn lookup_str(&self, string: &str) -> Option<Atom> { loop {
STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned() let mut block_epoch = atom_table.inner.active_epoch();
} let mut table_epoch = block_epoch.table.active_epoch();
pub fn build_with(&mut self, string: &str) -> Atom { if let Some(atom) = block_epoch.lookup_str(string) {
if let Some(atom) = self.lookup_str(string) { return atom;
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.active_epoch());
let is_same_atom_list =
RcuRef::same_epoch(&table_epoch, &block_epoch.table.active_epoch());
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;
}
unsafe {
let size = mem::size_of::<AtomHeader>() + string.len(); let size = mem::size_of::<AtomHeader>() + string.len();
let align_offset = 8 * mem::align_of::<AtomHeader>(); let align_offset = 8 * mem::align_of::<AtomHeader>();
let size = (size & !(align_offset - 1)) + align_offset; let size = (size & !(align_offset - 1)) + align_offset;
let len_ptr = { unsafe {
let mut ptr; let len_ptr = loop {
let ptr = block_epoch.block.alloc(size);
loop {
ptr = self.block.alloc(size);
if ptr.is_null() { if ptr.is_null() {
let old_base = self.block.base; // garbage collection would go here
self.block.grow(); let new_block = block_epoch.block.grow_new().unwrap();
if let Err(got) = set_atom_tbl_buf_base(old_base, self.block.base) { let new_table = Rcu::new(table_epoch.clone());
atom_table_base_pointer_mismatch(old_base, got); let new_alloc = InnerAtomTable {
} block: new_block,
table: new_table,
};
atom_table.inner.replace(new_alloc);
block_epoch = atom_table.inner.active_epoch();
table_epoch = block_epoch.table.active_epoch();
} else { } else {
break; break ptr;
} }
} };
ptr let ptr_base = block_epoch.block.base as usize;
};
let ptr_base = self.block.base as usize; write_to_ptr(string, len_ptr);
write_to_ptr(string, len_ptr); let atom = Atom {
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
};
let atom = Atom { let mut table = table_epoch.clone();
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64, table.insert(atom);
}; block_epoch.table.replace(table);
self.table.insert(atom); // expicit drop to ensure we don't accidentally drop it early
drop(update_guard);
atom return atom;
}
} }
} }
} }
unsafe impl Send for AtomTable {}
unsafe impl Sync for AtomTable {}
#[bitfield] #[bitfield]
#[repr(u64)] #[repr(u64)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct AtomCell { pub struct AtomCell {
name: B46, name: B46,
arity: B10, arity: B10,
#[allow(unused)] f: bool, #[allow(unused)]
#[allow(unused)] m: bool, f: bool,
#[allow(unused)] tag: B6, #[allow(unused)]
m: bool,
#[allow(unused)]
tag: B6,
} }
impl AtomCell { impl AtomCell {

View File

@@ -1,12 +1,28 @@
fn main() -> std::process::ExitCode { fn main() -> std::process::ExitCode {
use std::sync::atomic::Ordering;
use scryer_prolog::*; use scryer_prolog::*;
use scryer_prolog::atom_table::Atom;
use std::sync::atomic::Ordering;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed); scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
}).unwrap(); })
.unwrap();
let mut wam = machine::Machine::new(); #[cfg(target_arch = "wasm32")]
wam.run_top_level() 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 = machine::Machine::new(Default::default());
wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1))
})
} }

View File

@@ -1,14 +1,14 @@
use crate::atom_table::*;
use crate::parser::ast::*;
use crate::temp_v;
use crate::allocator::*; use crate::allocator::*;
use crate::arithmetic::*; use crate::arithmetic::*;
use crate::atom_table::*;
use crate::debray_allocator::*; use crate::debray_allocator::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::*; use crate::indexing::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::parser::ast::*;
use crate::targets::*; use crate::targets::*;
use crate::temp_v;
use crate::types::*; use crate::types::*;
use crate::instr; use crate::instr;
@@ -48,15 +48,20 @@ impl BranchCodeStack {
} }
fn code<'a>(&'a mut self, default_code: &'a mut CodeDeque) -> &'a mut CodeDeque { fn code<'a>(&'a mut self, default_code: &'a mut CodeDeque) -> &'a mut CodeDeque {
self.stack.last_mut() self.stack
.last_mut()
.and_then(|stack| stack.last_mut()) .and_then(|stack| stack.last_mut())
.unwrap_or(default_code) .unwrap_or(default_code)
} }
fn push_missing_vars(&mut self, depth: usize, marker: &mut DebrayAllocator) -> SubsumedBranchHits { fn push_missing_vars(
&mut self,
depth: usize,
marker: &mut DebrayAllocator,
) -> SubsumedBranchHits {
let mut subsumed_hits = SubsumedBranchHits::with_hasher(FxBuildHasher::default()); let mut subsumed_hits = SubsumedBranchHits::with_hasher(FxBuildHasher::default());
for idx in (self.stack.len() - depth .. self.stack.len()).rev() { for idx in (self.stack.len() - depth..self.stack.len()).rev() {
let branch = &mut marker.branch_stack[idx]; let branch = &mut marker.branch_stack[idx];
let branch_hits = &branch.hits; let branch_hits = &branch.hits;
@@ -91,14 +96,14 @@ impl BranchCodeStack {
fn push_jump_instrs(&mut self, depth: usize) { fn push_jump_instrs(&mut self, depth: usize) {
// add 2 in each arm length to compensate for each jump // add 2 in each arm length to compensate for each jump
// instruction and each branch instruction not yet added. // instruction and each branch instruction not yet added.
let mut jump_span: usize = self.stack[self.stack.len() - depth ..] let mut jump_span: usize = self.stack[self.stack.len() - depth..]
.iter() .iter()
.map(|branch| branch.iter().map(|code| code.len() + 2).sum::<usize>()) .map(|branch| branch.iter().map(|code| code.len() + 2).sum::<usize>())
.sum(); .sum();
jump_span -= depth; jump_span -= depth;
for idx in self.stack.len() - depth .. self.stack.len() { for idx in self.stack.len() - depth..self.stack.len() {
let inner_len = self.stack[idx].len(); let inner_len = self.stack[idx].len();
for (inner_idx, code) in self.stack[idx].iter_mut().enumerate() { for (inner_idx, code) in self.stack[idx].iter_mut().enumerate() {
@@ -117,9 +122,11 @@ impl BranchCodeStack {
fn pop_branch(&mut self, depth: usize, settings: CodeGenSettings) -> CodeDeque { fn pop_branch(&mut self, depth: usize, settings: CodeGenSettings) -> CodeDeque {
let mut combined_code = CodeDeque::new(); let mut combined_code = CodeDeque::new();
for mut branch_arm in self.stack.drain(self.stack.len() - depth ..).rev() { for mut branch_arm in self.stack.drain(self.stack.len() - depth..).rev() {
let num_branch_arms = branch_arm.len(); let num_branch_arms = branch_arm.len();
branch_arm.last_mut().map(|code| code.extend(combined_code.drain(..))); branch_arm
.last_mut()
.map(|code| code.extend(combined_code.drain(..)));
for (idx, code) in branch_arm.into_iter().enumerate() { for (idx, code) in branch_arm.into_iter().enumerate() {
combined_code.push_back(if idx == 0 { combined_code.push_back(if idx == 0 {
@@ -255,7 +262,7 @@ impl CodeGenSettings {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CodeGenerator<'a> { pub(crate) struct CodeGenerator<'a> {
pub(crate) atom_tbl: &'a mut AtomTable, pub(crate) atom_tbl: &'a AtomTable,
marker: DebrayAllocator, marker: DebrayAllocator,
settings: CodeGenSettings, settings: CodeGenSettings,
pub(crate) skeleton: PredicateSkeleton, pub(crate) skeleton: PredicateSkeleton,
@@ -269,13 +276,7 @@ impl DebrayAllocator {
vr: &Cell<VarReg>, vr: &Cell<VarReg>,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> RegType { ) -> RegType {
self.mark_var::<QueryInstruction>( self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
var_num,
Level::Shallow,
vr,
term_loc,
code,
);
vr.get().norm() vr.get().norm()
} }
@@ -308,8 +309,8 @@ impl DebrayAllocator {
// decrement the arity of the PutStructure instruction by 1. // decrement the arity of the PutStructure instruction by 1.
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) { fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
match instr { match instr {
Instruction::PutStructure(_, ref mut arity, _) | Instruction::PutStructure(_, ref mut arity, _)
Instruction::GetStructure(.., ref mut arity, _) => { | Instruction::GetStructure(.., ref mut arity, _) => {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
// it is acceptable if arity == 0 is the result of // it is acceptable if arity == 0 is the result of
// this decrement. call/N will have to read the index // this decrement. call/N will have to read the index
@@ -352,16 +353,16 @@ impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
fn structure_cell(term: &Term) -> Option<&Cell<RegType>> { fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
match term { match term {
&Term::Cons(ref cell, ..) | &Term::Cons(ref cell, ..)
&Term::Clause(ref cell, ..) | | &Term::Clause(ref cell, ..)
Term::PartialString(ref cell, ..) | | Term::PartialString(ref cell, ..)
Term::CompleteString(ref cell, ..) => Some(cell), | Term::CompleteString(ref cell, ..) => Some(cell),
_ => None, _ => None,
} }
} }
impl<'b> CodeGenerator<'b> { impl<'b> CodeGenerator<'b> {
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
CodeGenerator { CodeGenerator {
atom_tbl, atom_tbl,
marker: DebrayAllocator::new(), marker: DebrayAllocator::new(),
@@ -392,7 +393,8 @@ impl<'b> CodeGenerator<'b> {
target: &mut CodeDeque, target: &mut CodeDeque,
) { ) {
if self.marker.var_data.records[var_num].num_occurrences > 1 { if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker.mark_var::<Target>(var_num, Level::Deep, cell, term_loc, target); self.marker
.mark_var::<Target>(var_num, Level::Deep, cell, term_loc, target);
} else { } else {
Self::add_or_increment_void_instr::<Target>(target); Self::add_or_increment_void_instr::<Target>(target);
} }
@@ -408,31 +410,33 @@ impl<'b> CodeGenerator<'b> {
&Term::AnonVar => { &Term::AnonVar => {
Self::add_or_increment_void_instr::<Target>(target); Self::add_or_increment_void_instr::<Target>(target);
} }
&Term::Cons(ref cell, ..) | &Term::Cons(ref cell, ..)
&Term::Clause(ref cell, ..) | | &Term::Clause(ref cell, ..)
Term::PartialString(ref cell, ..) | | Term::PartialString(ref cell, ..)
Term::CompleteString(ref cell, ..) => { | Term::CompleteString(ref cell, ..) => {
self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target); self.marker
.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
target.push_back(Target::clause_arg_to_instr(cell.get())); target.push_back(Target::clause_arg_to_instr(cell.get()));
} }
&Term::Literal(_, ref constant) => { &Term::Literal(_, ref constant) => {
target.push_back(Target::constant_subterm(constant.clone())); target.push_back(Target::constant_subterm(constant.clone()));
} }
&Term::Var(ref cell, ref var_ptr) => { &Term::Var(ref cell, ref var_ptr) => {
self.deep_var_instr::<Target>(cell, var_ptr.to_var_num().unwrap(), term_loc, target); self.deep_var_instr::<Target>(
cell,
var_ptr.to_var_num().unwrap(),
term_loc,
target,
);
} }
}; };
} }
fn compile_target<'a, Target, Iter>( fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, term_loc: GenContext) -> CodeDeque
&mut self,
iter: Iter,
term_loc: GenContext,
) -> CodeDeque
where where
Target: crate::targets::CompilationTarget<'a>, Target: crate::targets::CompilationTarget<'a>,
Iter: Iterator<Item = TermRef<'a>>, Iter: Iterator<Item = TermRef<'a>>,
CodeGenerator<'b>: AddToFreeList<'a, Target> CodeGenerator<'b>: AddToFreeList<'a, Target>,
{ {
let mut target = CodeDeque::new(); let mut target = CodeDeque::new();
@@ -442,14 +446,19 @@ impl<'b> CodeGenerator<'b> {
if let GenContext::Head = term_loc { if let GenContext::Head = term_loc {
self.marker.advance_arg(); self.marker.advance_arg();
} else { } else {
self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target); self.marker
.mark_anon_var::<Target>(lvl, term_loc, &mut target);
} }
} }
TermRef::Clause(lvl, cell, name, terms) => { TermRef::Clause(lvl, cell, name, terms) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get())); target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get()));
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(self, cell.get()); <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
cell.get(),
);
if let Some(instr) = target.back_mut() { if let Some(instr) = target.back_mut() {
if let Some(term) = terms.last() { if let Some(term) = terms.last() {
@@ -462,38 +471,52 @@ impl<'b> CodeGenerator<'b> {
} }
for subterm in terms { for subterm in terms {
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(self, subterm); <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
self, subterm,
);
} }
} }
TermRef::Cons(lvl, cell, head, tail) => { TermRef::Cons(lvl, cell, head, tail) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_list(lvl, cell.get())); target.push_back(Target::to_list(lvl, cell.get()));
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(self, cell.get()); <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
cell.get(),
);
self.subterm_to_instr::<Target>(head, term_loc, &mut target); self.subterm_to_instr::<Target>(head, term_loc, &mut target);
self.subterm_to_instr::<Target>(tail, term_loc, &mut target); self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(self, head); <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(self, tail); self, head,
);
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
self, tail,
);
} }
TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => { TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_pstr(lvl, *string, cell.get(), false)); target.push_back(Target::to_pstr(lvl, *string, cell.get(), false));
} }
TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_constant(lvl, *constant, cell.get())); target.push_back(Target::to_constant(lvl, *constant, cell.get()));
} }
TermRef::PartialString(lvl, cell, string, tail) => { TermRef::PartialString(lvl, cell, string, tail) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
let atom = self.atom_tbl.build_with(&string); .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
let atom = AtomTable::build_with(&self.atom_tbl, &string);
target.push_back(Target::to_pstr(lvl, atom, cell.get(), true)); target.push_back(Target::to_pstr(lvl, atom, cell.get(), true));
self.subterm_to_instr::<Target>(tail, term_loc, &mut target); self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
} }
TermRef::CompleteString(lvl, cell, atom) => { TermRef::CompleteString(lvl, cell, atom) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_pstr(lvl, atom, cell.get(), false)); target.push_back(Target::to_pstr(lvl, atom, cell.get(), false));
} }
TermRef::Var(lvl @ Level::Shallow, cell, var) => { TermRef::Var(lvl @ Level::Shallow, cell, var) => {
@@ -563,9 +586,9 @@ impl<'b> CodeGenerator<'b> {
compare_number_instr!(cmp, at_1, at_2) compare_number_instr!(cmp, at_1, at_2)
} }
&InlinedClauseType::IsAtom(..) => match &terms[0] { &InlinedClauseType::IsAtom(..) => match &terms[0] {
&Term::Literal(_, Literal::Char(_)) | &Term::Literal(_, Literal::Char(_))
&Term::Literal(_, Literal::Atom(atom!("[]"))) | | &Term::Literal(_, Literal::Atom(atom!("[]")))
&Term::Literal(_, Literal::Atom(..)) => { | &Term::Literal(_, Literal::Atom(..)) => {
instr!("$succeed") instr!("$succeed")
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
@@ -586,11 +609,11 @@ impl<'b> CodeGenerator<'b> {
} }
}, },
&InlinedClauseType::IsAtomic(..) => match &terms[0] { &InlinedClauseType::IsAtomic(..) => match &terms[0] {
&Term::AnonVar | &Term::AnonVar
&Term::Clause(..) | | &Term::Clause(..)
&Term::Cons(..) | | &Term::Cons(..)
&Term::PartialString(..) | | &Term::PartialString(..)
&Term::CompleteString(..) => { | &Term::CompleteString(..) => {
instr!("$fail") instr!("$fail")
} }
&Term::Literal(_, Literal::String(_)) => { &Term::Literal(_, Literal::String(_)) => {
@@ -614,11 +637,11 @@ impl<'b> CodeGenerator<'b> {
} }
}, },
&InlinedClauseType::IsCompound(..) => match &terms[0] { &InlinedClauseType::IsCompound(..) => match &terms[0] {
&Term::Clause(..) | &Term::Clause(..)
&Term::Cons(..) | | &Term::Cons(..)
&Term::PartialString(..) | | &Term::PartialString(..)
&Term::CompleteString(..) | | &Term::CompleteString(..)
&Term::Literal(_, Literal::String(..)) => { | &Term::Literal(_, Literal::String(..)) => {
instr!("$succeed") instr!("$succeed")
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
@@ -644,7 +667,13 @@ impl<'b> CodeGenerator<'b> {
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1); self.marker.reset_arg(1);
let r = self.marker.mark_non_callable(name.to_var_num().unwrap(), 1, term_loc, vr, code); let r = self.marker.mark_non_callable(
name.to_var_num().unwrap(),
1,
term_loc,
vr,
code,
);
instr!("rational", r) instr!("rational", r)
} }
_ => { _ => {
@@ -673,10 +702,10 @@ impl<'b> CodeGenerator<'b> {
} }
}, },
&InlinedClauseType::IsNumber(..) => match &terms[0] { &InlinedClauseType::IsNumber(..) => match &terms[0] {
&Term::Literal(_, Literal::Float(_)) | &Term::Literal(_, Literal::Float(_))
&Term::Literal(_, Literal::Rational(_)) | | &Term::Literal(_, Literal::Rational(_))
&Term::Literal(_, Literal::Integer(_)) | | &Term::Literal(_, Literal::Integer(_))
&Term::Literal(_, Literal::Fixnum(_)) => { | &Term::Literal(_, Literal::Fixnum(_)) => {
instr!("$succeed") instr!("$succeed")
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
@@ -718,8 +747,7 @@ impl<'b> CodeGenerator<'b> {
} }
}, },
&InlinedClauseType::IsInteger(..) => match &terms[0] { &InlinedClauseType::IsInteger(..) => match &terms[0] {
&Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => {
&Term::Literal(_, Literal::Fixnum(_)) => {
instr!("$succeed") instr!("$succeed")
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
@@ -740,11 +768,11 @@ impl<'b> CodeGenerator<'b> {
} }
}, },
&InlinedClauseType::IsVar(..) => match &terms[0] { &InlinedClauseType::IsVar(..) => match &terms[0] {
&Term::Literal(..) | &Term::Literal(..)
&Term::Clause(..) | | &Term::Clause(..)
&Term::Cons(..) | | &Term::Cons(..)
&Term::PartialString(..) | | &Term::PartialString(..)
&Term::CompleteString(..) => { | &Term::CompleteString(..) => {
instr!("$fail") instr!("$fail")
} }
&Term::AnonVar => { &Term::AnonVar => {
@@ -791,11 +819,11 @@ impl<'b> CodeGenerator<'b> {
call_policy: CallPolicy, call_policy: CallPolicy,
) -> Result<(), CompilationError> { ) -> Result<(), CompilationError> {
macro_rules! compile_expr { macro_rules! compile_expr {
($self:expr, $terms:expr, $term_loc:expr, $code:expr) => ({ ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{
let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?; let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?;
$code.extend(acode.into_iter()); $code.extend(acode.into_iter());
at at
}); }};
} }
self.marker.reset_arg(2); self.marker.reset_arg(2);
@@ -804,22 +832,52 @@ impl<'b> CodeGenerator<'b> {
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
let var_num = name.to_var_num().unwrap(); let var_num = name.to_var_num().unwrap();
self.marker.mark_var::<QueryInstruction>( if self.marker.var_data.records[var_num].num_occurrences > 1 {
var_num, self.marker.mark_var::<QueryInstruction>(
Level::Shallow, var_num,
vr, Level::Shallow,
term_loc, vr,
code, term_loc,
); code,
);
self.marker.mark_safe_var_unconditionally(var_num); self.marker.mark_safe_var_unconditionally(var_num);
compile_expr!(self, &terms[1], term_loc, code)
} else {
if let Term::Var(ref vr, ref var) = &terms[1] {
let var_num = var.to_var_num().unwrap();
compile_expr!(self, &terms[1], term_loc, code) // if var is an anonymous variable, insert
// is/2 call so that an instantiation error is
// thrown when the predicate is run.
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker.mark_var::<QueryInstruction>(
var_num,
Level::Shallow,
vr,
term_loc,
code,
);
self.marker.mark_safe_var_unconditionally(var_num);
let at = ArithmeticTerm::Reg(vr.get().norm());
self.add_call(code, instr!("$get_number", at), call_policy);
return Ok(());
}
}
compile_expr!(self, &terms[1], term_loc, code)
}
} }
&Term::Literal(_, c @ Literal::Integer(_) | &Term::Literal(
c @ Literal::Float(_) | _,
c @ Literal::Rational(_) | c @ Literal::Integer(_)
c @ Literal::Fixnum(_)) => { | c @ Literal::Float(_)
| c @ Literal::Rational(_)
| c @ Literal::Fixnum(_),
) => {
let v = HeapCellValue::from(c); let v = HeapCellValue::from(c);
code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
@@ -892,10 +950,15 @@ impl<'b> CodeGenerator<'b> {
code.push_back(instr!("proceed")); code.push_back(instr!("proceed"));
} }
} }
&QueryTerm::LocalCut(var_num) => { &QueryTerm::LocalCut { var_num, cut_prev } => {
let code = branch_code_stack.code(code); let code = branch_code_stack.code(code);
let r = self.marker.get_binding(var_num); let r = self.marker.get_binding(var_num);
code.push_back(instr!("cut", r));
code.push_back(if cut_prev {
instr!("cut_prev", r)
} else {
instr!("cut", r)
});
if self.marker.in_tail_position { if self.marker.in_tail_position {
if self.marker.var_data.allocates { if self.marker.var_data.allocates {
@@ -912,15 +975,29 @@ impl<'b> CodeGenerator<'b> {
ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
ref terms, ref terms,
call_policy, call_policy,
) => self.compile_is_call(terms, branch_code_stack.code(code), term_loc, call_policy)?, ) => self.compile_is_call(
terms,
branch_code_stack.code(code),
term_loc,
call_policy,
)?,
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => { &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
self.compile_inlined(ct, terms, term_loc, branch_code_stack.code(code))? self.compile_inlined(
ct,
terms,
term_loc,
branch_code_stack.code(code),
)?
} }
&QueryTerm::Fail => { &QueryTerm::Fail => {
branch_code_stack.code(code).push_back(instr!("$fail")); branch_code_stack.code(code).push_back(instr!("$fail"));
} }
term @ &QueryTerm::Clause(..) => { term @ &QueryTerm::Clause(..) => {
self.compile_query_line(term, term_loc, branch_code_stack.code(code)); self.compile_query_line(
term,
term_loc,
branch_code_stack.code(code),
);
if self.marker.max_reg_allocated() > MAX_ARITY { if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity); return Err(CompilationError::ExceededMaxArity);
@@ -948,7 +1025,8 @@ impl<'b> CodeGenerator<'b> {
} }
ClauseItem::BranchEnd(depth) => { ClauseItem::BranchEnd(depth) => {
if !clause_iter.in_tail_position() { if !clause_iter.in_tail_position() {
let subsumed_hits = branch_code_stack.push_missing_vars(depth, &mut self.marker); let subsumed_hits =
branch_code_stack.push_missing_vars(depth, &mut self.marker);
self.marker.pop_branch(depth, subsumed_hits); self.marker.pop_branch(depth, subsumed_hits);
branch_code_stack.push_jump_instrs(depth); branch_code_stack.push_jump_instrs(depth);
} else { } else {
@@ -974,8 +1052,15 @@ impl<'b> CodeGenerator<'b> {
Ok(()) Ok(())
} }
pub(crate) fn compile_rule(&mut self, rule: &Rule, var_data: VarData) -> Result<Code, CompilationError> { pub(crate) fn compile_rule(
let Rule { head: (_, args), clauses } = rule; &mut self,
rule: &Rule,
var_data: VarData,
) -> Result<Code, CompilationError> {
let Rule {
head: (_, args),
clauses,
} = rule;
self.marker.var_data = var_data; self.marker.var_data = var_data;
let mut code = VecDeque::new(); let mut code = VecDeque::new();
@@ -996,7 +1081,11 @@ impl<'b> CodeGenerator<'b> {
Ok(Vec::from(code)) Ok(Vec::from(code))
} }
pub(crate) fn compile_fact(&mut self, fact: &Fact, var_data: VarData) -> Result<Code, CompilationError> { pub(crate) fn compile_fact(
&mut self,
fact: &Fact,
var_data: VarData,
) -> Result<Code, CompilationError> {
let mut code = Vec::new(); let mut code = Vec::new();
self.marker.var_data = var_data; self.marker.var_data = var_data;
@@ -1004,10 +1093,7 @@ impl<'b> CodeGenerator<'b> {
self.marker.reset_at_head(args); self.marker.reset_at_head(args);
let iter = FactInstruction::iter(&fact.head); let iter = FactInstruction::iter(&fact.head);
let compiled_fact = self.compile_target::<FactInstruction, _>( let compiled_fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
iter,
GenContext::Head,
);
if self.marker.max_reg_allocated() > MAX_ARITY { if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity); return Err(CompilationError::ExceededMaxArity);
@@ -1032,7 +1118,7 @@ impl<'b> CodeGenerator<'b> {
&QueryTerm::Clause(_, ref ct, _, call_policy) => { &QueryTerm::Clause(_, ref ct, _, call_policy) => {
self.add_call(code, ct.to_instr(), call_policy); self.add_call(code, ct.to_instr(), call_policy);
} }
_ => unreachable!() _ => unreachable!(),
}; };
} }
@@ -1045,8 +1131,7 @@ impl<'b> CodeGenerator<'b> {
if let Some(args) = clause.args() { if let Some(args) = clause.args() {
for (instantiated_arg_index, arg) in args.iter().enumerate() { for (instantiated_arg_index, arg) in args.iter().enumerate() {
match arg { match arg {
Term::Var(..) | Term::AnonVar => { Term::Var(..) | Term::AnonVar => {}
}
_ => { _ => {
if optimal_index != instantiated_arg_index { if optimal_index != instantiated_arg_index {
if left >= right { if left >= right {
@@ -1071,7 +1156,11 @@ impl<'b> CodeGenerator<'b> {
} }
if left < right { if left < right {
subseqs.push(ClauseSpan { left, right, instantiated_arg_index: optimal_index }); subseqs.push(ClauseSpan {
left,
right,
instantiated_arg_index: optimal_index,
});
} }
optimal_index = 0; optimal_index = 0;
@@ -1102,7 +1191,8 @@ impl<'b> CodeGenerator<'b> {
optimal_index: usize, optimal_index: usize,
) -> Result<Code, CompilationError> { ) -> Result<Code, CompilationError> {
let mut code = VecDeque::new(); let mut code = VecDeque::new();
let mut code_offsets = CodeOffsets::new(I::new(), optimal_index + 1); let mut code_offsets =
CodeOffsets::new(I::new(), optimal_index + 1, self.settings.non_counted_bt);
let mut skip_stub_try_me_else = false; let mut skip_stub_try_me_else = false;
let clauses_len = clauses.len(); let clauses_len = clauses.len();
@@ -1147,7 +1237,9 @@ impl<'b> CodeGenerator<'b> {
skip_stub_try_me_else = !self.settings.is_dynamic(); skip_stub_try_me_else = !self.settings.is_dynamic();
} }
let arg = clause.args().and_then(|args| args.iter().nth(optimal_index)); let arg = clause
.args()
.and_then(|args| args.iter().nth(optimal_index));
if let Some(arg) = arg { if let Some(arg) = arg {
let index = code.len(); let index = code.len();
@@ -1190,7 +1282,12 @@ impl<'b> CodeGenerator<'b> {
let split_pred = Self::split_predicate(&clauses); let split_pred = Self::split_predicate(&clauses);
let multi_seq = split_pred.len() > 1; let multi_seq = split_pred.len() > 1;
for ClauseSpan { left, right, instantiated_arg_index } in split_pred { for ClauseSpan {
left,
right,
instantiated_arg_index,
} in split_pred
{
let skel_lower_bound = self.skeleton.clauses.len(); let skel_lower_bound = self.skeleton.clauses.len();
let code_segment = if self.settings.is_dynamic() { let code_segment = if self.settings.is_dynamic() {
self.compile_pred_subseq::<DynamicCodeIndices>( self.compile_pred_subseq::<DynamicCodeIndices>(
@@ -1221,9 +1318,8 @@ impl<'b> CodeGenerator<'b> {
if self.settings.is_extensible { if self.settings.is_extensible {
let segment_is_indexed = code_segment[0].to_indexing_line().is_some(); let segment_is_indexed = code_segment[0].to_indexing_line().is_some();
for clause_index_info in self.skeleton.clauses for clause_index_info in
.make_contiguous()[skel_lower_bound..] self.skeleton.clauses.make_contiguous()[skel_lower_bound..].iter_mut()
.iter_mut()
{ {
clause_index_info.clause_start += clause_index_info.clause_start +=
clause_start_offset + 2 * (segment_is_indexed as usize); clause_start_offset + 2 * (segment_is_indexed as usize);

View File

@@ -76,11 +76,16 @@ impl BranchStack {
} }
} }
fn safety_unneeded_in_branch(&self, safety: &VarSafetyStatus, branch: &BranchDesignator) -> bool { fn safety_unneeded_in_branch(
&self,
safety: &VarSafetyStatus,
branch: &BranchDesignator,
) -> bool {
match safety { match safety {
VarSafetyStatus::Needed => false, VarSafetyStatus::Needed => false,
VarSafetyStatus::LocallyUnneeded(planter_branch) => VarSafetyStatus::LocallyUnneeded(planter_branch) => {
self.branch_subsumes(planter_branch, branch), self.branch_subsumes(planter_branch, branch)
}
VarSafetyStatus::GloballyUnneeded => true, VarSafetyStatus::GloballyUnneeded => true,
} }
} }
@@ -91,7 +96,9 @@ impl BranchStack {
let num_branches = occurrences.num_branches; let num_branches = occurrences.num_branches;
let entry = occurrences.hits.entry(var_num) let entry = occurrences
.hits
.entry(var_num)
.or_insert_with(|| BitVec::repeat(false, num_branches)); .or_insert_with(|| BitVec::repeat(false, num_branches));
entry.set(occurrences.current_branch, true); entry.set(occurrences.current_branch, true);
@@ -105,11 +112,15 @@ impl BranchStack {
pub(crate) fn current_branch_designator(&self) -> BranchDesignator { pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
let branch_stack_num = self.len(); let branch_stack_num = self.len();
let branch_num = self.last() let branch_num = self
.last()
.map(|occurrences| occurrences.current_branch) .map(|occurrences| occurrences.current_branch)
.unwrap_or(0); .unwrap_or(0);
BranchDesignator { branch_stack_num, branch_num } BranchDesignator {
branch_stack_num,
branch_num,
}
} }
#[inline] #[inline]
@@ -121,7 +132,7 @@ impl BranchStack {
#[inline] #[inline]
pub(crate) fn drain_branches(&mut self, depth: usize) -> std::vec::Drain<BranchOccurrences> { pub(crate) fn drain_branches(&mut self, depth: usize) -> std::vec::Drain<BranchOccurrences> {
let start_idx = self.len() - depth; let start_idx = self.len() - depth;
self.drain(start_idx ..) self.drain(start_idx..)
} }
} }
@@ -156,13 +167,23 @@ impl DebrayAllocator {
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, ref mut allocation) => { VarAlloc::Perm(_, ref mut allocation) => {
match allocation { match allocation {
PermVarAllocation::Done { shallow_safety, deep_safety, .. } => { PermVarAllocation::Done {
if !self.branch_stack.safety_unneeded_in_branch(shallow_safety, &branch_designator) { shallow_safety,
deep_safety,
..
} => {
if !self
.branch_stack
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
{
let branch_occurrences = self.branch_stack.last_mut().unwrap(); let branch_occurrences = self.branch_stack.last_mut().unwrap();
branch_occurrences.shallow_safety.insert(var_num); branch_occurrences.shallow_safety.insert(var_num);
} }
if !self.branch_stack.safety_unneeded_in_branch(deep_safety, &branch_designator) { if !self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
{
let branch_occurrences = self.branch_stack.last_mut().unwrap(); let branch_occurrences = self.branch_stack.last_mut().unwrap();
branch_occurrences.deep_safety.insert(var_num); branch_occurrences.deep_safety.insert(var_num);
} }
@@ -182,15 +203,15 @@ impl DebrayAllocator {
pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) { pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) {
let removed_branches = self.branch_stack.drain_branches(depth); let removed_branches = self.branch_stack.drain_branches(depth);
let (deep_safety, shallow_safety) = removed_branches let (deep_safety, shallow_safety) = removed_branches.into_iter().fold(
.into_iter() (BitSet::default(), BitSet::default()),
.fold((BitSet::default(), BitSet::default()), |(mut deep_safety, mut shallow_safety), branch_occurrences| {
|(mut deep_safety, mut shallow_safety), branch_occurrences| { deep_safety.union_with(&branch_occurrences.deep_safety);
deep_safety.union_with(&branch_occurrences.deep_safety); shallow_safety.union_with(&branch_occurrences.shallow_safety);
shallow_safety.union_with(&branch_occurrences.shallow_safety);
(deep_safety, shallow_safety) (deep_safety, shallow_safety)
}); },
);
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
@@ -201,7 +222,7 @@ impl DebrayAllocator {
(&latest_branch.deep_safety, &latest_branch.shallow_safety) (&latest_branch.deep_safety, &latest_branch.shallow_safety)
} }
None => (&deep_safety, &shallow_safety) None => (&deep_safety, &shallow_safety),
}; };
for var_num in subsumed_hits.iter().cloned() { for var_num in subsumed_hits.iter().cloned() {
@@ -221,10 +242,13 @@ impl DebrayAllocator {
); );
if running_count < num_occurrences { if running_count < num_occurrences {
*allocation = PermVarAllocation::Done { shallow_safety, deep_safety }; *allocation = PermVarAllocation::Done {
shallow_safety,
deep_safety,
};
} }
} }
_ => unreachable!() _ => unreachable!(),
} }
} }
@@ -244,9 +268,11 @@ impl DebrayAllocator {
fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool { fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool {
match &self.var_data.records[var_num].allocation { match &self.var_data.records[var_num].allocation {
VarAlloc::Temp { temp_var_data, term_loc: GenContext::Head, .. } => { VarAlloc::Temp {
temp_var_data.use_set.contains(&(GenContext::Head, r)) temp_var_data,
} term_loc: GenContext::Head,
..
} => temp_var_data.use_set.contains(&(GenContext::Head, r)),
_ => false, _ => false,
} }
} }
@@ -325,12 +351,14 @@ impl DebrayAllocator {
match &self.var_data.records[t_var].allocation { match &self.var_data.records[t_var].allocation {
VarAlloc::Temp { temp_var_data, .. } => { VarAlloc::Temp { temp_var_data, .. } => {
if !temp_var_data.use_set.contains(&(GenContext::Last(chunk_num), k)) { if !temp_var_data
.use_set
.contains(&(GenContext::Last(chunk_num), k))
{
return Some((t_var, self.alloc_with_ca(t_var))); return Some((t_var, self.alloc_with_ca(t_var)));
} }
} }
_ => { _ => {}
}
} }
None None
@@ -356,7 +384,9 @@ impl DebrayAllocator {
self.shallow_temp_mappings.swap_remove(&k); self.shallow_temp_mappings.swap_remove(&k);
self.shallow_temp_mappings.insert(r.reg_num(), var_num); self.shallow_temp_mappings.insert(r.reg_num(), var_num);
self.var_data.records[var_num].allocation.set_register(r.reg_num()); self.var_data.records[var_num]
.allocation
.set_register(r.reg_num());
self.in_use.insert(r.reg_num()); self.in_use.insert(r.reg_num());
} }
} }
@@ -417,12 +447,9 @@ impl DebrayAllocator {
fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool { fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool {
match term_loc { match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k, GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => { _ => match &self.var_data.records[var_num].allocation {
match &self.var_data.records[var_num].allocation { &VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k => temp_reg == k,
&VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k => _ => false,
temp_reg == k,
_ => false,
}
}, },
} }
} }
@@ -483,8 +510,7 @@ impl DebrayAllocator {
VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => { VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
return Some(std::mem::replace(p, 0)); return Some(std::mem::replace(p, 0));
} }
_ => { _ => {}
}
} }
} else { } else {
return None; return None;
@@ -500,8 +526,7 @@ impl DebrayAllocator {
*allocation = PermVarAllocation::Pending; *allocation = PermVarAllocation::Pending;
self.add_perm_to_free_list(chunk_num, var_num); self.add_perm_to_free_list(chunk_num, var_num);
} }
_ => { _ => {}
}
} }
} }
@@ -509,7 +534,14 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => { VarAlloc::Perm(
_,
PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
) => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator); *deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator); *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
} }
@@ -524,7 +556,14 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => { VarAlloc::Perm(
_,
PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
) => {
// GetVariable in head chunk is considered safe. // GetVariable in head chunk is considered safe.
if lvl == Level::Deep { if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator); *deep_safety = VarSafetyStatus::unneeded(branch_designator);
@@ -532,12 +571,16 @@ impl DebrayAllocator {
} else if term_loc == GenContext::Head { } else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::GloballyUnneeded; *shallow_safety = VarSafetyStatus::GloballyUnneeded;
} else { } else {
if let Some(temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c).cloned() { if let Some(temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c).cloned()
{
match &mut self.var_data.records[temp_var_num].allocation { match &mut self.var_data.records[temp_var_num].allocation {
VarAlloc::Temp { ref mut to_perm_var_num, .. } => { VarAlloc::Temp {
ref mut to_perm_var_num,
..
} => {
*to_perm_var_num = Some(var_num); *to_perm_var_num = Some(var_num);
} }
_ => unreachable!() _ => unreachable!(),
} }
} }
} }
@@ -560,8 +603,18 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut shallow_safety, .. }) => { VarAlloc::Perm(
if !self.in_tail_position || self.branch_stack.safety_unneeded_in_branch(shallow_safety, &branch_designator) { _,
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) Target::argument_to_value(r, arg_c)
} else { } else {
*shallow_safety = VarSafetyStatus::unneeded(branch_designator); *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
@@ -569,7 +622,10 @@ impl DebrayAllocator {
} }
} }
VarAlloc::Temp { ref mut safety, .. } => { VarAlloc::Temp { ref mut safety, .. } => {
if self.branch_stack.safety_unneeded_in_branch(safety, &branch_designator) { if self
.branch_stack
.safety_unneeded_in_branch(safety, &branch_designator)
{
Target::argument_to_value(r, arg_c) Target::argument_to_value(r, arg_c)
} else { } else {
*safety = VarSafetyStatus::GloballyUnneeded; *safety = VarSafetyStatus::GloballyUnneeded;
@@ -590,8 +646,17 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut deep_safety, .. }) => { VarAlloc::Perm(
if self.branch_stack.safety_unneeded_in_branch(deep_safety, &branch_designator) { _,
PermVarAllocation::Done {
ref mut deep_safety,
..
},
) => {
if self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
{
Target::subterm_to_value(r) Target::subterm_to_value(r)
} else { } else {
*deep_safety = VarSafetyStatus::unneeded(branch_designator); *deep_safety = VarSafetyStatus::unneeded(branch_designator);
@@ -599,7 +664,10 @@ impl DebrayAllocator {
} }
} }
VarAlloc::Temp { ref mut safety, .. } => { VarAlloc::Temp { ref mut safety, .. } => {
if self.branch_stack.safety_unneeded_in_branch(safety, &branch_designator) { if self
.branch_stack
.safety_unneeded_in_branch(safety, &branch_designator)
{
Target::subterm_to_value(r) Target::subterm_to_value(r)
} else { } else {
*safety = VarSafetyStatus::unneeded(branch_designator); *safety = VarSafetyStatus::unneeded(branch_designator);
@@ -626,7 +694,7 @@ impl Allocator for DebrayAllocator {
in_use: BitSet::default(), in_use: BitSet::default(),
temp_free_list: vec![], temp_free_list: vec![],
perm_free_list: VecDeque::new(), perm_free_list: VecDeque::new(),
branch_stack: BranchStack { stack: vec![] } branch_stack: BranchStack { stack: vec![] },
} }
} }
@@ -705,12 +773,14 @@ impl Allocator for DebrayAllocator {
} }
r @ RegType::Perm(_) => { r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation { let is_new_var = match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, allocation) => if allocation.pending() { VarAlloc::Perm(_, allocation) => {
*allocation = PermVarAllocation::done(); if allocation.pending() {
true *allocation = PermVarAllocation::done();
} else { true
false } else {
}, false
}
}
_ => unreachable!(), _ => unreachable!(),
}; };
@@ -828,7 +898,9 @@ impl Allocator for DebrayAllocator {
if !r.is_perm() && r.reg_num() == 0 { if !r.is_perm() && r.reg_num() == 0 {
self.in_use.insert(idx + 1); self.in_use.insert(idx + 1);
self.shallow_temp_mappings.insert(idx + 1, var_num); self.shallow_temp_mappings.insert(idx + 1, var_num);
self.var_data.records[var_num].allocation.set_register(idx + 1); self.var_data.records[var_num]
.allocation
.set_register(idx + 1);
} }
} }
} }

View File

@@ -24,12 +24,12 @@ use crate::atom_table::Atom;
use std::alloc::{alloc, Layout}; use std::alloc::{alloc, Layout};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::ffi::{CString, c_void};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::error::Error;
use std::ffi::{c_void, CString};
use libffi::low::{ffi_cif, types, CodePtr, ffi_abi_FFI_DEFAULT_ABI, prep_cif, ffi_type, type_tag}; use libffi::low::{ffi_abi_FFI_DEFAULT_ABI, ffi_cif, ffi_type, prep_cif, type_tag, types, CodePtr};
use libloading::{Symbol, Library}; use libloading::{Library, Symbol};
pub struct FunctionDefinition { pub struct FunctionDefinition {
pub name: String, pub name: String,
@@ -65,338 +65,393 @@ struct PointerArgs {
impl ForeignFunctionTable { impl ForeignFunctionTable {
pub fn merge(&mut self, other: ForeignFunctionTable) { pub fn merge(&mut self, other: ForeignFunctionTable) {
self.table.extend(other.table); self.table.extend(other.table);
} }
pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) { pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) {
let mut fields: Vec<_> = atom_fields.iter().map(|x| self.map_type_ffi(&x)).collect(); let mut fields: Vec<_> = atom_fields.iter().map(|x| self.map_type_ffi(&x)).collect();
fields.push(std::ptr::null_mut::<ffi_type>()); fields.push(std::ptr::null_mut::<ffi_type>());
let mut struct_type: ffi_type = Default::default(); let mut struct_type: ffi_type = Default::default();
struct_type.type_ = type_tag::STRUCT; struct_type.type_ = type_tag::STRUCT;
struct_type.elements = fields.as_mut_ptr(); struct_type.elements = fields.as_mut_ptr();
self.structs.insert(name.to_string(), StructImpl { ffi_type: struct_type, fields, atom_fields}); self.structs.insert(
name.to_string(),
StructImpl {
ffi_type: struct_type,
fields,
atom_fields,
},
);
} }
fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type { fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type {
unsafe { unsafe {
match source { match source {
atom!("sint64") => &mut types::sint64, atom!("sint64") => &mut types::sint64,
atom!("sint32") => &mut types::sint32, atom!("sint32") => &mut types::sint32,
atom!("sint16") => &mut types::sint16, atom!("sint16") => &mut types::sint16,
atom!("sint8") => &mut types::sint8, atom!("sint8") => &mut types::sint8,
atom!("uint64") => &mut types::uint64, atom!("uint64") => &mut types::uint64,
atom!("uint32") => &mut types::uint32, atom!("uint32") => &mut types::uint32,
atom!("uint16") => &mut types::uint16, atom!("uint16") => &mut types::uint16,
atom!("uint8") => &mut types::uint8, atom!("uint8") => &mut types::uint8,
atom!("bool") => &mut types::sint8, atom!("bool") => &mut types::sint8,
atom!("void") => &mut types::void, atom!("void") => &mut types::void,
atom!("cstr") => &mut types::pointer, atom!("cstr") => &mut types::pointer,
atom!("ptr") => &mut types::pointer, atom!("ptr") => &mut types::pointer,
atom!("f32") => &mut types::float, atom!("f32") => &mut types::float,
atom!("f64") => &mut types::double, atom!("f64") => &mut types::double,
struct_name => { struct_name => match self.structs.get_mut(&*struct_name.as_str()) {
match self.structs.get_mut(struct_name.as_str()) { Some(ref mut struct_type) => &mut struct_type.ffi_type,
Some(ref mut struct_type) => { None => unreachable!(),
&mut struct_type.ffi_type },
}, }
None => unreachable!() }
}
}
}
}
} }
pub(crate) fn load_library(&mut self, library_name: &str, functions: &Vec<FunctionDefinition>) -> Result<(), Box<dyn Error>> { pub(crate) fn load_library(
let mut ff_table: ForeignFunctionTable = Default::default(); &mut self,
unsafe { library_name: &str,
let library = Library::new(library_name)?; functions: &Vec<FunctionDefinition>,
for function in functions { ) -> Result<(), Box<dyn Error>> {
let symbol_name: CString = CString::new(function.name.clone())?; let mut ff_table: ForeignFunctionTable = Default::default();
let code_ptr: Symbol<*mut c_void> = library.get(&symbol_name.into_bytes_with_nul())?; unsafe {
let mut args: Vec<_> = function.args.iter().map(|x| self.map_type_ffi(&x)).collect(); let library = Library::new(library_name)?;
let mut cif: ffi_cif = Default::default(); for function in functions {
prep_cif( let symbol_name: CString = CString::new(function.name.clone())?;
&mut cif, let code_ptr: Symbol<*mut c_void> =
ffi_abi_FFI_DEFAULT_ABI, library.get(&symbol_name.into_bytes_with_nul())?;
args.len(), let mut args: Vec<_> = function
self.map_type_ffi(&function.return_value), .args
args.as_mut_ptr() .iter()
).unwrap(); .map(|x| self.map_type_ffi(&x))
.collect();
let mut cif: ffi_cif = Default::default();
prep_cif(
&mut cif,
ffi_abi_FFI_DEFAULT_ABI,
args.len(),
self.map_type_ffi(&function.return_value),
args.as_mut_ptr(),
)
.unwrap();
let return_struct_name = if (*self.map_type_ffi(&function.return_value)).type_ as u32 == libffi::raw::FFI_TYPE_STRUCT { let return_struct_name = if (*self.map_type_ffi(&function.return_value)).type_
Some(function.return_value.as_str().to_string()) as u32
} else { == libffi::raw::FFI_TYPE_STRUCT
None {
}; Some(function.return_value.as_str().to_string())
} else {
None
};
ff_table.table.insert(function.name.clone(), FunctionImpl { ff_table.table.insert(
cif, function.name.clone(),
args, FunctionImpl {
code_ptr: CodePtr(code_ptr.into_raw().into_raw() as *mut _), cif,
return_struct_name, args,
}); code_ptr: CodePtr(code_ptr.into_raw().into_raw() as *mut _),
} return_struct_name,
std::mem::forget(library); },
} );
self.merge(ff_table); }
Ok(()) std::mem::forget(library);
}
self.merge(ff_table);
Ok(())
} }
fn build_pointer_args(args: &mut Vec<Value>, type_args: &Vec<*mut ffi_type>, structs_table: &mut HashMap<String, StructImpl>) -> Result<PointerArgs, FFIError> { fn build_pointer_args(
let mut pointers = Vec::with_capacity(args.len()); args: &mut Vec<Value>,
let mut _memory = Vec::new(); type_args: &Vec<*mut ffi_type>,
for i in 0..args.len() { structs_table: &mut HashMap<String, StructImpl>,
let field_type = type_args[i]; ) -> Result<PointerArgs, FFIError> {
unsafe { let mut pointers = Vec::with_capacity(args.len());
macro_rules! push_int { let mut _memory = Vec::new();
($type:ty) => { for i in 0..args.len() {
{ let field_type = type_args[i];
let n: $type = <$type>::try_from(args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?; unsafe {
let mut box_value = Box::new(n) as Box<dyn Any>; macro_rules! push_int {
pointers.push(&mut *box_value as *mut _ as *mut c_void); ($type:ty) => {{
_memory.push(box_value); let n: $type = <$type>::try_from(args[i].as_int()?)
} .map_err(|_| FFIError::ValueDontFit)?;
} let mut box_value = Box::new(n) as Box<dyn Any>;
} pointers.push(&mut *box_value as *mut _ as *mut c_void);
_memory.push(box_value);
match (*field_type).type_ as u32 { }};
libffi::raw::FFI_TYPE_UINT8 => push_int!(u8), }
libffi::raw::FFI_TYPE_SINT8 => push_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => push_int!(u16), match (*field_type).type_ as u32 {
libffi::raw::FFI_TYPE_SINT16 => push_int!(i16), libffi::raw::FFI_TYPE_UINT8 => push_int!(u8),
libffi::raw::FFI_TYPE_UINT32 => push_int!(u32), libffi::raw::FFI_TYPE_SINT8 => push_int!(i8),
libffi::raw::FFI_TYPE_SINT32 => push_int!(i32), libffi::raw::FFI_TYPE_UINT16 => push_int!(u16),
libffi::raw::FFI_TYPE_UINT64 => push_int!(u64), libffi::raw::FFI_TYPE_SINT16 => push_int!(i16),
libffi::raw::FFI_TYPE_SINT64 => push_int!(i64), libffi::raw::FFI_TYPE_UINT32 => push_int!(u32),
libffi::raw::FFI_TYPE_FLOAT => { libffi::raw::FFI_TYPE_SINT32 => push_int!(i32),
let n: f32 = args[i].as_float()? as f32; libffi::raw::FFI_TYPE_UINT64 => push_int!(u64),
let mut box_value = Box::new(n) as Box<dyn Any>; libffi::raw::FFI_TYPE_SINT64 => push_int!(i64),
pointers.push(&mut *box_value as *mut _ as *mut c_void); libffi::raw::FFI_TYPE_FLOAT => {
_memory.push(box_value); let n: f32 = args[i].as_float()? as f32;
}, let mut box_value = Box::new(n) as Box<dyn Any>;
libffi::raw::FFI_TYPE_DOUBLE => { pointers.push(&mut *box_value as *mut _ as *mut c_void);
let n: f64 = args[i].as_float()?; _memory.push(box_value);
let mut box_value = Box::new(n) as Box<dyn Any>; }
pointers.push(&mut *box_value as *mut _ as *mut c_void); libffi::raw::FFI_TYPE_DOUBLE => {
_memory.push(box_value); let n: f64 = args[i].as_float()?;
}, let mut box_value = Box::new(n) as Box<dyn Any>;
libffi::raw::FFI_TYPE_POINTER => { pointers.push(&mut *box_value as *mut _ as *mut c_void);
let ptr: *mut c_void = args[i].as_ptr()?; _memory.push(box_value);
pointers.push(ptr); }
}, libffi::raw::FFI_TYPE_POINTER => {
libffi::raw::FFI_TYPE_STRUCT => { let ptr: *mut c_void = args[i].as_ptr()?;
let (mut ptr, _size, _align) = Self::build_struct(&mut args[i], structs_table)?; pointers.push(ptr);
pointers.push(&mut *ptr as *mut _ as *mut c_void); }
_memory.push(ptr); libffi::raw::FFI_TYPE_STRUCT => {
}, let (mut ptr, _size, _align) =
_ => return Err(FFIError::InvalidFFIType) Self::build_struct(&mut args[i], structs_table)?;
} pointers.push(&mut *ptr as *mut _ as *mut c_void);
} _memory.push(ptr);
} }
Ok(PointerArgs { _ => return Err(FFIError::InvalidFFIType),
pointers, }
_memory }
}) }
Ok(PointerArgs { pointers, _memory })
} }
fn build_struct(arg: &mut Value, structs_table: &mut HashMap<String, StructImpl>) -> Result<(Box<dyn Any>, usize, usize), FFIError> { fn build_struct(
unsafe { arg: &mut Value,
match arg { structs_table: &mut HashMap<String, StructImpl>,
Value::Struct(ref name, ref mut struct_args) => { ) -> Result<(Box<dyn Any>, usize, usize), FFIError> {
if let Some(ref mut struct_type) = structs_table.clone().get_mut(name) { unsafe {
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap(); match arg {
let align = struct_type.ffi_type.alignment as usize; Value::Struct(ref name, ref mut struct_args) => {
let size = struct_type.ffi_type.size; if let Some(ref mut struct_type) = structs_table.clone().get_mut(name) {
let ptr = alloc(layout) as *mut c_void; let layout = Layout::from_size_align(
let mut field_ptr = ptr; struct_type.ffi_type.size,
struct_type.ffi_type.alignment.into(),
)
.unwrap();
let align = struct_type.ffi_type.alignment as usize;
let size = struct_type.ffi_type.size;
let ptr = alloc(layout) as *mut c_void;
let mut field_ptr = ptr;
for i in 0..(struct_type.fields.len()-1) { for i in 0..(struct_type.fields.len() - 1) {
macro_rules! try_write_int { macro_rules! try_write_int {
($type:ty) => { ($type:ty) => {{
{ field_ptr = field_ptr
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>())); .add(field_ptr.align_offset(std::mem::align_of::<$type>()));
let n: $type = <$type>::try_from(struct_args[i].as_int()?).map_err(|_| FFIError::ValueDontFit)?; let n: $type = <$type>::try_from(struct_args[i].as_int()?)
std::ptr::write(field_ptr as *mut $type, n); .map_err(|_| FFIError::ValueDontFit)?;
field_ptr = field_ptr.add(std::mem::size_of::<$type>()); std::ptr::write(field_ptr as *mut $type, n);
} field_ptr = field_ptr.add(std::mem::size_of::<$type>());
} }};
} }
macro_rules! write { macro_rules! write {
($type:ty, $value:expr) => { ($type:ty, $value:expr) => {{
{ let data: $type = $value;
let data: $type = $value; std::ptr::write(field_ptr as *mut $type, data);
std::ptr::write(field_ptr as *mut $type, data); field_ptr = field_ptr.add(align);
field_ptr = field_ptr.add(align); }};
} }
}
}
let field = struct_type.fields[i]; let field = struct_type.fields[i];
match (*field).type_ as u32 { match (*field).type_ as u32 {
libffi::raw::FFI_TYPE_UINT8 => try_write_int!(u8), libffi::raw::FFI_TYPE_UINT8 => try_write_int!(u8),
libffi::raw::FFI_TYPE_SINT8 => try_write_int!(i8), libffi::raw::FFI_TYPE_SINT8 => try_write_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => try_write_int!(u16), libffi::raw::FFI_TYPE_UINT16 => try_write_int!(u16),
libffi::raw::FFI_TYPE_SINT16 => try_write_int!(i16), libffi::raw::FFI_TYPE_SINT16 => try_write_int!(i16),
libffi::raw::FFI_TYPE_UINT32 => try_write_int!(u32), libffi::raw::FFI_TYPE_UINT32 => try_write_int!(u32),
libffi::raw::FFI_TYPE_SINT32 => try_write_int!(i32), libffi::raw::FFI_TYPE_SINT32 => try_write_int!(i32),
libffi::raw::FFI_TYPE_UINT64 => try_write_int!(u64), libffi::raw::FFI_TYPE_UINT64 => try_write_int!(u64),
libffi::raw::FFI_TYPE_SINT64 => try_write_int!(i64), libffi::raw::FFI_TYPE_SINT64 => try_write_int!(i64),
libffi::raw::FFI_TYPE_POINTER => write!(*mut c_void, struct_args[i].as_ptr()?), libffi::raw::FFI_TYPE_POINTER => {
libffi::raw::FFI_TYPE_FLOAT => write!(f32, struct_args[i].as_float()? as f32), write!(*mut c_void, struct_args[i].as_ptr()?)
libffi::raw::FFI_TYPE_DOUBLE => write!(f64, struct_args[i].as_float()?), }
libffi::raw::FFI_TYPE_STRUCT => { libffi::raw::FFI_TYPE_FLOAT => {
let (struct_ptr, struct_size, struct_align) = Self::build_struct(&mut struct_args[i], structs_table)?; write!(f32, struct_args[i].as_float()? as f32)
field_ptr = field_ptr.add(field_ptr.align_offset(struct_align)); }
libffi::raw::FFI_TYPE_DOUBLE => {
std::ptr::copy(& *struct_ptr as *const _ as *const c_void, field_ptr as *mut c_void, struct_size); write!(f64, struct_args[i].as_float()?)
field_ptr = field_ptr.add(struct_size); }
}, libffi::raw::FFI_TYPE_STRUCT => {
_ => { let (struct_ptr, struct_size, struct_align) =
unreachable!() Self::build_struct(&mut struct_args[i], structs_table)?;
} field_ptr = field_ptr.add(field_ptr.align_offset(struct_align));
}
} std::ptr::copy(
return Ok((Box::from_raw(ptr), size, align)); &*struct_ptr as *const _ as *const c_void,
} else { field_ptr as *mut c_void,
return Err(FFIError::InvalidStructName); struct_size,
} );
} field_ptr = field_ptr.add(struct_size);
_ => return Err(FFIError::ValueCast) }
} _ => {
} unreachable!()
}
}
}
return Ok((Box::from_raw(ptr), size, align));
} else {
return Err(FFIError::InvalidStructName);
}
}
_ => return Err(FFIError::ValueCast),
}
}
} }
pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> Result<Value, FFIError> { pub fn exec(&mut self, name: &str, mut args: Vec<Value>) -> Result<Value, FFIError> {
let function_impl = self.table.get_mut(name).ok_or(FFIError::FunctionNotFound)?; let function_impl = self.table.get_mut(name).ok_or(FFIError::FunctionNotFound)?;
let mut pointer_args = Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?; let mut pointer_args =
Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
return unsafe {
macro_rules! call_and_return {
($type:ty) => {
{
let mut n: Box<u8> = Box::new(0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Int(i64::from(*n)))
}
}
}
match (*function_impl.cif.rtype).type_ as u32 {
libffi::raw::FFI_TYPE_VOID => call_and_return!(i32),
libffi::raw::FFI_TYPE_UINT8 => call_and_return!(u8),
libffi::raw::FFI_TYPE_SINT8 => call_and_return!(i8),
libffi::raw::FFI_TYPE_UINT16 => call_and_return!(u16),
libffi::raw::FFI_TYPE_SINT16 => call_and_return!(i16),
libffi::raw::FFI_TYPE_UINT32 => call_and_return!(u32),
libffi::raw::FFI_TYPE_SINT32 => call_and_return!(i32),
libffi::raw::FFI_TYPE_UINT64 => {
let mut n: Box<u64> = Box::new(0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Int(i64::try_from(*n).map_err(|_| FFIError::ValueDontFit)?))
},
libffi::raw::FFI_TYPE_SINT64 => call_and_return!(i64),
libffi::raw::FFI_TYPE_POINTER => call_and_return!(*mut c_void),
libffi::raw::FFI_TYPE_FLOAT => {
let mut n: Box<f32> = Box::new(0.0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Float((*n).into()))
},
libffi::raw::FFI_TYPE_DOUBLE => {
let mut n: Box<f64> = Box::new(0.0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void
);
Ok(Value::Float(*n))
},
libffi::raw::FFI_TYPE_STRUCT => {
let name = &function_impl.return_struct_name.clone().ok_or(FFIError::StructNotFound)?;
let struct_type = self.structs.get(name).ok_or(FFIError::StructNotFound)?;
let layout = Layout::from_size_align(struct_type.ffi_type.size, struct_type.ffi_type.alignment.into()).unwrap();
let ptr = alloc(layout) as *mut c_void;
libffi::raw::ffi_call( return unsafe {
&mut function_impl.cif, macro_rules! call_and_return {
Some(*function_impl.code_ptr.as_safe_fun()), ($type:ty) => {{
&mut *ptr as *mut _ as *mut c_void, let mut n: Box<u8> = Box::new(0);
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void libffi::raw::ffi_call(
); &mut function_impl.cif,
let struct_val = self.read_struct(ptr, name, struct_type); Some(*function_impl.code_ptr.as_safe_fun()),
drop(Box::from_raw(ptr)); &mut *n as *mut _ as *mut c_void,
struct_val pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
} );
_ => unreachable!() Ok(Value::Int(i64::from(*n)))
} }};
}; }
match (*function_impl.cif.rtype).type_ as u32 {
libffi::raw::FFI_TYPE_VOID => call_and_return!(i32),
libffi::raw::FFI_TYPE_UINT8 => call_and_return!(u8),
libffi::raw::FFI_TYPE_SINT8 => call_and_return!(i8),
libffi::raw::FFI_TYPE_UINT16 => call_and_return!(u16),
libffi::raw::FFI_TYPE_SINT16 => call_and_return!(i16),
libffi::raw::FFI_TYPE_UINT32 => call_and_return!(u32),
libffi::raw::FFI_TYPE_SINT32 => call_and_return!(i32),
libffi::raw::FFI_TYPE_UINT64 => {
let mut n: Box<u64> = Box::new(0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
);
Ok(Value::Int(
i64::try_from(*n).map_err(|_| FFIError::ValueDontFit)?,
))
}
libffi::raw::FFI_TYPE_SINT64 => call_and_return!(i64),
libffi::raw::FFI_TYPE_POINTER => call_and_return!(*mut c_void),
libffi::raw::FFI_TYPE_FLOAT => {
let mut n: Box<f32> = Box::new(0.0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
);
Ok(Value::Float((*n).into()))
}
libffi::raw::FFI_TYPE_DOUBLE => {
let mut n: Box<f64> = Box::new(0.0);
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *n as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
);
Ok(Value::Float(*n))
}
libffi::raw::FFI_TYPE_STRUCT => {
let name = &function_impl
.return_struct_name
.clone()
.ok_or(FFIError::StructNotFound)?;
let struct_type = self.structs.get(name).ok_or(FFIError::StructNotFound)?;
let layout = Layout::from_size_align(
struct_type.ffi_type.size,
struct_type.ffi_type.alignment.into(),
)
.unwrap();
let ptr = alloc(layout) as *mut c_void;
libffi::raw::ffi_call(
&mut function_impl.cif,
Some(*function_impl.code_ptr.as_safe_fun()),
&mut *ptr as *mut _ as *mut c_void,
pointer_args.pointers.as_mut_ptr() as *mut *mut c_void,
);
let struct_val = self.read_struct(ptr, name, struct_type);
drop(Box::from_raw(ptr));
struct_val
}
_ => unreachable!(),
}
};
} }
fn read_struct(&self, ptr: *mut c_void, name: &str, struct_type: &StructImpl) -> Result<Value, FFIError> { fn read_struct(
unsafe { &self,
let mut returns = Vec::new(); ptr: *mut c_void,
let mut field_ptr = ptr; name: &str,
struct_type: &StructImpl,
) -> Result<Value, FFIError> {
unsafe {
let mut returns = Vec::new();
let mut field_ptr = ptr;
for i in 0..(struct_type.fields.len()-1) { for i in 0..(struct_type.fields.len() - 1) {
let field = struct_type.fields[i]; let field = struct_type.fields[i];
macro_rules! read_and_push_int { macro_rules! read_and_push_int {
($type:ty) => { ($type:ty) => {{
{ field_ptr =
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>())); field_ptr.add(field_ptr.align_offset(std::mem::align_of::<$type>()));
let n = std::ptr::read(field_ptr as *mut $type); let n = std::ptr::read(field_ptr as *mut $type);
returns.push(Value::Int(i64::from(n))); returns.push(Value::Int(i64::from(n)));
field_ptr = field_ptr.add(std::mem::size_of::<$type>()); field_ptr = field_ptr.add(std::mem::size_of::<$type>());
} }};
} }
}
match (*field).type_ as u32 { match (*field).type_ as u32 {
libffi::raw::FFI_TYPE_UINT8 => read_and_push_int!(u8), libffi::raw::FFI_TYPE_UINT8 => read_and_push_int!(u8),
libffi::raw::FFI_TYPE_SINT8 => read_and_push_int!(i8), libffi::raw::FFI_TYPE_SINT8 => read_and_push_int!(i8),
libffi::raw::FFI_TYPE_UINT16 => read_and_push_int!(u16), libffi::raw::FFI_TYPE_UINT16 => read_and_push_int!(u16),
libffi::raw::FFI_TYPE_SINT16 => read_and_push_int!(i16), libffi::raw::FFI_TYPE_SINT16 => read_and_push_int!(i16),
libffi::raw::FFI_TYPE_UINT32 => read_and_push_int!(u32), libffi::raw::FFI_TYPE_UINT32 => read_and_push_int!(u32),
libffi::raw::FFI_TYPE_SINT32 => read_and_push_int!(i32), libffi::raw::FFI_TYPE_SINT32 => read_and_push_int!(i32),
libffi::raw::FFI_TYPE_UINT64 => { libffi::raw::FFI_TYPE_UINT64 => {
field_ptr = field_ptr.add(field_ptr.align_offset(std::mem::align_of::<u64>())); field_ptr =
let n = std::ptr::read(field_ptr as *mut u64); field_ptr.add(field_ptr.align_offset(std::mem::align_of::<u64>()));
returns.push(Value::Int(i64::try_from(n).map_err(|_| FFIError::ValueDontFit)?)); let n = std::ptr::read(field_ptr as *mut u64);
field_ptr = field_ptr.add(std::mem::size_of::<u64>()); returns.push(Value::Int(
}, i64::try_from(n).map_err(|_| FFIError::ValueDontFit)?,
libffi::raw::FFI_TYPE_SINT64 => read_and_push_int!(i64), ));
libffi::raw::FFI_TYPE_POINTER => read_and_push_int!(i64), field_ptr = field_ptr.add(std::mem::size_of::<u64>());
libffi::raw::FFI_TYPE_STRUCT => { }
let substruct = struct_type.atom_fields[i].as_str(); libffi::raw::FFI_TYPE_SINT64 => read_and_push_int!(i64),
let struct_type = self.structs.get(substruct).ok_or(FFIError::StructNotFound)?; libffi::raw::FFI_TYPE_POINTER => read_and_push_int!(i64),
field_ptr = field_ptr.add(field_ptr.align_offset(struct_type.ffi_type.alignment as usize)); libffi::raw::FFI_TYPE_STRUCT => {
let struct_val = self.read_struct(field_ptr, substruct, struct_type); let substruct = struct_type.atom_fields[i].as_str();
returns.push(struct_val?); let struct_type = self
field_ptr = field_ptr.add(struct_type.ffi_type.size); .structs
}, .get(&*substruct)
_ => { .ok_or(FFIError::StructNotFound)?;
unreachable!() field_ptr = field_ptr
} .add(field_ptr.align_offset(struct_type.ffi_type.alignment as usize));
} let struct_val = self.read_struct(field_ptr, &*substruct, struct_type);
} returns.push(struct_val?);
Ok(Value::Struct(name.into(), returns)) field_ptr = field_ptr.add(struct_type.ffi_type.size);
} }
_ => {
unreachable!()
}
}
}
Ok(Value::Struct(name.into(), returns))
}
} }
} }
@@ -410,26 +465,26 @@ pub enum Value {
impl Value { impl Value {
fn as_int(&self) -> Result<i64, FFIError> { fn as_int(&self) -> Result<i64, FFIError> {
match self { match self {
Value::Int(n) => Ok(*n), Value::Int(n) => Ok(*n),
_ => Err(FFIError::ValueCast), _ => Err(FFIError::ValueCast),
} }
} }
fn as_float(&self) -> Result<f64, FFIError> { fn as_float(&self) -> Result<f64, FFIError> {
match self { match self {
Value::Float(n) => Ok(*n), Value::Float(n) => Ok(*n),
Value::Int(n) => Ok(*n as f64), Value::Int(n) => Ok(*n as f64),
_ => Err(FFIError::ValueCast), _ => Err(FFIError::ValueCast),
} }
} }
fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> { fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> {
match self { match self {
Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void), Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void),
Value::Int(n) => Ok(*n as *mut c_void), Value::Int(n) => Ok(*n as *mut c_void),
_ => Err(FFIError::ValueCast) _ => Err(FFIError::ValueCast),
} }
} }
} }

View File

@@ -7,8 +7,8 @@ use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::parser::CompositeOpDesc;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::parser::parser::CompositeOpDesc;
use crate::types::*; use crate::types::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
@@ -58,7 +58,7 @@ impl AppendOrPrepend {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum VarComparison { pub enum VarComparison {
Indistinct, Indistinct,
Distinct Distinct,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -153,11 +153,14 @@ impl DerefMut for ChunkedTermVec {
impl ChunkedTermVec { impl ChunkedTermVec {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
Self { chunk_vec: VecDeque::new() } Self {
chunk_vec: VecDeque::new(),
}
} }
pub fn reserve_branch(&mut self, capacity: usize) { pub fn reserve_branch(&mut self, capacity: usize) {
self.chunk_vec.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); self.chunk_vec
.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
} }
pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) { pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) {
@@ -173,19 +176,22 @@ impl ChunkedTermVec {
#[inline] #[inline]
pub fn add_chunk(&mut self) { pub fn add_chunk(&mut self) {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![]))); self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
} }
pub fn push_chunk_term(&mut self, term: QueryTerm) { pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() { match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => { Some(ChunkedTerms::Branch(_)) => {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term]))); self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
} }
Some(ChunkedTerms::Chunk(chunk)) => { Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_back(term); chunk.push_back(term);
} }
None => { None => {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term]))); self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
} }
} }
} }
@@ -196,7 +202,7 @@ pub enum QueryTerm {
// register, clause type, subterms, clause call policy. // register, clause type, subterms, clause call policy.
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy), Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
Fail, Fail,
LocalCut(usize), // var_num LocalCut { var_num: usize, cut_prev: bool }, // var_num
GlobalCut(usize), // var_num GlobalCut(usize), // var_num
GetCutPoint { var_num: usize, prev_b: bool }, GetCutPoint { var_num: usize, prev_b: bool },
GetLevel(usize), // var_num GetLevel(usize), // var_num
@@ -266,11 +272,10 @@ impl ClauseInfo for Term {
fn name(&self) -> Option<Atom> { fn name(&self) -> Option<Atom> {
match self { match self {
Term::Clause(_, name, terms) => { Term::Clause(_, name, terms) => {
match name { match name {
atom!(":-") => { atom!(":-") => {
match terms.len() { match terms.len() {
1 => None, // a declaration. 1 => None, // a declaration.
2 => terms[0].name(), 2 => terms[0].name(),
_ => Some(*name), _ => Some(*name),
} }
@@ -285,7 +290,7 @@ impl ClauseInfo for Term {
fn arity(&self) -> usize { fn arity(&self) -> usize {
match self { match self {
Term::Clause(_, name, terms) => match name.as_str() { Term::Clause(_, name, terms) => match &*name.as_str() {
":-" => match terms.len() { ":-" => match terms.len() {
1 => 0, 1 => 0,
2 => terms[0].arity(), 2 => terms[0].arity(),
@@ -410,7 +415,6 @@ pub(crate) fn fixity(spec: u32) -> Fixity {
} }
} }
impl OpDecl { impl OpDecl {
#[inline] #[inline]
pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self { pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self {
@@ -477,35 +481,27 @@ pub enum AtomOrString {
impl AtomOrString { impl AtomOrString {
#[inline] #[inline]
pub fn as_atom(&self, atom_tbl: &mut AtomTable) -> Atom { pub fn as_atom(&self, atom_tbl: &AtomTable) -> Atom {
match self { match self {
&AtomOrString::Atom(atom) => { &AtomOrString::Atom(atom) => atom,
atom AtomOrString::String(string) => AtomTable::build_with(atom_tbl, &string),
}
AtomOrString::String(string) => {
atom_tbl.build_with(&string)
}
} }
} }
#[inline] #[inline]
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> AtomString<'_> {
match self { match self {
AtomOrString::Atom(atom) if atom == &atom!("[]") => "", AtomOrString::Atom(atom) if atom == &atom!("[]") => AtomString::Static(""),
AtomOrString::Atom(atom) => atom.as_str(), AtomOrString::Atom(atom) => atom.as_str(),
AtomOrString::String(string) => string.as_str(), AtomOrString::String(string) => AtomString::Static(string.as_str()),
} }
} }
#[inline] #[inline]
pub fn to_string(self) -> String { pub fn to_string(self) -> String {
match self { match self {
AtomOrString::Atom(atom) => { AtomOrString::Atom(atom) => atom.as_str().to_owned(),
atom.as_str().to_owned() AtomOrString::String(string) => string,
}
AtomOrString::String(string) => {
string
}
} }
} }
} }
@@ -561,9 +557,7 @@ pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<
} }
}) })
} }
0 => { 0 => fetch_atom_op_spec(name, None, op_dir),
fetch_atom_op_spec(name, None, op_dir)
}
_ => None, _ => None,
} }
} }
@@ -595,10 +589,7 @@ pub struct Module {
// Module's and related types are defined in forms. // Module's and related types are defined in forms.
impl Module { impl Module {
pub(crate) fn new( pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
module_decl: ModuleDecl,
listing_src: ListingSource,
) -> Self {
Module { Module {
module_decl, module_decl,
code_dir: CodeDir::with_hasher(FxBuildHasher::default()), code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
@@ -620,7 +611,7 @@ impl Module {
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()), meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()), extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::with_hasher( local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default() FxBuildHasher::default(),
), ),
listing_src: ListingSource::DynamicallyGenerated, listing_src: ListingSource::DynamicallyGenerated,
} }
@@ -923,8 +914,10 @@ impl PredicateInfo {
#[inline] #[inline]
pub(crate) fn must_retract_local_clauses(&self, is_cross_module_clause: bool) -> bool { pub(crate) fn must_retract_local_clauses(&self, is_cross_module_clause: bool) -> bool {
self.is_extensible && self.has_clauses && !self.is_discontiguous && self.is_extensible
!(self.is_multifile && is_cross_module_clause) && self.has_clauses
&& !self.is_discontiguous
&& !(self.is_multifile && is_cross_module_clause)
} }
} }
@@ -1013,19 +1006,17 @@ impl PredicateSkeleton {
&mut self, &mut self,
clause_clause_loc: usize, clause_clause_loc: usize,
) -> Option<usize> { ) -> Option<usize> {
let search_result = self.core.clause_clause_locs let search_result = self.core.clause_clause_locs.make_contiguous()
.make_contiguous()[0..self.core.clause_assert_margin] [0..self.core.clause_assert_margin]
.binary_search_by(|loc| clause_clause_loc.cmp(&loc)); .binary_search_by(|loc| clause_clause_loc.cmp(&loc));
match search_result { match search_result {
Ok(loc) => Some(loc), Ok(loc) => Some(loc),
Err(_) => { Err(_) => self.core.clause_clause_locs.make_contiguous()
self.core.clause_clause_locs [self.core.clause_assert_margin..]
.make_contiguous()[self.core.clause_assert_margin..] .binary_search_by(|loc| loc.cmp(&clause_clause_loc))
.binary_search_by(|loc| loc.cmp(&clause_clause_loc)) .map(|loc| loc + self.core.clause_assert_margin)
.map(|loc| loc + self.core.clause_assert_margin) .ok(),
.ok()
}
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{ibig, Integer, Rational};
use crate::parser::dashu::base::RemEuclid;
use crate::parser::dashu::integer::Sign;
use crate::{ use crate::{
alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char, alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char,
is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char,
@@ -18,8 +20,6 @@ use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::types::*; use crate::types::*;
use dashu::base::DivRem;
use dashu::base::DivRemEuclid;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use indexmap::IndexMap; use indexmap::IndexMap;
@@ -29,6 +29,7 @@ use std::convert::TryFrom;
use std::iter::once; use std::iter::once;
use std::net::{IpAddr, TcpListener}; use std::net::{IpAddr, TcpListener};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
/* contains the location, name, precision and Specifier of the parent op. */ /* contains the location, name, precision and Specifier of the parent op. */
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -46,7 +47,7 @@ impl DirectedOp {
} }
#[inline] #[inline]
fn is_prefix(&self )-> bool { fn is_prefix(&self) -> bool {
match self { match self {
&DirectedOp::Left(_name, cell) | &DirectedOp::Right(_name, cell) => { &DirectedOp::Left(_name, cell) | &DirectedOp::Right(_name, cell) => {
is_prefix!(cell.get_spec() as u32) is_prefix!(cell.get_spec() as u32)
@@ -74,7 +75,7 @@ fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool {
DirectedOp::Left(name, cell) => { DirectedOp::Left(name, cell) => {
let (priority, spec) = cell.get(); let (priority, spec) = cell.get();
if name.as_str() == "-" { if &*name.as_str() == "-" {
let child_assoc = child_desc.get_spec(); let child_assoc = child_desc.get_spec();
if is_prefix!(spec) && (is_postfix!(child_assoc) || is_infix!(child_assoc)) { if is_prefix!(spec) && (is_postfix!(child_assoc) || is_infix!(child_assoc)) {
return true; return true;
@@ -103,7 +104,7 @@ fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool {
} }
} }
impl<'a> StackfulPreOrderHeapIter<'a> { impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
/* /*
* descend into the subtree where the iterator is currently parked * descend into the subtree where the iterator is currently parked
* and check that the leftmost leaf is a number, with every node * and check that the leftmost leaf is a number, with every node
@@ -178,16 +179,16 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
'\u{08}' if is_quoted => "\\b".to_string(), // UTF-8 backspace '\u{08}' if is_quoted => "\\b".to_string(), // UTF-8 backspace
'\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert '\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert
'\\' if is_quoted => "\\\\".to_string(), '\\' if is_quoted => "\\\\".to_string(),
' ' | '\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' => { ' ' | '\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"'
c.to_string() | '\\' => c.to_string(),
} _ => {
_ =>
if c.is_whitespace() || c.is_control() { if c.is_whitespace() || c.is_control() {
// print all other control and whitespace characters in hex. // print all other control and whitespace characters in hex.
format!("\\x{:x}\\", c as u32) format!("\\x{:x}\\", c as u32)
} else { } else {
c.to_string() c.to_string()
} }
}
} }
} }
@@ -207,6 +208,15 @@ impl NumberFocus {
} }
} }
#[derive(Debug, Clone, Copy)]
struct CommaSeparatedCharList {
pstr: PartialString,
offset: usize,
max_depth: usize,
end_cell: HeapCellValue,
end_h: Option<usize>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum TokenOrRedirect { enum TokenOrRedirect {
Atom(Atom), Atom(Atom),
@@ -217,7 +227,8 @@ enum TokenOrRedirect {
CompositeRedirect(usize, DirectedOp), CompositeRedirect(usize, DirectedOp),
CurlyBracketRedirect(usize), CurlyBracketRedirect(usize),
FunctorRedirect(usize), FunctorRedirect(usize),
#[allow(unused)] IpAddr(IpAddr), #[allow(unused)]
IpAddr(IpAddr),
NumberFocus(usize, NumberFocus, Option<DirectedOp>), NumberFocus(usize, NumberFocus, Option<DirectedOp>),
Open, Open,
Close, Close,
@@ -231,6 +242,8 @@ enum TokenOrRedirect {
OpenList(Rc<Cell<(bool, usize)>>), OpenList(Rc<Cell<(bool, usize)>>),
CloseList(Rc<Cell<(bool, usize)>>), CloseList(Rc<Cell<(bool, usize)>>),
HeadTailSeparator, HeadTailSeparator,
StackPop,
CommaSeparatedCharList(CommaSeparatedCharList),
} }
pub(crate) fn requires_space(atom: &str, op: &str) -> bool { pub(crate) fn requires_space(atom: &str, op: &str) -> bool {
@@ -394,7 +407,7 @@ fn is_numbered_var(name: Atom, arity: usize) -> bool {
#[inline] #[inline]
fn negated_op_needs_bracketing( fn negated_op_needs_bracketing(
iter: &StackfulPreOrderHeapIter, iter: &StackfulPreOrderHeapIter<ListElider>,
op_dir: &OpDir, op_dir: &OpDir,
op: &Option<DirectedOp>, op: &Option<DirectedOp>,
) -> bool { ) -> bool {
@@ -467,8 +480,8 @@ pub fn fmt_float(mut fl: f64) -> String {
*/ */
if let Some(e_index) = fl_str.find('e') { if let Some(e_index) = fl_str.find('e') {
if !fl_str[0 .. e_index].contains('.') { if !fl_str[0..e_index].contains('.') {
return fl_str[0 .. e_index].to_string() + ".0" + &fl_str[e_index ..]; return fl_str[0..e_index].to_string() + ".0" + &fl_str[e_index..];
} }
} }
@@ -478,8 +491,8 @@ pub fn fmt_float(mut fl: f64) -> String {
#[derive(Debug)] #[derive(Debug)]
pub struct HCPrinter<'a, Outputter> { pub struct HCPrinter<'a, Outputter> {
outputter: Outputter, outputter: Outputter,
iter: StackfulPreOrderHeapIter<'a>, iter: StackfulPreOrderHeapIter<'a, ListElider>,
atom_tbl: &'a mut AtomTable, atom_tbl: Arc<AtomTable>,
op_dir: &'a OpDir, op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>, state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>, toplevel_spec: Option<DirectedOp>,
@@ -513,13 +526,10 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
]; ];
let n_clone: Integer = n.clone(); let i: usize = (&n).rem_euclid(ibig!(26)).try_into().unwrap();
let j = n / ibig!(26);
let i = n.div_rem_euclid(Integer::from(26)).1.to_f32().value() as usize; if j.is_zero() {
let j = n_clone.div_rem(Integer::from(26));
let j = <(Integer, Integer)>::from(j).0;
if j == Integer::from(0) {
CHAR_CODES[i].to_string() CHAR_CODES[i].to_string()
} else { } else {
format!("{}{}", CHAR_CODES[i], j) format!("{}{}", CHAR_CODES[i], j)
@@ -548,7 +558,7 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new( pub fn new(
heap: &'a mut Heap, heap: &'a mut Heap,
atom_tbl: &'a mut AtomTable, atom_tbl: Arc<AtomTable>,
stack: &'a mut Stack, stack: &'a mut Stack,
op_dir: &'a OpDir, op_dir: &'a OpDir,
output: Outputter, output: Outputter,
@@ -578,7 +588,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn ambiguity_check(&self, atom: &str) -> bool { fn ambiguity_check(&self, atom: &str) -> bool {
let tail = &self.outputter.as_str()[self.last_item_idx..]; let tail = &self.outputter.as_str()[self.last_item_idx..];
if !self.quoted || non_quoted_token(atom.chars()) { if atom == "," || !self.quoted || non_quoted_token(atom.chars()) {
requires_space(tail, atom) requires_space(tail, atom)
} else { } else {
requires_space(tail, "'") requires_space(tail, "'")
@@ -625,11 +635,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} else { } else {
let op = DirectedOp::Left(name, spec); let op = DirectedOp::Left(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op)); self.state_stack
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::Op(name, spec));
} }
} else { } else {
match name.as_str() { match &*name.as_str() {
"|" => { "|" => {
self.format_bar_separator_op(max_depth, name, spec); self.format_bar_separator_op(max_depth, name, spec);
return; return;
@@ -643,19 +654,40 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
} else if self.check_max_depth(&mut max_depth) { } else if self.check_max_depth(&mut max_depth) {
self.iter.pop_stack(); if is_xfy!(spec.get_spec()) {
self.iter.pop_stack(); let left_directed_op = DirectedOp::Left(name, spec);
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::CompositeRedirect(
self.state_stack.push(TokenOrRedirect::Op(name, spec)); 0,
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); left_directed_op,
));
self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::StackPop);
} else { // is_yfx!
let right_directed_op = DirectedOp::Right(name, spec);
self.state_stack.push(TokenOrRedirect::StackPop);
self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
0,
right_directed_op,
));
}
} else { } else {
let left_directed_op = DirectedOp::Left(name, spec); let left_directed_op = DirectedOp::Left(name, spec);
let right_directed_op = DirectedOp::Right(name, spec); let right_directed_op = DirectedOp::Right(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
} }
} }
} }
@@ -681,7 +713,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
for _ in 0..arity { for _ in 0..arity {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
} }
@@ -738,9 +771,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
return false; return false;
} }
self.state_stack.push(TokenOrRedirect::RightCurly); self.state_stack.push(TokenOrRedirect::RightCurly);
self.state_stack.push(TokenOrRedirect::CurlyBracketRedirect(max_depth)); self.state_stack
.push(TokenOrRedirect::CurlyBracketRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::LeftCurly); self.state_stack.push(TokenOrRedirect::LeftCurly);
true true
@@ -750,10 +783,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let h = self.iter.stack_last().unwrap(); let h = self.iter.stack_last().unwrap();
let cell = self.iter.read_cell(h); let cell = self.iter.read_cell(h);
let cell = heap_bound_store( let cell = heap_bound_store(&self.iter.heap, heap_bound_deref(&self.iter.heap, cell));
&self.iter.heap,
heap_bound_deref(&self.iter.heap, cell),
);
// 7.10.4 // 7.10.4
if let Some(var) = numbervar(&self.numbervars_offset, cell) { if let Some(var) = numbervar(&self.numbervars_offset, cell) {
@@ -831,57 +861,93 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
) )
} }
fn check_for_seen(&mut self) -> Option<HeapCellValue> { fn check_for_seen(&mut self, max_depth: &mut usize) -> Option<HeapCellValue> {
if let Some(cell) = self.iter.next() { if let Some(mut orig_cell) = self.iter.next() {
let is_cyclic = cell.get_forwarding_bit(); loop {
let is_cyclic = orig_cell.get_forwarding_bit();
let cell = heap_bound_store( let cell = heap_bound_store(self.iter.heap, heap_bound_deref(self.iter.heap, orig_cell));
self.iter.heap, let cell = unmark_cell_bits!(cell);
heap_bound_deref(self.iter.heap, cell),
);
let cell = unmark_cell_bits!(cell);
match self.var_names.get(&cell).cloned() { match self.var_names.get(&cell).cloned() {
Some(var) if cell.is_var() => { Some(var) if cell.is_var() => {
// If cell is an unbound variable and maps to // If cell is an unbound variable and maps to
// a name via heap_locs, append the name to // a name via heap_locs, append the name to
// the current output, and return None. None // the current output, and return None. None
// short-circuits handle_heap_term. // short-circuits handle_heap_term.
// self.iter.pop_stack(); // self.iter.pop_stack();
let var_str = var.borrow().to_string(); let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, { push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str); append_str!(self, &var_str);
}); });
None
}
var_opt => {
if is_cyclic && cell.is_compound(self.iter.heap) {
// self-referential variables are marked "cyclic".
match var_opt {
Some(var) => {
// If the term is bound to a named variable,
// print the variable's name to output.
let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str);
});
}
None => {
// otherwise, contract it to an ellipsis.
push_space_if_amb!(self, "...", {
append_str!(self, "...");
});
}
}
return None; return None;
} }
var_opt => {
if is_cyclic && cell.is_compound(self.iter.heap) {
// self-referential variables are marked "cyclic".
read_heap_cell!(cell,
(HeapCellValueTag::Lis, vh) => {
if self.iter.heap[vh].get_forwarding_bit() {
self.iter.pop_stack();
}
Some(cell) if self.iter.heap[vh+1].get_forwarding_bit() {
self.iter.pop_stack();
}
}
_ => {}
);
match var_opt {
Some(var) => {
// If the term is bound to a named variable,
// print the variable's name to output.
let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str);
});
}
None => {
if self.max_depth == 0 || *max_depth == 0 {
// otherwise, contract it to an ellipsis.
push_space_if_amb!(self, "...", {
append_str!(self, "...");
});
} else {
debug_assert!(cell.is_ref());
// as usual, the WAM's
// optimization of the Lis tag
// (conflating the location of
// the list and that of its
// first element) needs
// special consideration here
// lest we find ourselves in
// an infinite loop.
if cell.get_tag() == HeapCellValueTag::Lis {
*max_depth -= 1;
}
let h = cell.get_value() as usize;
self.iter.push_stack(IterStackLoc::iterable_loc(h, HeapOrStackTag::Heap));
if let Some(cell) = self.iter.next() {
orig_cell = cell;
continue;
}
}
}
}
return None;
}
return Some(cell);
}
} }
} }
} else { } else {
@@ -891,7 +957,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
fn print_impromptu_atom(&mut self, atom: Atom) { fn print_impromptu_atom(&mut self, atom: Atom) {
let result = self.print_op_addendum(atom.as_str()); let result = self.print_op_addendum(&*atom.as_str());
push_space_if_amb!(self, result.as_str(), { push_space_if_amb!(self, result.as_str(), {
append_str!(self, &result); append_str!(self, &result);
@@ -1020,7 +1086,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) { match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
Some(op_desc) => { Some(op_desc) => {
if r.is_integer() { if r.is_int() {
let output_str = format!("{}", r); let output_str = format!("{}", r);
push_space_if_amb!(self, &output_str, { push_space_if_amb!(self, &output_str, {
@@ -1050,7 +1116,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
NumberFocus::Denominator(r), NumberFocus::Denominator(r),
left_directed_op, left_directed_op,
)); ));
self.state_stack.push(TokenOrRedirect::Op(rdiv_ct, *op_desc)); self.state_stack
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Numerator(r), NumberFocus::Numerator(r),
@@ -1088,10 +1155,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
// returns true if max_depth limit is reached and ellipsis is printed. // returns true if max_depth limit is reached and ellipsis is printed.
fn print_string_as_functor(&mut self, focus: usize, max_depth: usize) -> bool { fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool {
let iter = HeapPStrIter::new(self.iter.heap, focus); let iter = HeapPStrIter::new(self.iter.heap, focus);
for (char_count, c) in iter.chars().enumerate() { for (char_count, c) in iter.chars().enumerate() {
if self.check_max_depth(max_depth) {
if char_count > 0 {
self.state_stack.push(TokenOrRedirect::Close);
}
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return true;
}
append_str!(self, "'.'"); append_str!(self, "'.'");
push_char!(self, '('); push_char!(self, '(');
@@ -1099,16 +1175,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
push_char!(self, ','); push_char!(self, ',');
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
if max_depth >= char_count + 1 {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return true;
}
} }
false false
} }
// proper strings are terminal so there's no need for max_depth to
// be a mutable ref here.
fn print_proper_string(&mut self, focus: usize, max_depth: usize) { fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
push_char!(self, '"'); push_char!(self, '"');
@@ -1157,8 +1230,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => { HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => {
self.iter.pop_stack(); self.iter.pop_stack();
} }
HeapCellValueTag::CStr => { HeapCellValueTag::CStr => {}
}
_ => { _ => {
unreachable!(); unreachable!();
} }
@@ -1197,7 +1269,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.at_cdr(","); self.at_cdr(",");
self.remove_list_children(focus.value() as usize); self.remove_list_children(focus.value() as usize);
if !self.print_string_as_functor(focus.value() as usize, max_depth) { if !self.print_string_as_functor(focus.value() as usize, &mut max_depth) {
if end_cell == empty_list_as_cell!() { if end_cell == empty_list_as_cell!() {
if !self.at_cdr("") { if !self.at_cdr("") {
append_str!(self, "[]"); append_str!(self, "[]");
@@ -1222,49 +1294,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let switch = self.close_list(switch); let switch = self.close_list(switch);
let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize); let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize);
let pstr = cell_as_string!(self.iter.heap[h]);
let pstr = pstr.as_str_from(offset.get_num() as usize); let offset = offset.get_num() as usize;
let tag = value.get_tag(); let tag = value.get_tag();
if tag == HeapCellValueTag::PStrOffset { let end_h = if tag == HeapCellValueTag::PStrOffset {
// remove the fixnum offset from the iterator stack so we don't // remove the fixnum offset from the iterator stack so we don't
// print an extraneous number. pstr offset value cells are never // print an extraneous number. pstr offset value cells are never
// used by the iterator to mark cyclic terms so the removal is safe. // used by the iterator to mark cyclic terms so the removal is safe.
self.iter.pop_stack(); self.iter.pop_stack();
} Some(end_h)
} else {
if max_depth > 0 && pstr.chars().count() + 1 >= max_depth { None
if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr { };
self.iter.pop_stack();
}
if !self.max_depth_exhausted(max_depth) {
let pstr = cell_as_string!(self.iter.heap[h]);
self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList {
pstr, offset, max_depth, end_cell, end_h,
}));
} else {
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else if end_cell != empty_list_as_cell!() {
if tag == HeapCellValueTag::PStrOffset {
self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap));
}
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
}
let state_stack_len = self.state_stack.len();
for (char_count, c) in pstr.chars().enumerate() {
if max_depth > 0 && char_count + 1 >= max_depth {
break;
}
self.state_stack.push(TokenOrRedirect::Comma);
self.state_stack.push(TokenOrRedirect::Char(c));
}
self.state_stack[state_stack_len ..].reverse();
if let Some(TokenOrRedirect::Comma) = self.state_stack.last() {
self.state_stack.pop();
} }
self.open_list(switch); self.open_list(switch);
@@ -1298,7 +1348,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
self.state_stack.push(TokenOrRedirect::CloseList(switch.clone())); self.state_stack
.push(TokenOrRedirect::CloseList(switch.clone()));
Some(switch) Some(switch)
} }
@@ -1337,7 +1388,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth+1)); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
self.open_list(switch); self.open_list(switch);
} }
@@ -1353,15 +1404,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
max_depth: usize, max_depth: usize,
) { ) {
let add_brackets = if !self.ignore_ops { let add_brackets = if !self.ignore_ops {
negated_operand || negated_operand
if let Some(ref op) = op { || if let Some(ref op) = op {
if self.numbervars && arity == 1 && name == atom!("$VAR") { if self.numbervars && arity == 1 && name == atom!("$VAR") {
!self.iter.immediate_leaf_has_property(|addr| { !self.iter.immediate_leaf_has_property(|addr| {
match Number::try_from(addr) { match Number::try_from(addr) {
Ok(Number::Integer(n)) => &*n >= &Integer::from(0), Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive,
Ok(Number::Fixnum(n)) => n.get_num() >= 0, Ok(Number::Fixnum(n)) => n.get_num() >= 0,
Ok(Number::Float(f)) => f >= OrderedFloat(0f64), Ok(Number::Float(f)) => f >= OrderedFloat(0f64),
Ok(Number::Rational(r)) => &*r >= &Integer::from(0), Ok(Number::Rational(r)) => (*r).sign() == Sign::Positive,
_ => false, _ => false,
} }
}) && needs_bracketing(op_desc, op) }) && needs_bracketing(op_desc, op)
@@ -1381,7 +1432,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
if !self.outputter.ends_with(" ") { if !self.outputter.ends_with(" ") {
let parent_op = self.parent_of_first_op let parent_op = self
.parent_of_first_op
.and_then(|(parent_op, last_item_idx)| { .and_then(|(parent_op, last_item_idx)| {
// if parent_op isn't printed to the output string // if parent_op isn't printed to the output string
// already, then it doesn't border the present op // already, then it doesn't border the present op
@@ -1395,7 +1447,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
for op in &[op, parent_op] { for op in &[op, parent_op] {
if let Some(ref op) = &op { if let Some(ref op) = &op {
if op.is_left() && (op.is_prefix() || requires_space(op.as_atom().as_str(), "(")) { if op.is_left()
&& (op.is_prefix() || requires_space(&*op.as_atom().as_str(), "("))
{
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
return; return;
} }
@@ -1490,20 +1544,68 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) {
let CommaSeparatedCharList { pstr, offset, max_depth, end_cell, end_h } = char_list;
let pstr_str = pstr.as_str_from(offset);
if let Some(c) = pstr_str.chars().next() {
let offset = offset + c.len_utf8();
if !self.max_depth_exhausted(max_depth) {
self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList {
pstr,
offset,
max_depth: max_depth.saturating_sub(1),
end_cell,
end_h,
}));
let max_depth_allows = self.max_depth == 0 || max_depth > 1;
if max_depth_allows && pstr_str.chars().skip(1).next().is_some() {
self.state_stack.push(TokenOrRedirect::Comma);
}
self.state_stack.push(TokenOrRedirect::Char(c));
} else {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
}
} else if self.max_depth_exhausted(max_depth) {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else if end_cell != empty_list_as_cell!() {
if let Some(end_h) = end_h {
self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap));
}
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
}
}
fn handle_heap_term( fn handle_heap_term(
&mut self, &mut self,
op: Option<DirectedOp>, op: Option<DirectedOp>,
is_functor_redirect: bool, is_functor_redirect: bool,
max_depth: usize, mut max_depth: usize,
) { ) {
let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op); let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op);
let addr = match self.check_for_seen(&mut max_depth) {
Some(addr) => addr,
None => return,
};
let print_struct = |printer: &mut Self, name: Atom, arity: usize| { let print_struct = |printer: &mut Self, name: Atom, arity: usize| {
if name == atom!("[]") && arity == 0 { if name == atom!("[]") && arity == 0 {
if let Some(TokenOrRedirect::CloseList(_)) = printer.state_stack.last() { match printer.state_stack.last() {
if printer.at_cdr("") { Some(TokenOrRedirect::CloseList(_) | TokenOrRedirect::ChildCloseList) => {
return; if printer.at_cdr("") {
return;
}
} }
_ => {}
} }
append_str!(printer, "[]"); append_str!(printer, "[]");
@@ -1519,7 +1621,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
max_depth, max_depth,
); );
} else { } else {
push_space_if_amb!(printer, name.as_str(), { push_space_if_amb!(printer, &*name.as_str(), {
printer.format_clause(max_depth, arity, name, None); printer.format_clause(max_depth, arity, name, None);
}); });
} }
@@ -1529,14 +1631,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if let Some(ref op) = op { if let Some(ref op) = op {
let op_is_prefix = op.is_prefix() && op.is_left(); let op_is_prefix = op.is_prefix() && op.is_left();
if op_is_prefix || printer.outputter.ends_with(&format!(" {}", op.as_atom().as_str())) { if op_is_prefix
|| printer
.outputter
.ends_with(&format!(" {}", op.as_atom().as_str()))
{
result.push(' '); result.push(' ');
} }
result.push('('); result.push('(');
} }
result += &printer.print_op_addendum(name.as_str()); result += &printer.print_op_addendum(&*name.as_str());
if op.is_some() { if op.is_some() {
result.push(')'); result.push(')');
@@ -1546,19 +1652,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
append_str!(printer, &result); append_str!(printer, &result);
}); });
} else { } else {
push_space_if_amb!(printer, name.as_str(), { push_space_if_amb!(printer, &*name.as_str(), {
printer.print_impromptu_atom(name); printer.print_impromptu_atom(name);
}); });
} }
}; };
let addr = match self.check_for_seen() { if !addr.is_var()
Some(addr) => addr, && !addr.is_compound(&self.iter.heap)
None => return, && self.max_depth_exhausted(max_depth)
}; {
if !(addr == atom_as_cell!(atom!("[]")) && self.at_cdr("")) {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
}
if !addr.is_var() && !addr.is_compound(&self.iter.heap) && self.max_depth_exhausted(max_depth) {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return; return;
} }
@@ -1567,7 +1674,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
print_struct(self, name, arity); print_struct(self, name, arity);
} }
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
let name = self.atom_tbl.build_with(&String::from(c)); let name = AtomTable::build_with(&self.atom_tbl, &String::from(c));
print_struct(self, name, 0); print_struct(self, name, 0);
} }
(HeapCellValueTag::Str, s) => { (HeapCellValueTag::Str, s) => {
@@ -1585,7 +1692,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
max_depth, max_depth,
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, &*name.as_str(), {
self.format_clause(max_depth, arity, name, None); self.format_clause(max_depth, arity, name, None);
}); });
} }
@@ -1627,9 +1734,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
self.print_stream(stream, max_depth); self.print_stream(stream, max_depth);
} }
(ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
self.print_impromptu_atom(atom!("$ossified_op_dir"));
}
(ArenaHeaderTag::Dropped, _value) => { (ArenaHeaderTag::Dropped, _value) => {
self.print_impromptu_atom(atom!("$dropped_value")); self.print_impromptu_atom(atom!("$dropped_value"));
} }
@@ -1668,7 +1772,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::BarAsOp => append_str!(self, " | "), TokenOrRedirect::BarAsOp => append_str!(self, " | "),
TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c), TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
TokenOrRedirect::Op(atom, op) => { TokenOrRedirect::Op(atom, op) => {
self.print_op(atom.as_str()); self.print_op(&*atom.as_str());
if is_prefix!(op.get_spec()) { if is_prefix!(op.get_spec()) {
self.set_parent_of_first_op(Some(DirectedOp::Left(atom, op))); self.set_parent_of_first_op(Some(DirectedOp::Left(atom, op)));
@@ -1715,6 +1819,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::Space => push_char!(self, ' '), TokenOrRedirect::Space => push_char!(self, ' '),
TokenOrRedirect::LeftCurly => push_char!(self, '{'), TokenOrRedirect::LeftCurly => push_char!(self, '{'),
TokenOrRedirect::RightCurly => push_char!(self, '}'), TokenOrRedirect::RightCurly => push_char!(self, '}'),
TokenOrRedirect::StackPop => {
self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
}
TokenOrRedirect::CommaSeparatedCharList(char_list) => {
self.print_comma_separated_char_list(char_list);
}
} }
} }
@@ -1737,16 +1848,18 @@ mod tests {
let b_atom = atom!("b"); let b_atom = atom!("b");
let c_atom = atom!("c"); let c_atom = atom!("c");
wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); wam.machine_st
.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
let output = printer.print(); let output = printer.print();
@@ -1771,11 +1884,11 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
let output = printer.print(); let output = printer.print();
@@ -1795,11 +1908,11 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
let output = printer.print(); let output = printer.print();
@@ -1808,14 +1921,16 @@ mod tests {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
printer.var_names.insert(list_loc_as_cell!(1), VarPtr::from("L")); printer
.var_names
.insert(list_loc_as_cell!(1), VarPtr::from("L"));
let output = printer.print(); let output = printer.print();
@@ -1839,7 +1954,7 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
@@ -1858,7 +1973,7 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
@@ -1875,14 +1990,16 @@ mod tests {
{ {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
printer.var_names.insert(list_loc_as_cell!(1), VarPtr::from("L")); printer
.var_names
.insert(list_loc_as_cell!(1), VarPtr::from("L"));
let output = printer.print(); let output = printer.print();
@@ -1905,11 +2022,11 @@ mod tests {
{ {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0),
); );
printer.max_depth = 5; printer.max_depth = 5;
@@ -1923,16 +2040,16 @@ mod tests {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
put_partial_string(&mut wam.machine_st.heap, "abc", &mut wam.machine_st.atom_tbl); put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
pstr_loc_as_cell!(0) pstr_loc_as_cell!(0),
); );
let output = printer.print(); let output = printer.print();
@@ -1956,7 +2073,7 @@ mod tests {
{ {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.atom_tbl, Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
@@ -2000,35 +2117,39 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
wam.op_dir.insert( wam.op_dir
(atom!("+"), Fixity::In), .insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX as u8));
OpDesc::build_with(500, YFX as u8), wam.op_dir
); .insert((atom!("*"), Fixity::In), OpDesc::build_with(400, YFX as u8));
wam.op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
assert_eq!(&wam.parse_and_print_term("[a|[] + b].").unwrap(), "[a|[]+b]"); assert_eq!(
&wam.parse_and_print_term("[a|[] + b].").unwrap(),
"[a|[]+b]"
);
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
assert_eq!(&wam.parse_and_print_term("[a|[b|c]*d].").unwrap(), "[a|[b|c]*d]"); assert_eq!(
&wam.parse_and_print_term("[a|[b|c]*d].").unwrap(),
"[a|[b|c]*d]"
);
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
wam.op_dir.insert( wam.op_dir
(atom!("fy"), Fixity::Pre), .insert((atom!("fy"), Fixity::Pre), OpDesc::build_with(9, FY as u8));
OpDesc::build_with(9, FY as u8),
wam.op_dir
.insert((atom!("yf"), Fixity::Post), OpDesc::build_with(9, YF as u8));
assert_eq!(
&wam.parse_and_print_term("(fy (fy 1)yf)yf.").unwrap(),
"(fy (fy 1)yf)yf"
); );
wam.op_dir.insert( assert_eq!(
(atom!("yf"), Fixity::Post), &wam.parse_and_print_term("fy(fy(yf(fy(1)))).").unwrap(),
OpDesc::build_with(9, YF as u8), "fy fy (fy 1)yf"
); );
assert_eq!(&wam.parse_and_print_term("(fy (fy 1)yf)yf.").unwrap(), "(fy (fy 1)yf)yf");
assert_eq!(&wam.parse_and_print_term("fy(fy(yf(fy(1)))).").unwrap(), "fy fy (fy 1)yf");
} }
} }

View File

@@ -1,54 +1,23 @@
use std::sync::{Arc, Mutex, Condvar}; use std::sync::{Arc, Mutex, Condvar};
use std::future::Future; use std::io::BufRead;
use std::pin::Pin;
use http_body_util::Full; use warp::http;
use bytes::Bytes;
use hyper::service::Service;
use hyper::{body::Incoming as IncomingBody, Request, Response};
pub struct HttpListener { pub struct HttpListener {
pub incoming: std::sync::mpsc::Receiver<HttpRequest> pub incoming: std::sync::mpsc::Receiver<HttpRequest>,
} }
#[derive(Debug)]
pub struct HttpRequest { pub struct HttpRequest {
pub request: Request<IncomingBody>, pub request_data: HttpRequestData,
pub response: HttpResponse, pub response: HttpResponse,
} }
pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<Response<Full<Bytes>>>>, Condvar)>; pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<warp::reply::Response>>, Condvar)>;
pub struct HttpService { pub struct HttpRequestData {
pub tx: std::sync::mpsc::SyncSender<HttpRequest>, pub method: http::Method,
} pub headers: http::HeaderMap,
pub path: String,
impl Service<Request<IncomingBody>> for HttpService { pub query: String,
type Response = Response<Full<Bytes>>; pub body: Box<dyn BufRead + Send>,
type Error = hyper::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn call(&mut self, req: Request<IncomingBody>) -> Self::Future {
// new connection!
// we send the Request info to Prolog
let response = Arc::new((Mutex::new(false), Mutex::new(None), Condvar::new()));
let http_request = HttpRequest { request: req, response: Arc::clone(&response) };
self.tx.send(http_request).unwrap();
// we wait for the Response info from Prolog
{
let (ready, _response, cvar) = &*response;
let mut ready = ready.lock().unwrap();
while !*ready {
ready = cvar.wait(ready).unwrap();
}
}
{
let (_, response, _) = &*response;
let response = response.lock().unwrap().take();
let res = response.expect("Data race error in HTTP Server");
Box::pin(async move {
Ok(res)
})
}
}
} }

View File

@@ -150,17 +150,20 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
vec![ vec![
IndexedChoiceInstruction::Try(external), IndexedChoiceInstruction::Try(external),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index),
].into() ]
.into()
} else { } else {
vec![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(external) IndexedChoiceInstruction::Trust(external),
].into() ]
.into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); self.indexing_code
.push(IndexingLine::IndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] { match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => {
@@ -188,7 +191,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index)); self.indexing_code
.push(IndexingLine::DynamicIndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] { match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => {
@@ -275,10 +279,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
); );
} }
None | Some(IndexingCodePtr::Fail) => { None | Some(IndexingCodePtr::Fail) => {
constants.insert( constants
overlapping_constant, .insert(overlapping_constant, IndexingCodePtr::External(index));
IndexingCodePtr::External(index),
);
} }
Some(IndexingCodePtr::DynamicExternal(o)) => { Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant( self.add_dynamic_indexed_choice_for_constant(
@@ -345,16 +347,10 @@ impl<'a> IndexingCodeMergingPtr<'a> {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&constant).cloned() { match constants.get(&constant).cloned() {
None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
constants.insert( constants.insert(constant, IndexingCodePtr::DynamicExternal(index));
constant,
IndexingCodePtr::DynamicExternal(index),
);
} }
None | Some(IndexingCodePtr::Fail) => { None | Some(IndexingCodePtr::Fail) => {
constants.insert( constants.insert(constant, IndexingCodePtr::External(index));
constant,
IndexingCodePtr::External(index),
);
} }
Some(IndexingCodePtr::DynamicExternal(o)) => { Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant(o, constant, index); self.add_dynamic_indexed_choice_for_constant(o, constant, index);
@@ -432,17 +428,20 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
vec![ vec![
IndexedChoiceInstruction::Try(external), IndexedChoiceInstruction::Try(external),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index),
].into() ]
.into()
} else { } else {
vec![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(external) IndexedChoiceInstruction::Trust(external),
].into() ]
.into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); self.indexing_code
.push(IndexingLine::IndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] { match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
@@ -470,7 +469,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index)); self.indexing_code
.push(IndexingLine::DynamicIndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] { match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
@@ -584,13 +584,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
vec![ vec![
IndexedChoiceInstruction::Try(o), IndexedChoiceInstruction::Try(o),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index),
].into() ]
.into()
} else { } else {
vec![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(o) IndexedChoiceInstruction::Trust(o),
].into() ]
.into()
}; };
self.indexing_code self.indexing_code
@@ -613,7 +615,7 @@ pub(crate) fn merge_clause_index(
target_indexing_code: &mut Vec<IndexingLine>, target_indexing_code: &mut Vec<IndexingLine>,
skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton.
retracted_clauses: &Option<Vec<ClauseIndexInfo>>, retracted_clauses: &Option<Vec<ClauseIndexInfo>>,
new_clause_loc: usize, // the absolute location of the new clause in the code vector. new_clause_loc: usize, // the absolute location of the new clause in the code vector.
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) { ) {
let opt_arg_index_key = match append_or_prepend { let opt_arg_index_key = match append_or_prepend {
@@ -636,11 +638,7 @@ pub(crate) fn merge_clause_index(
for overlapping_constant in overlapping_constants { for overlapping_constant in overlapping_constants {
merging_ptr.offset = 0; merging_ptr.offset = 0;
merging_ptr.index_overlapping_constant( merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset);
*constant,
*overlapping_constant,
offset,
);
} }
} }
OptArgIndexKey::Structure(_, index_loc, name, arity) => { OptArgIndexKey::Structure(_, index_loc, name, arity) => {
@@ -1060,19 +1058,27 @@ fn cap_choice_seq(prelude: &mut [IndexedChoiceInstruction]) {
#[inline] #[inline]
fn cap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { fn cap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) {
prelude.last_mut().map(|instr| { prelude.last_mut().map(|instr| match instr {
if let IndexedChoiceInstruction::Retry(i) = instr { IndexedChoiceInstruction::Retry(i) => {
*instr = IndexedChoiceInstruction::Trust(*i); *instr = IndexedChoiceInstruction::Trust(*i);
} }
IndexedChoiceInstruction::DefaultRetry(i) => {
*instr = IndexedChoiceInstruction::DefaultTrust(*i);
}
_ => {}
}); });
} }
#[inline] #[inline]
fn uncap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { fn uncap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) {
prelude.last_mut().map(|instr| { prelude.last_mut().map(|instr| match instr {
if let IndexedChoiceInstruction::Trust(i) = instr { IndexedChoiceInstruction::Trust(i) => {
*instr = IndexedChoiceInstruction::Retry(*i); *instr = IndexedChoiceInstruction::Retry(*i);
} }
IndexedChoiceInstruction::DefaultTrust(i) => {
*instr = IndexedChoiceInstruction::DefaultRetry(*i);
}
_ => {}
}); });
} }
@@ -1087,7 +1093,7 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
pub(crate) fn constant_key_alternatives( pub(crate) fn constant_key_alternatives(
constant: Literal, constant: Literal,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
// arena: &mut Arena, // arena: &mut Arena,
) -> Vec<Literal> { ) -> Vec<Literal> {
let mut constants = vec![]; let mut constants = vec![];
@@ -1099,7 +1105,7 @@ pub(crate) fn constant_key_alternatives(
} }
} }
Literal::Char(c) => { Literal::Char(c) => {
let atom = atom_tbl.build_with(&c.to_string()); let atom = AtomTable::build_with(&atom_tbl, &c.to_string());
constants.push(Literal::Atom(atom)); constants.push(Literal::Atom(atom));
} }
/* /*
@@ -1116,8 +1122,9 @@ pub(crate) fn constant_key_alternatives(
} }
*/ */
Literal::Integer(ref n) => { Literal::Integer(ref n) => {
if let Some(n) = n.to_isize() { let result = (&**n).try_into();
Fixnum::build_with_checked(n as i64).map(|n| { if let Ok(value) = result {
Fixnum::build_with_checked(value).map(|n| {
constants.push(Literal::Fixnum(n)); constants.push(Literal::Fixnum(n));
}).unwrap(); }).unwrap();
} }
@@ -1147,11 +1154,19 @@ pub(crate) trait Indexer {
fn new() -> Self; fn new() -> Self;
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>; fn constants(
&mut self,
) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>; fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>; fn structures(
&mut self,
) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; fn compute_index(
is_initial_index: bool,
index: usize,
non_counted_bt: bool,
) -> Self::ThirdLevelIndex;
fn second_level_index<IndexKey: Eq + Hash>( fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>, indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
@@ -1187,7 +1202,9 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> { fn constants(
&mut self,
) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
&mut self.constants &mut self.constants
} }
@@ -1197,13 +1214,21 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher> { fn structures(
&mut self,
) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
&mut self.structures &mut self.structures
} }
fn compute_index(is_initial_index: bool, index: usize) -> IndexedChoiceInstruction { fn compute_index(
is_initial_index: bool,
index: usize,
non_counted_bt: bool,
) -> IndexedChoiceInstruction {
if is_initial_index { if is_initial_index {
IndexedChoiceInstruction::Try(index + 1) IndexedChoiceInstruction::Try(index + 1)
} else if non_counted_bt {
IndexedChoiceInstruction::DefaultRetry(index + 1)
} else { } else {
IndexedChoiceInstruction::Retry(index + 1) IndexedChoiceInstruction::Retry(index + 1)
} }
@@ -1231,7 +1256,9 @@ impl Indexer for StaticCodeIndices {
} }
fn switch_on<IndexKey: Eq + Hash>( fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction, mut instr_fn: impl FnMut(
IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>,
) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>, index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr { ) -> IndexingCodePtr {
@@ -1318,7 +1345,7 @@ impl Indexer for DynamicCodeIndices {
} }
#[inline] #[inline]
fn compute_index(_: bool, index: usize) -> usize { fn compute_index(_: bool, index: usize, _: bool) -> usize {
index + 1 index + 1
} }
@@ -1331,7 +1358,9 @@ impl Indexer for DynamicCodeIndices {
for (key, code) in indices.into_iter() { for (key, code) in indices.into_iter() {
if code.len() > 1 { if code.len() > 1 {
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
prelude.push_back(IndexingLine::DynamicIndexedChoice(code.into_iter().collect())); prelude.push_back(IndexingLine::DynamicIndexedChoice(
code.into_iter().collect(),
));
} else { } else {
code.front().map(|i| { code.front().map(|i| {
index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i)); index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i));
@@ -1343,7 +1372,9 @@ impl Indexer for DynamicCodeIndices {
} }
fn switch_on<IndexKey: Eq + Hash>( fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction, mut instr_fn: impl FnMut(
IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>,
) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>, index: &mut IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr { ) -> IndexingCodePtr {
@@ -1370,7 +1401,9 @@ impl Indexer for DynamicCodeIndices {
) -> IndexingCodePtr { ) -> IndexingCodePtr {
if lists.len() > 1 { if lists.len() > 1 {
let lists = mem::replace(lists, VecDeque::new()); let lists = mem::replace(lists, VecDeque::new());
prelude.push_back(IndexingLine::DynamicIndexedChoice(lists.into_iter().collect())); prelude.push_back(IndexingLine::DynamicIndexedChoice(
lists.into_iter().collect(),
));
IndexingCodePtr::Internal(1) IndexingCodePtr::Internal(1)
} else { } else {
lists lists
@@ -1400,33 +1433,43 @@ impl Indexer for DynamicCodeIndices {
pub(crate) struct CodeOffsets<I: Indexer> { pub(crate) struct CodeOffsets<I: Indexer> {
indices: I, indices: I,
optimal_index: usize, optimal_index: usize,
non_counted_bt: bool,
} }
impl<I: Indexer> CodeOffsets<I> { impl<I: Indexer> CodeOffsets<I> {
pub(crate) fn new(indices: I, optimal_index: usize) -> Self { pub(crate) fn new(indices: I, optimal_index: usize, non_counted_bt: bool) -> Self {
CodeOffsets { CodeOffsets {
indices, indices,
optimal_index, optimal_index,
non_counted_bt,
} }
} }
fn index_list(&mut self, index: usize) { fn index_list(&mut self, index: usize) {
let is_initial_index = self.indices.lists().is_empty(); let is_initial_index = self.indices.lists().is_empty();
let index = I::compute_index(is_initial_index, index); let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
self.indices.lists().push_back(index); self.indices.lists().push_back(index);
} }
fn index_constant( fn index_constant(
&mut self, &mut self,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
constant: Literal, constant: Literal,
index: usize, index: usize,
) -> Vec<Literal> { ) -> Vec<Literal> {
let overlapping_constants = constant_key_alternatives(constant, atom_tbl); let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
let code = self.indices.constants().entry(constant).or_insert(VecDeque::new()); let code = self
.indices
.constants()
.entry(constant)
.or_insert(VecDeque::new());
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
code.push_back(I::compute_index(is_initial_index, index)); code.push_back(I::compute_index(
is_initial_index,
index,
self.non_counted_bt,
));
for constant in &overlapping_constants { for constant in &overlapping_constants {
let code = self let code = self
@@ -1436,7 +1479,7 @@ impl<I: Indexer> CodeOffsets<I> {
.or_insert(VecDeque::new()); .or_insert(VecDeque::new());
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index); let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
code.push_back(index); code.push_back(index);
} }
@@ -1454,7 +1497,11 @@ impl<I: Indexer> CodeOffsets<I> {
let code_len = code.len(); let code_len = code.len();
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
code.push_back(I::compute_index(is_initial_index, index)); code.push_back(I::compute_index(
is_initial_index,
index,
self.non_counted_bt,
));
code_len code_len
} }
@@ -1463,7 +1510,7 @@ impl<I: Indexer> CodeOffsets<I> {
optimal_arg: &Term, optimal_arg: &Term,
index: usize, index: usize,
clause_index_info: &mut ClauseIndexInfo, clause_index_info: &mut ClauseIndexInfo,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) { ) {
match optimal_arg { match optimal_arg {
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => { &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {

View File

@@ -62,9 +62,7 @@ impl<'a> TermIterState<'a> {
Term::PartialString(cell, string_buf, tail) => { Term::PartialString(cell, string_buf, tail) => {
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
} }
Term::CompleteString(cell, atom) => { Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom),
TermIterState::CompleteString(lvl, cell, *atom)
}
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()), Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
} }
} }
@@ -77,7 +75,8 @@ pub(crate) struct QueryIterator<'a> {
impl<'a> QueryIterator<'a> { impl<'a> QueryIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) { fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack.push(TermIterState::subterm_to_state(lvl, term)); self.state_stack
.push(TermIterState::subterm_to_state(lvl, term));
} }
/* /*
@@ -94,19 +93,16 @@ impl<'a> QueryIterator<'a> {
fn from_term(term: &'a Term) -> Self { fn from_term(term: &'a Term) -> Self {
let state = match term { let state = match term {
Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::AnonVar
Term::PartialString(..) | Term::CompleteString(..) => { | Term::Cons(..)
| Term::Literal(..)
| Term::PartialString(..)
| Term::CompleteString(..) => {
return QueryIterator { return QueryIterator {
state_stack: vec![], state_stack: vec![],
} }
} }
Term::Clause(r, name, terms) => TermIterState::Clause( Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
Level::Root,
0,
r,
*name,
terms,
),
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()), Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
}; };
@@ -118,18 +114,21 @@ impl<'a> QueryIterator<'a> {
fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) { fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
match term { match term {
&QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => { &QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
self.state_stack.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms)); self.state_stack
.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
} }
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
self.state_stack.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms)); self.state_stack
} .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
_ => {
} }
_ => {}
} }
} }
pub fn new(term: &'a QueryTerm) -> Self { pub fn new(term: &'a QueryTerm) -> Self {
let mut iter = QueryIterator { state_stack: vec![] }; let mut iter = QueryIterator {
state_stack: vec![],
};
iter.extend_state(Level::Root, term); iter.extend_state(Level::Root, term);
iter iter
} }
@@ -170,13 +169,15 @@ impl<'a> Iterator for QueryIterator<'a> {
} }
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {
self.state_stack.push(TermIterState::FinalCons(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(), tail);
self.push_subterm(lvl.child_level(), head); self.push_subterm(lvl.child_level(), head);
} }
TermIterState::InitialPartialString(lvl, cell, string, tail) => { TermIterState::InitialPartialString(lvl, cell, string, tail) => {
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail)); self.state_stack
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
self.push_subterm(lvl.child_level(), tail); self.push_subterm(lvl.child_level(), tail);
} }
TermIterState::FinalPartialString(lvl, cell, atom, tail) => { TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
@@ -248,11 +249,7 @@ impl<'a> FactIterator<'a> {
)] )]
} }
Term::CompleteString(cell, atom) => { Term::CompleteString(cell, atom) => {
vec![TermIterState::CompleteString( vec![TermIterState::CompleteString(Level::Root, cell, *atom)]
Level::Root,
cell,
*atom,
)]
} }
Term::Literal(cell, constant) => { Term::Literal(cell, constant) => {
vec![TermIterState::Literal(Level::Root, cell, constant)] vec![TermIterState::Literal(Level::Root, cell, constant)]
@@ -319,7 +316,10 @@ pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
QueryIterator::from_term(term) QueryIterator::from_term(term)
} }
pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: RootIterationPolicy) -> FactIterator<'a> { pub(crate) fn breadth_first_iter<'a>(
term: &'a Term,
iterable_root: RootIterationPolicy,
) -> FactIterator<'a> {
FactIterator::new(term, iterable_root) FactIterator::new(term, iterable_root)
} }
@@ -356,18 +356,14 @@ fn state_from_chunked_terms<'a>(chunk_vec: &'a VecDeque<ChunkedTerms>) -> Clause
impl<'a> ClauseIterator<'a> { impl<'a> ClauseIterator<'a> {
pub fn new(clauses: &'a ChunkedTermVec) -> Self { pub fn new(clauses: &'a ChunkedTermVec) -> Self {
match state_from_chunked_terms(&clauses.chunk_vec) { match state_from_chunked_terms(&clauses.chunk_vec) {
state @ ClauseIteratorState::RemainingBranches(..) => { state @ ClauseIteratorState::RemainingBranches(..) => Self {
Self { state_stack: vec![state],
state_stack: vec![state], remaining_chunks_on_stack: 0,
remaining_chunks_on_stack: 0, },
} state @ ClauseIteratorState::RemainingChunks(..) => Self {
} state_stack: vec![state],
state @ ClauseIteratorState::RemainingChunks(..) => { remaining_chunks_on_stack: 1,
Self { },
state_stack: vec![state],
remaining_chunks_on_stack: 1,
}
}
} }
} }
@@ -403,14 +399,16 @@ impl<'a> Iterator for ClauseIterator<'a> {
match state { match state {
ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => { ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
if focus + 1 < chunks.len() { if focus + 1 < chunks.len() {
self.state_stack.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1)); self.state_stack
.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
} else { } else {
self.remaining_chunks_on_stack -= 1; self.remaining_chunks_on_stack -= 1;
} }
match &chunks[focus] { match &chunks[focus] {
ChunkedTerms::Branch(branches) => { ChunkedTerms::Branch(branches) => {
self.state_stack.push(ClauseIteratorState::RemainingBranches(branches, 0)); self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0));
} }
ChunkedTerms::Chunk(chunk) => { ChunkedTerms::Chunk(chunk) => {
return Some(ClauseItem::Chunk(chunk)); return Some(ClauseItem::Chunk(chunk));
@@ -420,8 +418,11 @@ impl<'a> Iterator for ClauseIterator<'a> {
ClauseIteratorState::RemainingChunks(chunks, focus) => { ClauseIteratorState::RemainingChunks(chunks, focus) => {
debug_assert_eq!(chunks.len(), focus); debug_assert_eq!(chunks.len(), focus);
} }
ClauseIteratorState::RemainingBranches(branches, focus) if focus < branches.len() => { ClauseIteratorState::RemainingBranches(branches, focus)
self.state_stack.push(ClauseIteratorState::RemainingBranches(&branches, focus + 1)); if focus < branches.len() =>
{
self.state_stack
.push(ClauseIteratorState::RemainingBranches(&branches, focus + 1));
let state = state_from_chunked_terms(&branches[focus]); let state = state_from_chunked_terms(&branches[focus]);
if let ClauseIteratorState::RemainingChunks(..) = &state { if let ClauseIteratorState::RemainingChunks(..) = &state {

View File

@@ -2,6 +2,8 @@
#[macro_use] #[macro_use]
extern crate static_assertions; extern crate static_assertions;
#[cfg(test)]
#[macro_use] extern crate maplit;
#[macro_use] #[macro_use]
pub mod macros; pub mod macros;
@@ -17,13 +19,13 @@ pub mod codegen;
mod debray_allocator; mod debray_allocator;
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
mod ffi; mod ffi;
mod variable_records;
mod forms; mod forms;
mod heap_iter; mod heap_iter;
pub mod heap_print; pub mod heap_print;
#[cfg(feature = "http")] #[cfg(feature = "http")]
mod http; mod http;
mod indexing; mod indexing;
mod variable_records;
#[macro_use] #[macro_use]
pub mod instructions { pub mod instructions {
include!(concat!(env!("OUT_DIR"), "/instructions.rs")); include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
@@ -38,3 +40,18 @@ mod targets;
pub mod types; pub mod types;
use instructions::instr; use instructions::instr;
mod rcu;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn eval_code(s: &str) -> String {
use machine::mock_wam::*;
let mut wam = Machine::with_test_streams();
let bytes = wam.test_load_string(s);
String::from_utf8_lossy(&bytes).to_string()
}

View File

@@ -124,7 +124,7 @@ call(_, _, _, _, _, _, _, _, _).
% while others can be set with `set_prolog_flag/2`. % while others can be set with `set_prolog_flag/2`.
% %
% The flags that Scryer Prolog support are: % The flags that Scryer Prolog support are:
% %
% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only. % * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only.
% * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set % * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set
% to `false` since it supports unbounded integer arithmethic. Read only. % to `false` since it supports unbounded integer arithmethic. Read only.
@@ -143,6 +143,7 @@ call(_, _, _, _, _, _, _, _, _).
% enabled) and `error` which throws an exception when a cylic term is created. Read and write. % enabled) and `error` which throws an exception when a cylic term is created. Read and write.
% * `unknown`: How undefined predicates are handled when called. Possible values are `error` (the default, an error is thrown), % * `unknown`: How undefined predicates are handled when called. Possible values are `error` (the default, an error is thrown),
% `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed). % `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed).
% * `answer_write_options`: Additional write options used by the top level for writing answers.
% %
current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 1023. current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 1023.
current_prolog_flag(max_arity, 1023). current_prolog_flag(max_arity, 1023).
@@ -160,6 +161,14 @@ current_prolog_flag(Flag, OccursCheckEnabled) :-
Flag == occurs_check, Flag == occurs_check,
!, !,
'$is_sto_enabled'(OccursCheckEnabled). '$is_sto_enabled'(OccursCheckEnabled).
current_prolog_flag(occurs_check, OccursCheckEnabled) :-
'$is_sto_enabled'(OccursCheckEnabled).
current_prolog_flag(Flag, Value) :-
Flag == answer_write_options,
!,
answer_write_options(Value).
current_prolog_flag(answer_write_options, Value) :-
answer_write_options(Value).
current_prolog_flag(Flag, _) :- current_prolog_flag(Flag, _) :-
atom(Flag), atom(Flag),
throw(error(domain_error(prolog_flag, Flag), current_prolog_flag/2)). % 8.17.2.3 b throw(error(domain_error(prolog_flag, Flag), current_prolog_flag/2)). % 8.17.2.3 b
@@ -167,10 +176,15 @@ current_prolog_flag(Flag, _) :-
nonvar(Flag), nonvar(Flag),
throw(error(type_error(atom, Flag), current_prolog_flag/2)). % 8.17.2.3 a throw(error(type_error(atom, Flag), current_prolog_flag/2)). % 8.17.2.3 a
answer_write_options(Value) :-
( iso_ext:bb_get('$answer_write_options', Value) -> true
; Value = []
).
%% set_prolog_flag(Flag, Value). %% set_prolog_flag(Flag, Value).
% %
% Sets the internal value of the flag. To see the list of flags supported by Scryer Prolog, % Sets the internal value of the flag. To see the list of flags supported by Scryer Prolog,
% check `current_prolog_flag/2`. The flags that are read only will fail if you try to change their values % check `current_prolog_flag/2`. The flags that are read only will fail if you try to change their values
set_prolog_flag(Flag, Value) :- set_prolog_flag(Flag, Value) :-
(var(Flag) ; var(Value)), (var(Flag) ; var(Value)),
throw(error(instantiation_error, set_prolog_flag/2)). % 8.17.1.3 a, b throw(error(instantiation_error, set_prolog_flag/2)). % 8.17.1.3 a, b
@@ -207,14 +221,25 @@ set_prolog_flag(occurs_check, false) :-
set_prolog_flag(occurs_check, error) :- set_prolog_flag(occurs_check, error) :-
!, '$set_sto_with_error_as_unify'. !, '$set_sto_with_error_as_unify'.
set_prolog_flag(double_quotes, Value) :- set_prolog_flag(double_quotes, Value) :-
throw(error(domain_error(flag_value, double_quotes + Value), flag_domain_error(double_quotes, Value).
set_prolog_flag/2)). % 8.17.1.3 e set_prolog_flag(answer_write_options, Options) :-
!,
catch(catch(builtins:parse_write_options(Options, _, set_prolog_flag/2),
error(domain_error(_,_), _),
throw(error(type_error(_,_), _))), % convert domain error to type error ....
error(type_error(_,_), _), % ... to catch type and domain errors.
flag_domain_error(answer_write_options, Options)),
iso_ext:bb_put('$answer_write_options', Options).
set_prolog_flag(Flag, _) :- set_prolog_flag(Flag, _) :-
atom(Flag), atom(Flag),
throw(error(domain_error(prolog_flag, Flag), set_prolog_flag/2)). % 8.17.1.3 d throw(error(domain_error(prolog_flag, Flag), set_prolog_flag/2)). % 8.17.1.3 d
set_prolog_flag(Flag, _) :- set_prolog_flag(Flag, _) :-
throw(error(type_error(atom, Flag), set_prolog_flag/2)). % 8.17.1.3 c throw(error(type_error(atom, Flag), set_prolog_flag/2)). % 8.17.1.3 c
flag_domain_error(Flag, Value) :-
% domain error via 8.17.1.3 e: Value is inappropriate for Flag
throw(error(domain_error(flag_value, Flag + Value), set_prolog_flag/2)).
% control operators. % control operators.
%% fail. %% fail.
@@ -262,6 +287,9 @@ repeat :- repeat.
%% ->(G1, G2) %% ->(G1, G2)
% %
% If-then and if-then-else constructs % If-then and if-then-else constructs
:- non_counted_backtracking (->)/2.
G1 -> G2 :- control_entry_point((G1 -> G2)). G1 -> G2 :- control_entry_point((G1 -> G2)).
@@ -275,6 +303,9 @@ staggered_if_then(G1, G2) :-
%% ;(G1, G2) %% ;(G1, G2)
% %
% Disjunction (or) % Disjunction (or)
:- non_counted_backtracking (;)/2.
G1 ; G2 :- control_entry_point((G1 ; G2)). G1 ; G2 :- control_entry_point((G1 ; G2)).
@@ -297,6 +328,9 @@ staggered_sc(_, G) :- call(G).
% to reason about the programs. Also restricts the ability to run the program with alternative execution strategies % to reason about the programs. Also restricts the ability to run the program with alternative execution strategies
!. !.
:- non_counted_backtracking get_cp/1.
get_cp(B) :- '$get_cp'(B).
:- non_counted_backtracking set_cp/1. :- non_counted_backtracking set_cp/1.
set_cp(B) :- '$set_cp'(B). set_cp(B) :- '$set_cp'(B).
@@ -304,6 +338,9 @@ set_cp(B) :- '$set_cp'(B).
%% ,(G1, G2) %% ,(G1, G2)
% %
% Conjuction (and) % Conjuction (and)
:- non_counted_backtracking (',')/2.
','(G1, G2) :- control_entry_point((G1, G2)). ','(G1, G2) :- control_entry_point((G1, G2)).
@@ -325,24 +362,21 @@ cont_list_goal(Conts, '$call'(builtins:dispatch_call_list(Conts))).
:- non_counted_backtracking dispatch_prep/3. :- non_counted_backtracking dispatch_prep/3.
dispatch_prep(Gs, B, [Cont|Conts]) :- dispatch_prep(Gs, B, Conts) :-
( callable(Gs) -> ( callable(Gs) ->
strip_module(Gs, M, Gs0), strip_module(Gs, M, Gs0),
( nonvar(Gs0), ( nonvar(Gs0),
dispatch_prep_(Gs0, B, [Cont|Conts]) -> dispatch_prep_(Gs0, B, Conts) ->
true true
; Gs0 == ! -> ; Gs0 == ! ->
Cont = '$call'(builtins:set_cp(B)), Conts = ['$call'(builtins:set_cp(B))]
Conts = []
; nonvar(Gs0), ; nonvar(Gs0),
\+ callable(Gs0) -> \+ callable(Gs0) ->
throw(dispatch_prep_error) throw(dispatch_prep_error)
; Cont = Gs, ; Conts = [Gs]
Conts = []
) )
; var(Gs) -> ; var(Gs) ->
Cont = Gs, Conts = [Gs]
Conts = []
; throw(dispatch_prep_error) ; throw(dispatch_prep_error)
). ).
@@ -353,20 +387,32 @@ dispatch_prep_((G1, G2), B, [Cont|Conts]) :-
dispatch_prep(G1, B, IConts1), dispatch_prep(G1, B, IConts1),
cont_list_goal(IConts1, Cont), cont_list_goal(IConts1, Cont),
dispatch_prep(G2, B, Conts). dispatch_prep(G2, B, Conts).
dispatch_prep_((G1 ; G2), B, [Cont|Conts]) :- dispatch_prep_((G1 ; G2), B, Conts) :-
dispatch_prep(G1, B, IConts0), ( nonvar(G1) ->
( G1 = (G11 -> G12) ->
dispatch_prep(G11, B, IConts2),
dispatch_prep(G12, B, IConts3),
cont_list_goal(IConts2, Cont2),
cont_list_goal(IConts3, Cont3),
Cont0 = '$call'(builtins:staggered_if_then(Cont2, Cont3))
; dispatch_prep(G1, B, IConts0),
dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0)
)
; dispatch_prep(G1, B1, IConts0),
cont_list_goal(IConts0, Cont0)
),
dispatch_prep(G2, B, IConts1), dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0), cont_list_goal(IConts0, Cont0),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
Cont = '$call'(builtins:staggered_sc(Cont0, Cont1)), Conts = ['$call'(builtins:staggered_sc(Cont0, Cont1))].
Conts = []. dispatch_prep_((G1 -> G2), B, Conts) :-
dispatch_prep_((G1 -> G2), B, [Cont|Conts]) :- dispatch_prep(G1, B1, IConts1),
dispatch_prep(G1, B, IConts1),
dispatch_prep(G2, B, IConts2), dispatch_prep(G2, B, IConts2),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
cont_list_goal(IConts2, Cont2), cont_list_goal(IConts2, Cont2),
Cont = '$call'(builtins:staggered_if_then(Cont1, Cont2)), Conts = ['$call'(builtins:get_cp(B1)),
Conts = []. '$call'(builtins:staggered_if_then(Cont1, Cont2))].
:- non_counted_backtracking dispatch_call_list/1. :- non_counted_backtracking dispatch_call_list/1.
@@ -540,26 +586,30 @@ parse_write_options(Options, OptionValues, Stub) :-
parse_write_options_(double_quotes(DoubleQuotes), double_quotes-DoubleQuotes) :- parse_write_options_(double_quotes(DoubleQuotes), double_quotes-DoubleQuotes) :-
( nonvar(DoubleQuotes), ( var(DoubleQuotes) ->
lists:member(DoubleQuotes, [true, false]), throw(error(instantiation_error, _))
; lists:member(DoubleQuotes, [true, false]),
! !
; throw(error(domain_error(write_option, double_quotes(DoubleQuotes)), _)) ; throw(error(domain_error(write_option, double_quotes(DoubleQuotes)), _))
). ).
parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :- parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :-
( nonvar(IgnoreOps), ( var(IgnoreOps) ->
lists:member(IgnoreOps, [true, false]), throw(error(instantiation_error, _))
; lists:member(IgnoreOps, [true, false]),
! !
; throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _)) ; throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _))
). ).
parse_write_options_(quoted(Quoted), quoted-Quoted) :- parse_write_options_(quoted(Quoted), quoted-Quoted) :-
( nonvar(Quoted), ( var(Quoted) ->
lists:member(Quoted, [true, false]), throw(error(instantiation_error, _))
; lists:member(Quoted, [true, false]),
! !
; throw(error(domain_error(write_option, quoted(Quoted)), _)) ; throw(error(domain_error(write_option, quoted(Quoted)), _))
). ).
parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :- parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :-
( nonvar(NumberVars), ( var(NumberVars) ->
lists:member(NumberVars, [true, false]), throw(error(instantiation_error, _))
; lists:member(NumberVars, [true, false]),
! !
; throw(error(domain_error(write_option, numbervars(NumberVars)), _)) ; throw(error(domain_error(write_option, numbervars(NumberVars)), _))
). ).
@@ -567,7 +617,9 @@ parse_write_options_(variable_names(VNNames), variable_names-VNNames) :-
must_be_var_names_list(VNNames), must_be_var_names_list(VNNames),
!. !.
parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :- parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
( integer(MaxDepth), ( var(MaxDepth) ->
throw(error(instantiation_error, _))
; integer(MaxDepth),
MaxDepth >= 0, MaxDepth >= 0,
! !
; throw(error(domain_error(write_option, max_depth(MaxDepth)), _)) ; throw(error(domain_error(write_option, max_depth(MaxDepth)), _))
@@ -681,30 +733,9 @@ parse_read_term_options(Options, OptionValues, Stub) :-
parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub). parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub).
parse_read_term_options_(singletons(Vars), singletons-Vars) :- parse_read_term_options_(singletons(Vars), singletons-Vars) :- !.
( ( var(Vars) parse_read_term_options_(variables(Vars), variables-Vars) :- !.
; '$skip_max_list'(_, _, Vars, Rs), parse_read_term_options_(variable_names(Vars), variable_names-Vars) :- !.
Rs == []
) ->
!
; throw(error(domain_error(read_option, singletons(Vars)), read_term/2))
).
parse_read_term_options_(variables(Vars), variables-Vars) :-
( ( var(Vars)
; '$skip_max_list'(_, _, Vars, Rs),
Rs == []
) ->
!
; throw(error(domain_error(read_option, variables(Vars)), read_term/2))
).
parse_read_term_options_(variable_names(Vars), variable_names-Vars) :-
( ( var(Vars)
; '$skip_max_list'(_, _, Vars, Rs),
Rs == []
) ->
!
; throw(error(domain_error(read_option, variable_names(Vars)), read_term/2))
).
parse_read_term_options_(E,_) :- parse_read_term_options_(E,_) :-
throw(error(domain_error(read_option, E), _)). throw(error(domain_error(read_option, E), _)).
@@ -714,7 +745,7 @@ parse_read_term_options_(E,_) :-
% Read Term from the stream Stream. It supports several options: % Read Term from the stream Stream. It supports several options:
% * `variables(-Vars)` unifies Vars with a list of variables in the term. Similar to do `term_variables/2` with the new term. % * `variables(-Vars)` unifies Vars with a list of variables in the term. Similar to do `term_variables/2` with the new term.
% * `variable_names(-Vars)` unifies Vars with a list `Name=Var` with Name describing the variable name and Var the variable itself that appears in Term. % * `variable_names(-Vars)` unifies Vars with a list `Name=Var` with Name describing the variable name and Var the variable itself that appears in Term.
% * `singletons` similar to `variable_names` but only reports variables occurring only once in Term. % * `singletons` similar to `variable_names` but only reports variables occurring only once in Term.
read_term(Stream, Term, Options) :- read_term(Stream, Term, Options) :-
parse_read_term_options(Options, [Singletons, VariableNames, Variables], read_term/3), parse_read_term_options(Options, [Singletons, VariableNames, Variables], read_term/3),
'$read_term'(Stream, Term, Singletons, Variables, VariableNames). '$read_term'(Stream, Term, Singletons, Variables, VariableNames).
@@ -788,7 +819,7 @@ catch(G,C,R) :-
catch(G,C,R,Bb) :- catch(G,C,R,Bb) :-
'$install_new_block'(NBb), '$install_new_block'(NBb),
'$call_with_inference_counting'(call(G)), call(G),
end_block(Bb, NBb). end_block(Bb, NBb).
catch(G,C,R,Bb) :- catch(G,C,R,Bb) :-
'$reset_block'(Bb), '$reset_block'(Bb),
@@ -1342,11 +1373,6 @@ current_predicate(Pred) :-
; throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) ; throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
). ).
'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
'$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
can_be_op_priority(Priority) :- var(Priority). can_be_op_priority(Priority) :- var(Priority).
can_be_op_priority(Priority) :- op_priority(Priority). can_be_op_priority(Priority) :- op_priority(Priority).
@@ -1362,8 +1388,8 @@ current_op(Priority, Spec, Op) :-
( can_be_op_priority(Priority), ( can_be_op_priority(Priority),
can_be_op_specifier(Spec), can_be_op_specifier(Spec),
error:can_be(atom, Op) -> error:can_be(atom, Op) ->
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op), '$get_next_op_db_ref'(Priority, Spec, Op, ListOfOps),
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) lists:member(op(Priority, Spec, Op), ListOfOps)
). ).
list_of_op_atoms(Var) :- list_of_op_atoms(Var) :-
@@ -1587,7 +1613,7 @@ atom_concat(Atom_1, Atom_2, Atom_12) :-
%% sub_atom(+Atom, ?Before, ?Length, ?After, ?SubAtom). %% sub_atom(+Atom, ?Before, ?Length, ?After, ?SubAtom).
% %
% Relates an atom to a subatom inside with some key properties: % Relates an atom to a subatom inside with some key properties:
% %
% * SubAtom starts at Before characters (0-based) from Atom % * SubAtom starts at Before characters (0-based) from Atom
% * SubAtom has Length characters % * SubAtom has Length characters
% * After SubAtom there are After characters in Atom % * After SubAtom there are After characters in Atom
@@ -2186,6 +2212,9 @@ set_stream_position(S_or_a, Position) :-
%% callable(X). %% callable(X).
% %
% True iff X is bound o an atom or a compund term. % True iff X is bound o an atom or a compund term.
:- non_counted_backtracking callable/1.
callable(X) :- callable(X) :-
( nonvar(X), functor(X, F, _), atom(F) -> ( nonvar(X), functor(X, F, _), atom(F) ->
true true
@@ -2209,4 +2238,7 @@ nl(Stream) :-
% %
% Throws an exception of the following structure: `error(ErrorTerm, ImpDef)`. % Throws an exception of the following structure: `error(ErrorTerm, ImpDef)`.
error(Error_term, Imp_def) :- error(Error_term, Imp_def) :-
throw(error(Error_term, Imp_def)). ( var(Error_term) ->
throw(error(instantiation_error, error/2))
; throw(error(Error_term, Imp_def))
).

View File

@@ -105,8 +105,8 @@ extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :-
% - `symbolic_control` % - `symbolic_control`
% - `symbolic_hexadecimal` % - `symbolic_hexadecimal`
% - `upper` % - `upper`
% - `to_lower(Lower)` % - `lower(Lower)`
% - `to_upper(Upper)` % - `upper(Upper)`
% - `whitespace` % - `whitespace`
% %
% An example: % An example:
@@ -124,8 +124,8 @@ extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :-
% ; Type = octet % ; Type = octet
% ; Type = prolog % ; Type = prolog
% ; Type = symbolic_control % ; Type = symbolic_control
% ; Type = to_lower("a") % ; Type = lower("a")
% ; Type = to_upper("A") % ; Type = upper("A")
% ; false. % ; false.
% ``` % ```
% %
@@ -168,8 +168,8 @@ ctype(sign).
ctype(solo). ctype(solo).
ctype(symbolic_control). ctype(symbolic_control).
ctype(symbolic_hexadecimal). ctype(symbolic_hexadecimal).
ctype(to_lower(_)). ctype(lower(_)).
ctype(to_upper(_)). ctype(upper(_)).
ctype(upper). ctype(upper).
ctype(whitespace). ctype(whitespace).

View File

@@ -1,10 +1,29 @@
/* CLP(B): Constraint Logic Programming over Boolean Variables /* CLP(B): Constraint Logic Programming over Boolean Variables
Copyright (C): 2019-2023 Markus Triska Author: Markus Triska
All rights reserved.
E-mail: triska@metalevel.at E-mail: triska@metalevel.at
WWW: http://www.metalevel.at WWW: https://www.metalevel.at
Copyright (C): 2019-2023 Markus Triska
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/ */
@@ -17,8 +36,8 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(clpb, [op(300, fy, ~), :- module(clpb, [op(300, fy, ~),
op(500, yfx, #), op(500, yfx, #),
sat/1, sat/1,
taut/2, taut/2,
labeling/1, labeling/1,
sat_count/2, sat_count/2,
@@ -91,6 +110,46 @@ domain_error(Expectation, Term) :-
type_error(Expectation, Term) :- type_error(Expectation, Term) :-
type_error(Expectation, Term, unknown(Term)-1). type_error(Expectation, Term, unknown(Term)-1).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Compatibility predicates.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- meta_predicate(include(1, ?, ?)).
include(_, [], []).
include(Goal, [L|Ls0], Ls) :-
( call(Goal, L) ->
Ls = [L|Rest]
; Ls = Rest
),
include(Goal, Ls0, Rest).
:- meta_predicate(exclude(1, ?, ?)).
exclude(_, [], []).
exclude(Goal, [L|Ls0], Ls) :-
( call(Goal, L) ->
Ls = Rest
; Ls = [L|Rest]
),
exclude(Goal, Ls0, Rest).
:- meta_predicate(partition(2,?,?,?,?)).
partition(_, [], [], [], []).
partition(Pred, [H|T], L, E, G) :-
call(Pred, H, Diff),
partition_(Diff, H, Pred, T, L, E, G).
partition_(<, H, Pred, T, [H|Rest], E, G) :-
partition(Pred, T, Rest, E, G).
partition_(=, H, Pred, T, L, [H|Rest], G) :-
partition(Pred, T, L, Rest, G).
partition_(>, H, Pred, T, L, E, [H|Rest]) :-
partition(Pred, T, L, E, Rest).
:- meta_predicate(partition(1,?,?,?)).
partition(Pred, Ls0, As, Bs) :- partition(Pred, Ls0, As, Bs) :-
include(Pred, Ls0, As), include(Pred, Ls0, As),
exclude(Pred, Ls0, Bs). exclude(Pred, Ls0, Bs).
@@ -447,6 +506,10 @@ non_monotonic(X) :-
; true ; true
). ).
:- meta_predicate(bdd_nodes(1, ?, ?)).
:- meta_predicate(bdd_nodes_(1, ?, ?, ?)).
:- meta_predicate(with_aux(1, ?)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Rewriting to canonical expressions. Rewriting to canonical expressions.
Atoms are converted to variables with a special attribute. Atoms are converted to variables with a special attribute.
@@ -1513,8 +1576,7 @@ random_bindings(VNum, Node) -->
% %
% ``` % ```
% ?- sat(A#B), weighted_maximum([1,2,1], [A,B,C], Maximum). % ?- sat(A#B), weighted_maximum([1,2,1], [A,B,C], Maximum).
% A = 0, B = 1, C = 1, Maximum = 3 % A = 0, B = 1, C = 1, Maximum = 3.
% ; false.
% ``` % ```
weighted_maximum(Ws, Vars, Max) :- weighted_maximum(Ws, Vars, Max) :-
@@ -1635,8 +1697,7 @@ attribute_goals(Var) -->
{ bdd_nodes(BDD, Nodes), { bdd_nodes(BDD, Nodes),
phrase(nodes(Nodes), Ns) }, phrase(nodes(Nodes), Ns) },
[clpb:'$clpb_bdd'(Ns)] [clpb:'$clpb_bdd'(Ns)]
; { prepare_global_variables(BDD), ; { phrase(sat_ands(Formula), Ands0),
phrase(sat_ands(Formula), Ands0),
ands_fusion(Ands0, Ands), ands_fusion(Ands0, Ands),
maplist(formula_anf, Ands, ANFs0), maplist(formula_anf, Ands, ANFs0),
sort(ANFs0, ANFs1), sort(ANFs0, ANFs1),
@@ -1656,6 +1717,10 @@ attribute_goals(Var) -->
booleans(RestVs) booleans(RestVs)
; boolean(Var) % the variable may have occurred only in taut/2 ; boolean(Var) % the variable may have occurred only in taut/2
). ).
attribute_goals(Var) -->
{ get_atts(Var, clpb_max(_)),
!,
put_atts(Var, -clpb_max(_)) }.
attribute_goals(Var) --> attribute_goals(Var) -->
{ get_atts(Var, clpb_bdd(BDD)), { get_atts(Var, clpb_bdd(BDD)),
ground(BDD), ground(BDD),
@@ -1663,36 +1728,13 @@ attribute_goals(Var) -->
del_clpb(Var) :- del_clpb(Var) :-
del_attr(Var, clpb), del_attr(Var, clpb),
del_attr(Var, clpb_hash). del_attr(Var, clpb_hash),
del_attr(Var, clpb_atom).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
To make residual projection work with recorded constraints, the
global counters must be adjusted so that new variables and nodes
also get new IDs. Also, clpb_next_id/2 is used to actually create
these counters, because creating them with b_setval/2 would make
them [] on backtracking, which is quite unfortunate in itself.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
b_setval(K, T) :- bb_b_put(K, T). b_setval(K, T) :- bb_b_put(K, T).
nb_setval(K, T) :- bb_put(K, T). nb_setval(K, T) :- bb_put(K, T).
b_getval(K, T) :- bb_get(K, T). b_getval(K, T) :- bb_get(K, T).
prepare_global_variables(BDD) :-
clpb_next_id('$clpb_next_var', V0),
clpb_next_id('$clpb_next_node', N0),
bdd_nodes(BDD, Nodes),
foldl(max_variable_node, Nodes, V0-N0, MaxV0-MaxN0),
MaxV is MaxV0 + 1,
MaxN is MaxN0 + 1,
b_setval('$clpb_next_var', MaxV),
b_setval('$clpb_next_node', MaxN).
max_variable_node(Node, V0-N0, V-N) :-
node_id(Node, N1),
node_varindex(Node, V1),
N is max(N0,N1),
V is max(V0,V1).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Fuse formulas that share the same variables into single conjunctions. Fuse formulas that share the same variables into single conjunctions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -1817,7 +1859,8 @@ booleans([B|Bs]) --> boolean(B), booleans(Bs).
boolean(Var) --> boolean(Var) -->
{ del_clpb(Var) }, { del_clpb(Var) },
( { get_attr(Var, clpb_omit_boolean, true) } -> [] ( { get_attr(Var, clpb_omit_boolean, true) } ->
{ put_atts(Var, -clpb_omit_boolean(_)) }
; [clpb:sat(Var =:= Var)] ; [clpb:sat(Var =:= Var)]
). ).
@@ -1919,49 +1962,3 @@ clpb_atom_var(Atom, Var) :-
put_assoc(Atom, A0, Var, A), put_assoc(Atom, A0, Var, A),
b_setval('$clpb_atoms', A) b_setval('$clpb_atoms', A)
). ).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Compatibility predicates.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
include(Goal, List, Is) :-
include_(List, Goal, Is).
include_([], _, []).
include_([X1|Xs1], P, Is) :-
( call(P, X1)
-> Is = [X1|Is1]
; Is = Is1
),
include_(Xs1, P, Is1).
exclude(Goal, List, Is) :-
exclude_(List, Goal, Is).
exclude_([], _, []).
exclude_([X1|Xs1], P, Is) :-
( call(P, X1)
-> Is = Is1
; Is = [X1|Is1]
),
exclude_(Xs1, P, Is1).
partition(Pred, List, Less, Equal, Greater) :-
partition_(List, Pred, Less, Equal, Greater).
partition_([], _, [], [], []).
partition_([H|T], Pred, L, E, G) :-
call(Pred, H, Diff),
partition_(Diff, H, Pred, T, L, E, G).
partition_(<, H, Pred, T, [H|Rest], E, G) :-
partition_(T, Pred, Rest, E, G).
partition_(=, H, Pred, T, L, [H|Rest], G) :-
partition_(T, Pred, L, Rest, G).
partition_(>, H, Pred, T, L, E, [H|Rest]) :-
partition_(T, Pred, L, E, Rest).

View File

@@ -1030,8 +1030,8 @@ term_expansion(Term0, Term) :-
once(duodcg_body(Body0, Body, As0, As, Bs0, Bs)). once(duodcg_body(Body0, Body, As0, As, Bs0, Bs)).
duodcg_body([], (As0=As,Bs0=Bs), As0, As, Bs0, Bs). duodcg_body([], (As0=As,Bs0=Bs), As0, As, Bs0, Bs).
duodcg_body(Xs+Ys, (phrase(list(Xs), As0, As), duodcg_body(Xs+Ys, (phrase(seq(Xs), As0, As),
phrase(list(Ys), Bs0, Bs)), As0, As, Bs0, Bs). phrase(seq(Ys), Bs0, Bs)), As0, As, Bs0, Bs).
duodcg_body({Goal}, call(Goal), As, As, Bs, Bs). duodcg_body({Goal}, call(Goal), As, As, Bs, Bs).
duodcg_body((A0,B0), (A,B), As0, As, Bs0, Bs) :- duodcg_body((A0,B0), (A,B), As0, As, Bs0, Bs) :-
duodcg_body(A0, A, As0, As1, Bs0, Bs1), duodcg_body(A0, A, As0, As1, Bs0, Bs1),
@@ -1957,7 +1957,6 @@ choice_order_variable(step, Order, Var, Vars, Vars0, Selection, Consistency) :-
( Var = Next, ( Var = Next,
label(Vars, Selection, Order, step, Consistency) label(Vars, Selection, Order, step, Consistency)
; neq_num(Var, Next), ; neq_num(Var, Next),
do_queue,
label(Vars0, Selection, Order, step, Consistency) label(Vars0, Selection, Order, step, Consistency)
). ).
choice_order_variable(enum, Order, Var, Vars, _, Selection, Consistency) :- choice_order_variable(enum, Order, Var, Vars, _, Selection, Consistency) :-
@@ -2142,16 +2141,17 @@ fds_sespsize([V|Vs], S0, S) :-
fds_sespsize(Vs, S2, S). fds_sespsize(Vs, S2, S).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Optimisation uses destructive assignment to save the computed Optimisation uses the clause database to save the computed extremum
extremum over backtracking. Failure is used to get rid of copies of over backtracking. Failure is used to get rid of copies of
attributed variables that are created in intermediate steps. At attributed variables that are created in intermediate steps.
least that's the intention - it currently doesn't work in SWI:
%?- X in 0..3, call_residue_vars(labeling([min(X)], [X]), Vs). Example:
%@ X = 0,
%@ Vs = [_G6174, _G6177],
%@ _G6174 in 0..3
?- X in 1..3, call_residue_vars(labeling([min(X)], [X]), Vs).
%@ X = 1, Vs = []
%@ ; X = 2, Vs = []
%@ ; X = 3, Vs = []
%@ ; false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- dynamic(extremum/1). :- dynamic(extremum/1).
@@ -2565,13 +2565,13 @@ parse_clpz(E, R,
g(power_var_num(E, V, N)) => [p(pexp(V, N, R))], g(power_var_num(E, V, N)) => [p(pexp(V, N, R))],
m(A*B) => [p(ptimes(A, B, R))], m(A*B) => [p(ptimes(A, B, R))],
m(A-B) => [p(pplus(R,B,A))], m(A-B) => [p(pplus(R,B,A))],
m(-A) => [p(ptimes(-1,A,R))], m(-A) => [p(pplus(A,R,0))],
m(max(A,B)) => [g(A #=< #R), g(B #=< R), p(pmax(A, B, R))], m(max(A,B)) => [g(A #=< #R), g(B #=< R), p(pmax(A, B, R))],
m(min(A,B)) => [g(A #>= #R), g(B #>= R), p(pmin(A, B, R))], m(min(A,B)) => [g(A #>= #R), g(B #>= R), p(pmin(A, B, R))],
m(A mod B) => [g(B #\= 0), p(pmod(A, B, R))], m(A mod B) => [g(B #\= 0), p(pmod(A, B, R))],
m(A rem B) => [g(B #\= 0), p(prem(A, B, R))], m(A rem B) => [g(B #\= 0), p(prem(A, B, R))],
m(abs(A)) => [g(#R #>= 0), p(pabs(A, R))], m(abs(A)) => [g(#R #>= 0), p(pabs(A, R))],
m(A/B) => [g(B #\= 0), p(prdiv(A, B, R))], m(A/B) => [g(B #\= 0), p(ptimes(R, B, A))],
m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))], m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))],
m(A div B) => [g(#R #= (A - (A mod B)) // B)], m(A div B) => [g(#R #= (A - (A mod B)) // B)],
m(A^B) => [p(pexp(A, B, R))], m(A^B) => [p(pexp(A, B, R))],
@@ -2635,14 +2635,37 @@ parse_goals([]) --> [].
parse_goals([G|Gs]) --> parse_goal(G), parse_goals(Gs). parse_goals([G|Gs]) --> parse_goal(G), parse_goals(Gs).
parse_goal(g(Goal)) --> [Goal]. parse_goal(g(Goal)) --> [Goal].
parse_goal(p(Prop)) --> parse_goal(p(Prop0)) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P), [make_propagator(Prop, P),
new_queue(Q0), new_queue(Q0),
phrase(init_propagator_(Vs, P), [Q0], [Q]), phrase(init_propagator_(Vs, P), [Q0], [Q]),
variables_same_queue(Vs), variables_same_queue(Vs),
trigger_once_(P, Q)]. trigger_once_(P, Q)].
morphing(pplus).
morphing(ptimes).
morphing(pexp).
morphing(ptzdiv).
morphing_propagator(P0, P, Target) :-
P0 =.. [F|Args0],
( morphing(F) ->
append(Args0, [Last], Args),
Target = p(Last)
; Args = Args0,
Target = none
),
P =.. [F|Args].
morph_into_propagator(MState, Vs, P0, Morph) -->
kill(MState),
{ morphing_propagator(P0, P, _),
make_propagator(P, Morph) },
init_propagator_(Vs, Morph),
trigger_prop(Morph).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- use_module(library(lists)), ?- use_module(library(lists)),
use_module(library(format)), use_module(library(format)),
@@ -2733,14 +2756,12 @@ geq(A, B) :-
) )
; ( AI cis_geq n(B) -> true ; ( AI cis_geq n(B) -> true
; domain_remove_smaller_than(AD, B, AD1), ; domain_remove_smaller_than(AD, B, AD1),
fd_put(A, AD1, APs), fd_put(A, AD1, APs)
do_queue
) )
) )
; fd_get(B, BD, BPs) -> ; fd_get(B, BD, BPs) ->
domain_remove_greater_than(BD, A, BD1), domain_remove_greater_than(BD, A, BD1),
fd_put(B, BD1, BPs), fd_put(B, BD1, BPs)
do_queue
; A >= B ; A >= B
). ).
@@ -2810,7 +2831,7 @@ matches([
m(var(X) #= var(Y)+var(Z)) => [p(pplus(Y,Z,X))], m(var(X) #= var(Y)+var(Z)) => [p(pplus(Y,Z,X))],
m(var(X) #= var(Y)-var(Z)) => [p(pplus(X,Z,Y))], m(var(X) #= var(Y)-var(Z)) => [p(pplus(X,Z,Y))],
m(var(X) #= var(Y)*var(Z)) => [p(ptimes(Y,Z,X))], m(var(X) #= var(Y)*var(Z)) => [p(ptimes(Y,Z,X))],
m(var(X) #= -var(Z)) => [p(ptimes(-1, Z, X))], m(var(X) #= -var(Y)) => [p(pplus(X,Y,0))],
m_c(any(X) #= any(Y), left_right_linsum_const(X, Y, Cs, Vs, S)) => m_c(any(X) #= any(Y), left_right_linsum_const(X, Y, Cs, Vs, S)) =>
[g(scalar_product_(#=, Cs, Vs, S))], [g(scalar_product_(#=, Cs, Vs, S))],
m_c(var(X) #= abs(var(Y)) + any(V0), X == Y) => [d(V0,V),p(x_eq_abs_plus_v(X,V))], m_c(var(X) #= abs(var(Y)) + any(V0), X == Y) => [d(V0,V),p(x_eq_abs_plus_v(X,V))],
@@ -2906,8 +2927,9 @@ match_goals([G|Gs], F) --> match_goal(G, F), match_goals(Gs, F).
match_goal(r(X,Y), F) --> { G =.. [F,X,Y] }, [G]. match_goal(r(X,Y), F) --> { G =.. [F,X,Y] }, [G].
match_goal(d(X,Y), _) --> [parse_clpz(X, Y)]. match_goal(d(X,Y), _) --> [parse_clpz(X, Y)].
match_goal(g(Goal), _) --> [Goal]. match_goal(g(Goal), _) --> [Goal].
match_goal(p(Prop), _) --> match_goal(p(Prop0), _) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P), [make_propagator(Prop, P),
new_queue(Q0), new_queue(Q0),
phrase(init_propagator_(Vs, P), [Q0], [Q]), phrase(init_propagator_(Vs, P), [Q0], [Q]),
@@ -3295,7 +3317,7 @@ integer_kroot_leq(L, U, N, K, R) :-
% When reasoning over integers, replace (=\=)/2 by (#\=)/2 to obtain more % When reasoning over integers, replace (=\=)/2 by (#\=)/2 to obtain more
% general relations. % general relations.
X #\= Y :- clpz_neq(X, Y), do_queue. X #\= Y :- clpz_neq(X, Y).
% X #\= Y + Z % X #\= Y + Z
@@ -3358,7 +3380,7 @@ X #< Y :- Y #> X.
% X in inf.. -4\/1..9\/81..sup. % X in inf.. -4\/1..9\/81..sup.
% ``` % ```
#\ Q :- reify(Q, 0), do_queue. #\ Q :- reify(Q, 0).
%% #<==>(?P, ?Q) %% #<==>(?P, ?Q)
% %
@@ -3396,7 +3418,7 @@ X #< Y :- Y #> X.
% Z = 2. % Z = 2.
% ``` % ```
L #<==> R :- reify(L, B), reify(R, B), do_queue. L #<==> R :- reify(L, B), reify(R, B).
%% #==>(?P, ?Q) %% #==>(?P, ?Q)
% %
@@ -3431,7 +3453,7 @@ L #<== R :- R #==> L.
% %
% P and Q hold. % P and Q hold.
L #/\ R :- reify(L, 1), reify(R, 1), do_queue. L #/\ R :- reify(L, 1), reify(R, 1).
conjunctive_neqs_var_drep(Eqs, Var, Drep) :- conjunctive_neqs_var_drep(Eqs, Var, Drep) :-
conjunctive_neqs_var(Eqs, Var), conjunctive_neqs_var(Eqs, Var),
@@ -3519,16 +3541,17 @@ L #\ R :- (L #\/ R) #/\ #\ (L #/\ R).
d(D) that states D is 1 iff all subexpressions are defined. a(V) d(D) that states D is 1 iff all subexpressions are defined. a(V)
means that V is an auxiliary variable that was introduced while means that V is an auxiliary variable that was introduced while
parsing a compound expression. a(X,V) means V is auxiliary unless parsing a compound expression. a(X,V) means V is auxiliary unless
it is ==/2 X, and a(X,Y,V) means V is auxiliary unless it is ==/2 X it is (==)/2 X, and a(X,Y,V) means V is auxiliary unless it is
or Y. l(L) means the literal L occurs in the described list. (==)/2 X or Y. l(L) means the literal L occurs in the described
list, and ls(Ls) means the literals Ls occur in the described list.
When a constraint becomes entailed or subexpressions become When a constraint becomes entailed or subexpressions become
undefined, created auxiliary constraints are killed, and the undefined, created auxiliary constraints are killed, and the
"clpz" attribute is removed from auxiliary variables. "clpz" attribute is removed from auxiliary variables.
For mod/2, div/2, rem/2 etc. we create a skeleton propagator and For (//)/2, (mod)/2 and (rem)/2, we create a skeleton propagator
remember it as an auxiliary constraint. The pskeleton propagator and remember it as an auxiliary constraint. The pskeleton
can use the skeleton when the constraint is defined. propagator can use the skeleton when the constraint is defined.
We cannot use a skeleton propagator for (/)/2, since (/)/2 can We cannot use a skeleton propagator for (/)/2, since (/)/2 can
fail in cases such as 0 #==> X #= 1/2, where we expect success. fail in cases such as 0 #==> X #= 1/2, where we expect success.
@@ -3544,27 +3567,32 @@ parse_reified(E, R, D,
m(A+B) => [d(D), p(pplus(A,B,R)), a(A,B,R)], m(A+B) => [d(D), p(pplus(A,B,R)), a(A,B,R)],
m(A*B) => [d(D), p(ptimes(A,B,R)), a(A,B,R)], m(A*B) => [d(D), p(ptimes(A,B,R)), a(A,B,R)],
m(A-B) => [d(D), p(pplus(R,B,A)), a(A,B,R)], m(A-B) => [d(D), p(pplus(R,B,A)), a(A,B,R)],
m(-A) => [d(D), p(ptimes(-1,A,R)), a(R)], m(-A) => [d(D), p(pplus(A,R,0)), a(R)],
m(max(A,B)) => [d(D), p(pgeq(R, A)), p(pgeq(R, B)), p(pmax(A,B,R)), a(A,B,R)], m(max(A,B)) => [d(D), p(pgeq(R, A)), p(pgeq(R, B)), p(pmax(A,B,R)), a(A,B,R)],
m(min(A,B)) => [d(D), p(pgeq(A, R)), p(pgeq(B, R)), p(pmin(A,B,R)), a(A,B,R)], m(min(A,B)) => [d(D), p(pgeq(A, R)), p(pgeq(B, R)), p(pmin(A,B,R)), a(A,B,R)],
m(abs(A)) => [g(#R#>=0), d(D), p(pabs(A, R)), a(A,R)], m(abs(A)) => [d(D), g(#R#>=0), p(pabs(A, R)), a(A,R)],
m(A/B) => [p(preified_slash(A,B,D,R)), a(A,B,R)], m(A^B) => [d(D1), p(preified_exp(A,B,D2,R)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A/B) => [d(D1), p(preified_slash(A,B,D2,R)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A div B) => [d(D1),
g(phrase(parse_reified_clpz(((A-(A mod B)) // B), R, D2), Ps)),
ls(Ps),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A//B) => [skeleton(A,B,D,R,ptzdiv)], m(A//B) => [skeleton(A,B,D,R,ptzdiv)],
m(A div B) => [skeleton(A,B,D,R,pdiv)],
m(A mod B) => [skeleton(A,B,D,R,pmod)], m(A mod B) => [skeleton(A,B,D,R,pmod)],
m(A rem B) => [skeleton(A,B,D,R,prem)], m(A rem B) => [skeleton(A,B,D,R,prem)],
m(A^B) => [d(D), p(pexp(A,B,R)), a(A,B,R)],
% bitwise operations % bitwise operations
m(\A) => [function(D,\,A,R)], m(\A) => [function(D,\,A,R)],
m(msb(A)) => [g(#A#>0) ,function(D,msb,A,R)], m(msb(A)) => [g(#A#>0) ,function(D,msb,A,R)],
m(lsb(A)) => [g(#A#>0), function(D,lsb,A,R)], m(lsb(A)) => [g(#A#>0), function(D,lsb,A,R)],
m(popcount(A)) => [function(D,popcount,A,R)], m(popcount(A)) => [d(D), p(ppopcount(A, R)), a(A,R)],
m(sign(A)) => [function(D,sign,A,R)], m(sign(A)) => [d(D), p(psign(A, R)), a(A,R)],
m(A<<B) => [function(D,<<,A,B,R)], m(A<<B) => [function(D,<<,A,B,R)],
m(A>>B) => [function(D,>>,A,B,R)], m(A>>B) => [function(D,>>,A,B,R)],
m(A/\B) => [function(D,/\,A,B,R)], m(A/\B) => [function(D,/\,A,B,R)],
m(A\/B) => [function(D,\/,A,B,R)], m(A\/B) => [function(D,\/,A,B,R)],
m(xor(A, B)) => [function(D,xor,A,B,R)], m(xor(A, B)) => [skeleton(A,B,D,R,pxor)],
g(true) => [g(domain_error(clpz_expression, E))]] g(true) => [g(domain_error(clpz_expression, E))]]
). ).
@@ -3620,10 +3648,13 @@ reified_goal(d(D), Ds) -->
; { domain_error(one_or_two_element_list, Ds) } ; { domain_error(one_or_two_element_list, Ds) }
). ).
reified_goal(g(Goal), _) --> [{Goal}]. reified_goal(g(Goal), _) --> [{Goal}].
reified_goal(p(Vs, Prop), _) --> reified_goal(p(Vs, Prop0), _) -->
{ morphing_propagator(Prop0, Prop, Target) },
[{make_propagator(Prop, P)}], [{make_propagator(Prop, P)}],
target_propagator(Target),
parse_init_dcg(Vs, P), parse_init_dcg(Vs, P),
[{trigger_once(P)}], [{variables_same_queue(Vs),
trigger_once(P)}],
[( { propagator_state(P, S), S == dead } -> [] ; [p(P)])]. [( { propagator_state(P, S), S == dead } -> [] ; [p(P)])].
reified_goal(p(Prop), Ds) --> reified_goal(p(Prop), Ds) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop, Vs) },
@@ -3633,7 +3664,9 @@ reified_goal(function(D,Op,A,B,R), Ds) -->
reified_goal(function(D,Op,A,R), Ds) --> reified_goal(function(D,Op,A,R), Ds) -->
reified_goals([d(D),p(pfunction(Op,A,R)),a(A,R)], Ds). reified_goals([d(D),p(pfunction(Op,A,R)),a(A,R)], Ds).
reified_goal(skeleton(A,B,D,R,F), Ds) --> reified_goal(skeleton(A,B,D,R,F), Ds) -->
{ Prop =.. [F,X,Y,Z] }, { Prop0 =.. [F,X,Y,Z],
morphing_propagator(Prop0, Prop, Target) },
target_propagator(Target),
reified_goals([d(D1),l(p(P)),g(make_propagator(Prop, P)), reified_goals([d(D1),l(p(P)),g(make_propagator(Prop, P)),
p([A,B,D2,R], pskeleton(A,B,D2,[X,Y,Z]-P,R,F)), p([A,B,D2,R], pskeleton(A,B,D2,[X,Y,Z]-P,R,F)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)], Ds). p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)], Ds).
@@ -3641,12 +3674,20 @@ reified_goal(a(V), _) --> [a(V)].
reified_goal(a(X,V), _) --> [a(X,V)]. reified_goal(a(X,V), _) --> [a(X,V)].
reified_goal(a(X,Y,V), _) --> [a(X,Y,V)]. reified_goal(a(X,Y,V), _) --> [a(X,Y,V)].
reified_goal(l(L), _) --> [[L]]. reified_goal(l(L), _) --> [[L]].
reified_goal(ls(Ls), _) --> [Ls].
target_propagator(p(Prop)) --> [[p(Prop)]].
target_propagator(none) --> [].
parse_init_dcg([], _) --> []. parse_init_dcg([], _) --> [].
parse_init_dcg([V|Vs], P) --> [{init_propagator(V, P)}], parse_init_dcg(Vs, P). parse_init_dcg([V|Vs], P) --> [{init_propagator(V, P)}], parse_init_dcg(Vs, P).
%?- set_prolog_flag(answer_write_options, [portray(true)]), /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% clpz:parse_reified_clauses(Cs), maplist(portray_clause, Cs). ?- use_module(library(lists)),
use_module(library(format)),
clpz:parse_reified_clauses(Cs),
maplist(portray_clause, Cs).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
reify(E, B) :- reify(E, B, _). reify(E, B) :- reify(E, B, _).
@@ -3691,7 +3732,7 @@ reify_(tuples_in(Tuples, Relation), B) -->
#B #<==> And }, #B #<==> And },
propagator_init_trigger([B], tuples_not_in(Tuples, Relation, B)), propagator_init_trigger([B], tuples_not_in(Tuples, Relation, B)),
kill_reified_tuples(Bs, Ps, Bs), kill_reified_tuples(Bs, Ps, Bs),
list(Ps), seq(Ps),
as([B|Bs]). as([B|Bs]).
reify_(finite_domain(V), B) --> reify_(finite_domain(V), B) -->
propagator_init_trigger(reified_fd(V,B)), propagator_init_trigger(reified_fd(V,B)),
@@ -3723,20 +3764,17 @@ arithmetic(L, R, B, Functor) -->
{ phrase((parse_reified_clpz(L, LR, LD), { phrase((parse_reified_clpz(L, LR, LD),
parse_reified_clpz(R, RR, RD)), Ps), parse_reified_clpz(R, RR, RD)), Ps),
Prop =.. [Functor,LD,LR,RD,RR,Ps,B] }, Prop =.. [Functor,LD,LR,RD,RR,Ps,B] },
list(Ps), seq(Ps),
propagator_init_trigger([LD,LR,RD,RR,B], Prop), propagator_init_trigger([LD,LR,RD,RR,B], Prop),
a(B). a(B).
boolean(L, R, B, Functor) --> boolean(L, R, B, Functor) -->
{ reify(L, LR, Ps1), reify(R, RR, Ps2), { reify(L, LR, Ps1), reify(R, RR, Ps2),
Prop =.. [Functor,LR,Ps1,RR,Ps2,B] }, Prop =.. [Functor,LR,Ps1,RR,Ps2,B] },
list(Ps1), list(Ps2), seq(Ps1), seq(Ps2),
propagator_init_trigger([LR,RR,B], Prop), propagator_init_trigger([LR,RR,B], Prop),
a(LR, RR, B). a(LR, RR, B).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
a(X,Y,B) --> a(X,Y,B) -->
( nonvar(X) -> a(Y, B) ( nonvar(X) -> a(Y, B)
; nonvar(Y) -> a(X, B) ; nonvar(Y) -> a(X, B)
@@ -3871,7 +3909,6 @@ domain(V, Dom) :-
domains_intersection(Dom, Dom0, Dom1), domains_intersection(Dom, Dom0, Dom1),
%format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]), %format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]),
fd_put(V, Dom1, VPs), fd_put(V, Dom1, VPs),
do_queue,
reinforce(V) reinforce(V)
; domain_contains(Dom, V) ; domain_contains(Dom, V)
). ).
@@ -4186,7 +4223,6 @@ activate_propagator(propagator(P,State)) -->
enable_queue :- true. % NOP enable_queue :- true. % NOP
disable_queue :- true. % NOP disable_queue :- true. % NOP
do_queue. % NOP
%do_queue --> print_queue, { false }. %do_queue --> print_queue, { false }.
do_queue --> do_queue -->
@@ -4768,7 +4804,7 @@ run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
) }. ) }.
% X + Y = Z % X + Y = Z
run_propagator(pplus(X,Y,Z), MState) --> run_propagator(pplus(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( X =:= 0 -> kill(MState), Y = Z ( X =:= 0 -> kill(MState), Y = Z
; Y == Z -> kill(MState), X =:= 0 ; Y == Z -> kill(MState), X =:= 0
@@ -4787,7 +4823,7 @@ run_propagator(pplus(X,Y,Z), MState) -->
; [] ; []
) )
) )
; nonvar(Y) -> run_propagator(pplus(Y,X,Z), MState) ; nonvar(Y) -> run_propagator(pplus(Y,X,Z,Morph), MState)
; nonvar(Z) -> ; nonvar(Z) ->
( X == Y -> kill(MState), { even(Z), X is Z // 2 } ( X == Y -> kill(MState), { even(Z), X is Z // 2 }
; { fd_get(X, XD, _), ; { fd_get(X, XD, _),
@@ -4804,7 +4840,8 @@ run_propagator(pplus(X,Y,Z), MState) -->
; [] ; []
) )
) )
; ( X == Y -> { kill(MState), 2*X #= Z } ; ( X == Y ->
morph_into_propagator(MState, [X,Z], ptimes(2,X,Z), Morph)
; X == Z -> kill(MState), Y = 0 ; X == Z -> kill(MState), Y = 0
; Y == Z -> kill(MState), X = 0 ; Y == Z -> kill(MState), X = 0
; { fd_get(X, XD, XL, XU, XPs), ; { fd_get(X, XD, XL, XU, XPs),
@@ -4830,7 +4867,7 @@ run_propagator(pplus(X,Y,Z), MState) -->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(ptimes(X,Y,Z), MState) --> run_propagator(ptimes(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( nonvar(Y) -> kill(MState), Z is X * Y ( nonvar(Y) -> kill(MState), Z is X * Y
; X =:= 0 -> kill(MState), Z = 0 ; X =:= 0 -> kill(MState), Z = 0
@@ -4850,7 +4887,7 @@ run_propagator(ptimes(X,Y,Z), MState) -->
) )
) )
) )
; nonvar(Y) -> run_propagator(ptimes(Y,X,Z), MState) ; nonvar(Y) -> run_propagator(ptimes(Y,X,Z,Morph), MState)
; nonvar(Z) -> ; nonvar(Z) ->
( X == Y -> ( X == Y ->
kill(MState), kill(MState),
@@ -4876,7 +4913,8 @@ run_propagator(ptimes(X,Y,Z), MState) -->
; neq_num(X, 0), neq_num(Y, 0) ; neq_num(X, 0), neq_num(Y, 0)
) )
) )
; ( X == Y -> kill(MState), { X^2 #= Z } ; ( X == Y ->
morph_into_propagator(MState, [X,Z], pexp(X,2,Z), Morph)
; { fd_get(X, XD, XL, XU, XPs), ; { fd_get(X, XD, XL, XU, XPs),
fd_get(Y, _, YL, YU, _), fd_get(Y, _, YL, YU, _),
fd_get(Z, ZD, ZL, ZU, _) }, fd_get(Z, ZD, ZL, ZU, _) },
@@ -4907,17 +4945,8 @@ run_propagator(ptimes(X,Y,Z), MState) -->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% X div Y = Z
run_propagator(pdiv(X,Y,Z), MState) -->
{ kill(MState), Z #= (X-(X mod Y)) // Y }.
% X rdiv Y = Z
run_propagator(prdiv(X,Y,Z), MState) -->
{ kill(MState), Z*Y #= X }.
% X // Y = Z (round towards zero) % X // Y = Z (round towards zero)
run_propagator(ptzdiv(X,Y,Z), MState) --> run_propagator(ptzdiv(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( nonvar(Y) -> kill(MState), Y =\= 0, Z is X // Y ( nonvar(Y) -> kill(MState), Y =\= 0, Z is X // Y
; { fd_get(Y, YD, YL, YU, YPs) }, ; { fd_get(Y, YD, YL, YU, YPs) },
@@ -4961,7 +4990,8 @@ run_propagator(ptzdiv(X,Y,Z), MState) -->
; nonvar(Y) -> ; nonvar(Y) ->
Y =\= 0, Y =\= 0,
( Y =:= 1 -> kill(MState), X = Z ( Y =:= 1 -> kill(MState), X = Z
; Y =:= -1 -> kill(MState), { Z #= -X } ; Y =:= -1 ->
morph_into_propagator(MState, [X,Z], pplus(X,Z,0), Morph)
; { fd_get(X, XD, XL, XU, XPs) }, ; { fd_get(X, XD, XL, XU, XPs) },
( nonvar(Z) -> ( nonvar(Z) ->
kill(MState), kill(MState),
@@ -5411,9 +5441,11 @@ run_propagator(pmin(X,Y,Z), MState) -->
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% % Z = X ^ Y %% % Z = X ^ Y
run_propagator(pexp(X,Y,Z), MState) --> run_propagator(pexp(X,Y,Z,Morph), MState) -->
( X == 1 -> kill(MState), Z = 1 ( X == 1 -> kill(MState), Z = 1
; X == 0 -> kill(MState), queue_goal((Z in 0..1, Y #>= 0, Z #<==> Y #= 0)) ; X == 0 ->
queue_goal((Z in 0..1, Y #>= 0)),
morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph)
; Y == 0 -> kill(MState), Z = 1 ; Y == 0 -> kill(MState), Z = 1
; Y == 1 -> kill(MState), Z = X ; Y == 1 -> kill(MState), Z = X
; nonvar(X) -> ; nonvar(X) ->
@@ -5473,7 +5505,9 @@ run_propagator(pexp(X,Y,Z), MState) -->
) )
; nonvar(Y), Y > 0 -> ; nonvar(Y), Y > 0 ->
( { even(Y) } -> ( { even(Y) } ->
{ geq(Z, 0) } { fd_get(Z, ZD0, ZPs0),
domain_remove_smaller_than(ZD0, 0, ZDG0) },
fd_put(Z, ZDG0, ZPs0)
; true ; true
), ),
( { fd_get(X, XD, XL, XU, _), fd_get(Z, ZD, ZL, ZU, ZPs) } -> ( { fd_get(X, XD, XL, XU, _), fd_get(Z, ZD, ZL, ZU, ZPs) } ->
@@ -5906,6 +5940,35 @@ run_propagator(preified_slash(X, Y, D, R), MState) -->
; [] ; []
). ).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(preified_exp(X, Y, D, R), MState) -->
( X == 1 ->
kill(MState),
D = 1,
R = 1
; Y == 0 ->
kill(MState),
D = 1,
R = 1
; Y == 1 ->
kill(MState),
D = 1,
R = X
; nonvar(X),
nonvar(Y) ->
kill(MState),
( ( abs(X) =:= 1 ; Y >= 0 ) ->
D = 1,
R is X^Y
; D = 0
)
; D == 1 ->
kill(MState),
queue_goal(X^Y #= R)
; []
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -6054,7 +6117,7 @@ domain_to_list(Domain, List) :- phrase(domain_to_list(Domain), List).
domain_to_list(split(_, Left, Right)) --> domain_to_list(split(_, Left, Right)) -->
domain_to_list(Left), domain_to_list(Right). domain_to_list(Left), domain_to_list(Right).
domain_to_list(empty) --> []. domain_to_list(empty) --> [].
domain_to_list(from_to(n(F),n(T))) --> { numlist(F, T, Ns) }, list(Ns). domain_to_list(from_to(n(F),n(T))) --> { numlist(F, T, Ns) }, seq(Ns).
difference_arcs([], []) --> []. difference_arcs([], []) --> [].
difference_arcs([V|Vs], FL0) --> difference_arcs([V|Vs], FL0) -->
@@ -6414,8 +6477,7 @@ num_infinite(Var, N0, N) :-
weak_arc_all_distinct(Ls) :- weak_arc_all_distinct(Ls) :-
must_be(list, Ls), must_be(list, Ls),
Orig = original_goal(_, weak_arc_all_distinct(Ls)), Orig = original_goal(_, weak_arc_all_distinct(Ls)),
all_distinct(Ls, [], Orig), all_distinct(Ls, [], Orig).
do_queue.
all_distinct([], _, _). all_distinct([], _, _).
all_distinct([X|Right], Left, Orig) :- all_distinct([X|Right], Left, Orig) :-
@@ -6728,8 +6790,10 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :-
gcc_global(Vs, KNs) :- gcc_global(Vs, KNs) :-
gcc_check(KNs), gcc_check(KNs),
% reach fix-point: all elements of clpz_gcc_vs must be variables % previously: call do_queue/0 (now a NOP) here to reach a
do_queue, % fix-point: all elements of clpz_gcc_vs must be variables. We
% must ensure this holds if gcc_check/1 is later rewritten to
% actually disable the queue.
with_local_attributes(Vs, with_local_attributes(Vs,
(gcc_arcs(KNs, S, Vals), (gcc_arcs(KNs, S, Vals),
variables_with_num_occurrences(Vs, VNs), variables_with_num_occurrences(Vs, VNs),
@@ -7752,7 +7816,7 @@ attributes_goals([propagator(P, State)|As]) -->
; maplist(unwrap_with(=), Gs, Gs1) ; maplist(unwrap_with(=), Gs, Gs1)
), ),
maplist(with_clpz, Gs1, Gs2) }, maplist(with_clpz, Gs1, Gs2) },
list(Gs2) seq(Gs2)
; [P] % possibly user-defined constraint ; [P] % possibly user-defined constraint
), ),
attributes_goals(As). attributes_goals(As).
@@ -7770,17 +7834,15 @@ bare_integer(V0, V) :- ( integer(V0) -> V = V0 ; V = #V0 ).
attribute_goal_(presidual(Goal)) --> [Goal]. attribute_goal_(presidual(Goal)) --> [Goal].
attribute_goal_(pgeq(A,B)) --> [#A #>= #B]. attribute_goal_(pgeq(A,B)) --> [#A #>= #B].
attribute_goal_(pplus(X,Y,Z)) --> [#X + #Y #= #Z]. attribute_goal_(pplus(X,Y,Z,_)) --> [#X + #Y #= #Z].
attribute_goal_(pneq(A,B)) --> [#A #\= #B]. attribute_goal_(pneq(A,B)) --> [#A #\= #B].
attribute_goal_(ptimes(X,Y,Z)) --> [#X * #Y #= #Z]. attribute_goal_(ptimes(X,Y,Z,_)) --> [#X * #Y #= #Z].
attribute_goal_(absdiff_neq(X,Y,C)) --> [abs(#X - #Y) #\= C]. attribute_goal_(absdiff_neq(X,Y,C)) --> [abs(#X - #Y) #\= C].
attribute_goal_(x_eq_abs_plus_v(X,V)) --> [#X #= abs(#X) + #V]. attribute_goal_(x_eq_abs_plus_v(X,V)) --> [#X #= abs(#X) + #V].
attribute_goal_(x_neq_y_plus_z(X,Y,Z)) --> [#X #\= #Y + #Z]. attribute_goal_(x_neq_y_plus_z(X,Y,Z)) --> [#X #\= #Y + #Z].
attribute_goal_(x_leq_y_plus_c(X,Y,C)) --> [#X #=< #Y + C]. attribute_goal_(x_leq_y_plus_c(X,Y,C)) --> [#X #=< #Y + C].
attribute_goal_(ptzdiv(X,Y,Z)) --> [#X // #Y #= #Z]. attribute_goal_(ptzdiv(X,Y,Z,_)) --> [#X // #Y #= #Z].
attribute_goal_(pdiv(X,Y,Z)) --> [#X div #Y #= #Z]. attribute_goal_(pexp(X,Y,Z,_)) --> [#X ^ #Y #= #Z].
attribute_goal_(prdiv(X,Y,Z)) --> [#X / #Y #= #Z].
attribute_goal_(pexp(X,Y,Z)) --> [#X ^ #Y #= #Z].
attribute_goal_(psign(X,Y)) --> [#Y #= sign(#X)]. attribute_goal_(psign(X,Y)) --> [#Y #= sign(#X)].
attribute_goal_(pabs(X,Y)) --> [#Y #= abs(#X)]. attribute_goal_(pabs(X,Y)) --> [#Y #= abs(#X)].
attribute_goal_(pmod(X,M,K)) --> [#X mod #M #= #K]. attribute_goal_(pmod(X,M,K)) --> [#X mod #M #= #K].
@@ -7840,6 +7902,7 @@ attribute_goal_(reified_and(X,_,Y,_,B)) --> [#X #/\ #Y #<==> #B].
attribute_goal_(reified_or(X, _, Y, _, B)) --> [#X #\/ #Y #<==> #B]. attribute_goal_(reified_or(X, _, Y, _, B)) --> [#X #\/ #Y #<==> #B].
attribute_goal_(reified_not(X, Y)) --> [#\ #X #<==> #Y]. attribute_goal_(reified_not(X, Y)) --> [#\ #X #<==> #Y].
attribute_goal_(preified_slash(X, Y, _, R)) --> [#X/ #Y #= R]. attribute_goal_(preified_slash(X, Y, _, R)) --> [#X/ #Y #= R].
attribute_goal_(preified_exp(X, Y, _, R)) --> [#X^ #Y #= R].
attribute_goal_(pimpl(X, Y, _)) --> [#X #==> #Y]. attribute_goal_(pimpl(X, Y, _)) --> [#X #==> #Y].
attribute_goal_(pfunction(Op, A, B, R)) --> attribute_goal_(pfunction(Op, A, B, R)) -->
{ Expr =.. [Op,#A,#B] }, { Expr =.. [Op,#A,#B] },

View File

@@ -7,7 +7,7 @@ arguments are different terms.
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(lists), [append/3]). :- use_module(library(lists), [append/3, maplist/3]).
:- attribute dif/1. :- attribute dif/1.
@@ -23,6 +23,32 @@ dif_set_variables([Var|Vars], X, Y) :-
put_dif_att(Var, X, Y), put_dif_att(Var, X, Y),
dif_set_variables(Vars, X, Y). dif_set_variables(Vars, X, Y).
remove_goal([], _, []).
remove_goal([G0|G0s], Goal0, Goals) :-
( G0 == Goal0 ->
remove_goal(G0s, Goal0, Goals)
; Goals = [G0|Goals1],
remove_goal(G0s, Goal0, Goals1)
).
vars_remove_goal([], _).
vars_remove_goal([Var|Vars], Goal0) :-
get_atts(Var, +dif(Goals0)),
remove_goal(Goals0, Goal0, Goals),
( Goals = [] ->
put_atts(Var, -dif(_))
; put_atts(Var, +dif(Goals))
),
vars_remove_goal(Vars, Goal0).
reinforce_goal(Goal0, Goal) :-
Goal = (
term_variables(Goal0, Vars),
dif:vars_remove_goal(Vars, Goal0),
Goal0 = (L \== R),
dif:dif(L, R)
).
append_goals([], _). append_goals([], _).
append_goals([Var|Vars], Goals) :- append_goals([Var|Vars], Goals) :-
( get_atts(Var, +dif(VarGoals)) -> ( get_atts(Var, +dif(VarGoals)) ->
@@ -34,9 +60,10 @@ append_goals([Var|Vars], Goals) :-
append_goals(Vars, Goals). append_goals(Vars, Goals).
verify_attributes(Var, Value, Goals) :- verify_attributes(Var, Value, Goals) :-
( get_atts(Var, +dif(Goals)) -> ( get_atts(Var, +dif(Goals0)) ->
term_variables(Value, ValueVars), term_variables(Value, ValueVars),
append_goals(ValueVars, Goals) append_goals(ValueVars, Goals0),
maplist(reinforce_goal, Goals0, Goals)
; Goals = [] ; Goals = []
). ).

View File

@@ -6,8 +6,8 @@
*/ */
/** This library provides an starting point to build HTTP server based applications. /** This library provides an starting point to build HTTP server based applications.
It is based on [Hyper](https://hyper.rs/), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However, It is based on [Warp](https://github.com/seanmonstar/warp), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
some advanced features that Hyper provides are still not accesible. some advanced features that Warp provides are still not accesible.
## Usage ## Usage
@@ -46,7 +46,6 @@ recommeded to use the helper predicates, which are easier to understand and clea
Some things that are still missing: Some things that are still missing:
- Read forms in multipart format - Read forms in multipart format
- HTTP Basic Auth
- Session handling via cookies - Session handling via cookies
- HTML Templating (but you can use [Teruel](https://github.com/aarroyoc/teruel/), [Marquete](https://github.com/aarroyoc/marquete/) or [Djota](https://github.com/aarroyoc/djota) for that) - HTML Templating (but you can use [Teruel](https://github.com/aarroyoc/teruel/), [Marquete](https://github.com/aarroyoc/marquete/) or [Djota](https://github.com/aarroyoc/djota) for that)
*/ */
@@ -54,14 +53,19 @@ Some things that are still missing:
:- module(http_server, [ :- module(http_server, [
http_listen/2, http_listen/2,
http_listen/3,
http_headers/2, http_headers/2,
http_status_code/2, http_status_code/2,
http_body/2, http_body/2,
http_redirect/2, http_redirect/2,
http_query/3 http_query/3,
http_basic_auth/4
]). ]).
:- meta_predicate http_listen(?, :). :- meta_predicate http_listen(?, :).
:- meta_predicate http_listen(?, :, ?).
:- meta_predicate http_basic_auth(:, :, ?, ?).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(crypto)). :- use_module(library(crypto)).
@@ -74,25 +78,58 @@ Some things that are still missing:
%% http_listen(+Port, +Handlers). %% http_listen(+Port, +Handlers).
% %
% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`. % Equivalent to `http_listen(Port, Handlers, [])`.
% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable)
% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User.
http_listen(Port, Module:Handlers0) :- http_listen(Port, Module:Handlers0) :-
must_be(integer, Port), must_be(integer, Port),
must_be(list, Handlers0), must_be(list, Handlers0),
maplist(module_qualification(Module), Handlers0, Handlers), maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers). http_listen_(Port, Handlers, []).
%% http_listen(+Port, +Handlers, +Options).
%
% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`.
% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable)
% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User.
%
% The following options are supported:
%
% - `tls_key(+Key)` - a TLS key for HTTPS (string)
% - `tls_cert(+Cert)` - a TLS cert for HTTPS (string)
% - `content_length_limit(+Limit)` - maximum length (in bytes) for the incoming bodies. By default, 32KB.
%
% In order to have a HTTPS server (instead of plain HTTP), both `tls_key` and `tls_cert` options must be provided.
http_listen(Port, Module:Handlers0, Options) :-
must_be(integer, Port),
must_be(list, Handlers0),
must_be(list, Options),
maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers, Options).
module_qualification(M, H0, H) :- module_qualification(M, H0, H) :-
H0 =.. [Method, Path, Goal], H0 =.. [Method, Path, Goal],
H =.. [Method, Path, M:Goal]. H =.. [Method, Path, M:Goal].
http_listen_(Port, Handlers) :- http_listen_(Port, Handlers, Options) :-
parse_options(Options, TLSKey, TLSCert, ContentLengthLimit),
phrase(format_("0.0.0.0:~d", [Port]), Addr), phrase(format_("0.0.0.0:~d", [Port]), Addr),
'$http_listen'(Addr, HttpListener),!, '$http_listen'(Addr, HttpListener, TLSKey, TLSCert, ContentLengthLimit),!,
format("Listening at ~s\n", [Addr]), format("Listening at ~s\n", [Addr]),
http_loop(HttpListener, Handlers). http_loop(HttpListener, Handlers).
parse_options(Options, TLSKey, TLSCert, ContentLengthLimit) :-
member_option_default(tls_key, Options, "", TLSKey),
member_option_default(tls_cert, Options, "", TLSCert),
member_option_default(content_length_limit, Options, 32768, ContentLengthLimit),
must_be(integer, ContentLengthLimit).
member_option_default(Key, List, _Default, Value) :-
X =.. [Key, Value],
member(X, List).
member_option_default(Key, List, Default, Default) :-
X =.. [Key, _],
\+ member(X, List).
http_loop(HttpListener, Handlers) :- http_loop(HttpListener, Handlers) :-
'$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle), '$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
current_time(Time), current_time(Time),
@@ -114,7 +151,7 @@ http_loop(HttpListener, Handlers) :-
) )
; ( ; (
'$http_answer'(ResponseHandle, 404, [], ResponseStream), '$http_answer'(ResponseHandle, 404, [], ResponseStream),
call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream))) call_cleanup(format(ResponseStream, "Not Found", []), close(ResponseStream)))
), ),
http_loop(HttpListener, Handlers). http_loop(HttpListener, Handlers).
@@ -263,25 +300,21 @@ http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries
parse_queries([Key-Value|Queries]) --> parse_queries([Key-Value|Queries]) -->
string_without("=", Key0), string_without("=", Key0),
{
phrase(url_decode(Key), Key0)
},
"=", "=",
string_without("&", Value0), string_without("&", Value0),
{
phrase(url_decode(Value), Value0)
},
"&", "&",
parse_queries(Queries). parse_queries(Queries),
{
phrase(url_decode(Key), Key0),
phrase(url_decode(Value), Value0)
}.
parse_queries([Key-Value]) --> parse_queries([Key-Value]) -->
string_without("=", Key0), string_without("=", Key0),
{
phrase(url_decode(Key), Key0)
},
"=", "=",
string_without(" ", Value0), string_without(" ", Value0),
{ {
phrase(url_decode(Key), Key0),
phrase(url_decode(Value), Value0) phrase(url_decode(Value), Value0)
}. }.
@@ -292,9 +325,13 @@ parse_queries([]) -->
url_decode([Char|Chars]) --> url_decode([Char|Chars]) -->
[Char], [Char],
{ {
Char \= '%' Char \= '%',
Char \= (+)
}, },
url_decode(Chars). url_decode(Chars).
url_decode([' '|Chars]) -->
"+",
url_decode(Chars).
url_decode([Char|Chars]) --> url_decode([Char|Chars]) -->
"%", "%",
[A], [A],
@@ -352,3 +389,49 @@ url_decode([Char|Chars]) -->
url_decode(Chars). url_decode(Chars).
url_decode([]) --> []. url_decode([]) --> [].
%% http_basic_auth(+LoginPredicate, +Handler, +Request, -Response)
%
% Metapredicate that wraps an existing Handler with an HTTP Basic Auth flow.
% Checks if a given user + password is authorized to execute that handler, returning 401
% if it's not satisfied.
%
% `LoginPredicate` must be a predicate of arity 2 that takes a User and a Password.
% `Handler` will have, in addition to the Request and Response arguments, a User argument
% containing the User given in the authentication.
%
% Example:
%
% ```
% main :-
% http_listen(8800,[get('/', http_basic_auth(login, inside_handler("data")))]).
%
% login(User, Pass) :-
% User = "aarroyoc",
% Pass = "123456".
%
% inside_handler(Data, User, Request, Response) :-
% http_body(Response, text(User)).
% ```
http_basic_auth(LoginPredicate, Handler, Request, Response) :-
http_headers(Request, Headers),
member("authorization"-AuthorizationStr, Headers),
append("Basic ", Coded, AuthorizationStr),
chars_base64(UserPass, Coded, []),
append(User, [':'|Password], UserPass),
(
call(LoginPredicate, User, Password) ->
call(Handler, User, Request, Response)
; http_basic_auth_unauthorized_response(Response)
).
http_basic_auth(_LoginPredicate, _Handler, Request, Response) :-
http_headers(Request, Headers),
\+ member("authorization"-_, Headers),
http_basic_auth_unauthorized_response(Response).
http_basic_auth_unauthorized_response(Response) :-
http_status_code(Response, 401),
http_headers(Response, ["www-authenticate"-"Basic realm=\"Scryer Prolog\", charset=\"UTF-8\""]),
http_body(Response, text("Unauthorized")).

View File

@@ -214,26 +214,6 @@ run_cleaners_without_handling(Cp) :-
% call_with_inference_limit % call_with_inference_limit
:- non_counted_backtracking end_block/4.
end_block(_, Bb, NBb, _L) :-
'$clean_up_block'(NBb),
'$reset_block'(Bb).
end_block(B, _Bb, NBb, L) :-
'$install_inference_counter'(B, L, _),
'$reset_block'(NBb),
'$fail'.
:- non_counted_backtracking handle_ile/3.
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :-
!,
'$pop_ball_stack'.
handle_ile(B, _, _) :-
'$remove_call_policy_check'(B),
'$pop_from_ball_stack',
'$unwind_stack'.
:- meta_predicate(call_with_inference_limit(0, ?, ?)). :- meta_predicate(call_with_inference_limit(0, ?, ?)).
:- non_counted_backtracking call_with_inference_limit/3. :- non_counted_backtracking call_with_inference_limit/3.
@@ -256,8 +236,6 @@ call_with_inference_limit(G, L, R) :-
call_with_inference_limit(G, L, R, Bb, B), call_with_inference_limit(G, L, R, Bb, B),
'$remove_call_policy_check'(B). '$remove_call_policy_check'(B).
install_inference_counter(B, L, Count0) :-
'$install_inference_counter'(B, L, Count0).
:- meta_predicate(call_with_inference_limit(0,?,?,?,?)). :- meta_predicate(call_with_inference_limit(0,?,?,?,?)).
@@ -265,23 +243,34 @@ install_inference_counter(B, L, Count0) :-
call_with_inference_limit(G, L, R, Bb, B) :- call_with_inference_limit(G, L, R, Bb, B) :-
'$install_new_block'(NBb), '$install_new_block'(NBb),
'$install_inference_counter'(B, L, Count0), '$install_inference_counter'(NBb, L, Count0),
'$call_with_inference_counting'(call(G)), '$call_with_inference_counting'(call(G)),
'$inference_level'(R, B), '$inference_level'(R, B),
'$remove_inference_counter'(B, Count1), '$remove_inference_counter'(NBb, Count1),
Diff is L - (Count1 - Count0), Diff is L - (Count1 - Count0),
end_block(B, Bb, NBb, Diff). ( '$clean_up_block'(NBb),
'$reset_block'(Bb)
; '$install_inference_counter'(NBb, Diff, _),
'$reset_block'(NBb),
'$fail'
).
call_with_inference_limit(_, _, R, Bb, B) :- call_with_inference_limit(_, _, R, Bb, B) :-
( '$inference_limit_exceeded' ->
R = inference_limit_exceeded
; true
),
'$get_current_block'(NBb),
'$remove_inference_counter'(NBb, _),
'$reset_block'(Bb), '$reset_block'(Bb),
'$remove_inference_counter'(B, _), '$remove_call_policy_check'(B),
( '$get_ball'(Ball), ( '$get_ball'(_),
'$push_ball_stack', '$push_ball_stack',
'$get_cp'(Cp), '$get_cp'(Cp),
'$set_cp_by_default'(Cp) '$set_cp_by_default'(Cp),
; '$remove_call_policy_check'(B), '$pop_from_ball_stack',
'$fail' '$unwind_stack'
), ; nonvar(R)
handle_ile(B, Ball, R). ).
%% partial_string(String, L, L0) %% partial_string(String, L, L0)
% %
@@ -358,10 +347,10 @@ call_nth_nesting(C, ID) :-
bb_put(ID, 0), bb_put(ID, 0),
bb_put(i_call_nth_counter, C). bb_put(i_call_nth_counter, C).
%% countall(Goal, N). %% countall(G_0, N).
% %
% countall(Goal, N) counts all solutions of Goal and unifies N with % countall(G_0, N) is true iff N unifies with the total number of
% this number of solutions. This predicate always succeeds once. % answers of call(G_0).
:- meta_predicate(countall(0, ?)). :- meta_predicate(countall(0, ?)).
@@ -370,7 +359,7 @@ countall(Goal, N) :-
( integer(N) -> ( integer(N) ->
( N < 0 -> ( N < 0 ->
domain_error(not_less_than_zero, N, countall/2) domain_error(not_less_than_zero, N, countall/2)
; N > 0 ; true
) )
; true ; true
), ),

View File

@@ -9,6 +9,7 @@
:- module(pio, [phrase_from_file/2, :- module(pio, [phrase_from_file/2,
phrase_from_file/3, phrase_from_file/3,
phrase_from_stream/2,
phrase_to_file/2, phrase_to_file/2,
phrase_to_file/3, phrase_to_file/3,
phrase_to_stream/2 phrase_to_stream/2
@@ -17,16 +18,30 @@
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(freeze)). :- use_module(library(freeze)).
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]). :- use_module(library(gensym)).
:- use_module(library(lists), [member/2, maplist/2]). :- use_module(library(iso_ext), [
bb_get/2, bb_put/2, setup_call_cleanup/3, partial_string/3, partial_string_tail/2
]).
:- use_module(library(lists), [append/3, length/2, member/2, maplist/2]).
:- use_module(library(charsio), [get_n_chars/3]). :- use_module(library(charsio), [get_n_chars/3]).
:- meta_predicate(phrase_from_file(2, ?)). :- meta_predicate(phrase_from_file(2, ?)).
:- meta_predicate(phrase_from_file(2, ?, ?)). :- meta_predicate(phrase_from_file(2, ?, ?)).
:- meta_predicate(phrase_from_stream(2, ?)).
:- meta_predicate(phrase_to_file(2, ?)). :- meta_predicate(phrase_to_file(2, ?)).
:- meta_predicate(phrase_to_file(2, ?, ?)). :- meta_predicate(phrase_to_file(2, ?, ?)).
:- meta_predicate(phrase_to_stream(2, ?)). :- meta_predicate(phrase_to_stream(2, ?)).
%% phrase_from_stream(+GRBody, +Stream)
%
% True if grammar rule body GRBody covers the contents of the stream,
% represented as a list of characters.
phrase_from_stream(GRBody, Stream) :-
stream_to_lazy_list(Stream, Ls),
phrase(GRBody, Ls).
%% phrase_from_file(+GRBody, +File) %% phrase_from_file(+GRBody, +File)
% %
% True if grammar rule body GRBody covers the contents of File, % True if grammar rule body GRBody covers the contents of File,
@@ -48,25 +63,121 @@ phrase_from_file(NT, File, Options) :-
member(Type, [text,binary]) member(Type, [text,binary])
; Type = text ; Type = text
), ),
setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]), setup_call_cleanup(
( stream_to_lazy_list(Stream, Xs), open(File, read, Stream, Options),
phrase(NT, Xs) ), phrase_from_stream(NT, Stream),
close(Stream)) close(Stream)
). )
).
% How many chars to read from stream and buffer in each step
chars_to_read(4096).
stream_to_lazy_list(Stream, Xs) :- stream_to_lazy_list(Stream, Ls) :-
stream_property(Stream, position(Pos)), get_stream_buffer_position(Stream, Pos),
freeze(Xs, reader_step(Stream, Pos, Xs)). freeze(Ls, render_step(Stream, Pos, Ls)).
reader_step(Stream, Pos, Xs0) :- render_step(Stream, Pos, Ls) :-
set_stream_position(Stream, Pos), set_stream_buffer_position(Stream, Pos),
( at_end_of_stream(Stream) ( buffer_at_end_of_stream(Stream) ->
-> Xs0 = [] Ls = []
; get_n_chars(Stream, 4096, Cs), ; chars_to_read(CharsToRead),
partial_string(Cs, Xs0, Xs), buffer_get_n_chars(Stream, CharsToRead, Chars),
stream_to_lazy_list(Stream, Xs) partial_string(Chars, Ls, Ls0),
). stream_to_lazy_list(Stream, Ls0)
).
buffer_at_end_of_stream(Stream) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_get(BufferPosId, Pos),
Pos = eof.
get_stream_buffer_position(Stream, Pos) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_get(BufferPosId, Pos).
set_stream_buffer_position(Stream, Pos) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_put(BufferPosId, Pos).
buffer_get_n_chars(Stream, N, Chars) :-
stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId),
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N),
bb_get(BufferId, Buffer),
bb_get(BufferPosId, BufferPos),
( BufferPos = eof ->
Chars = []
; string_get_n_chars(Buffer, BufferPos, N, Chars),
length(Chars, NChars),
( NChars = 0 ->
BufferPos1 = eof
; BufferPos1 is BufferPos + NChars
),
bb_put(BufferPosId, BufferPos1)
).
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N) :-
bb_get(BufferPosId, BufferPos),
bb_get(BufferLenId, BufferLen),
( BufferLen < BufferPos + N ->
bb_get(BufferId, Buffer),
(
( var(Buffer) ->
BufferTail = Buffer
; partial_string_last_tail(Buffer, BufferTail)
) ->
( at_end_of_stream(Stream) ->
BufferTail = [],
bb_put(BufferId, Buffer)
; chars_to_read(CharsToRead),
get_n_chars(Stream, CharsToRead, Chars),
length(Chars, NChars),
partial_string(Chars, BufferTail, _),
bb_put(BufferId, Buffer),
BufferLen1 is BufferLen + NChars,
bb_put(BufferLenId, BufferLen1),
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N)
)
; true
)
; true
).
partial_string_last_tail(PartialString, PartialStringTail) :-
partial_string_tail(PartialString, PartialStringTail0),
( var(PartialStringTail0) ->
PartialStringTail = PartialStringTail0
; partial_string_last_tail(PartialStringTail0, PartialStringTail)
).
string_get_n_chars(String, Pos, N, Chars) :-
'$skip_max_list'(_, Pos, String, String1),
'$skip_max_list'(N1, N, String1, _),
length(Chars, N1),
append(Chars, _, String1).
stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId) :-
( bb_get(streams_buffers, _) ->
true
; bb_put(streams_buffers, [])
),
bb_get(streams_buffers, StreamsBuffers),
( member(
stream_buffer(Stream, BufferId, BufferPosId, BufferLenId),
StreamsBuffers
) ->
true
; gensym(buffer, BufferId),
gensym(buffer_pos, BufferPosId),
gensym(buffer_len, BufferLenId),
bb_put(
streams_buffers,
[stream_buffer(Stream, BufferId, BufferPosId, BufferLenId)|StreamsBuffers]
),
bb_put(BufferId, _),
bb_put(BufferPosId, 0),
bb_put(BufferLenId, 0)
).
%% phrase_to_stream(+GRBody, +Stream) %% phrase_to_stream(+GRBody, +Stream)
% %

View File

@@ -35,9 +35,9 @@ write_error(Error) :-
), ),
write('.'). write('.').
% '$print_message_and_fail'(inference_limit_exceeded(B)) :-
% integer(B), :- non_counted_backtracking '$print_message_and_fail'/1.
% throw(inference_limit_exceeded(B)).
'$print_message_and_fail'(Error) :- '$print_message_and_fail'(Error) :-
write_error(Error), write_error(Error),
nl, nl,
@@ -70,6 +70,8 @@ term_expansion_list([Term|Terms], ExpandedTermsHead, ExpandedTermsTail) :-
). ).
:- non_counted_backtracking goal_expansion/3.
goal_expansion(Goal, Module, ExpandedGoal) :- goal_expansion(Goal, Module, ExpandedGoal) :-
( atom(Module), ( atom(Module),
'$predicate_defined'(Module, goal_expansion, 2), '$predicate_defined'(Module, goal_expansion, 2),
@@ -84,7 +86,6 @@ goal_expansion(Goal, Module, ExpandedGoal) :-
). ).
create_file_load_context(Stream, Path, Evacuable) :- create_file_load_context(Stream, Path, Evacuable) :-
'$push_load_context'(Stream, Path), '$push_load_context'(Stream, Path),
'$push_load_state_payload'(Evacuable). '$push_load_state_payload'(Evacuable).
@@ -134,9 +135,15 @@ file_load_init(Stream, Evacuable) :-
run_initialization_goals. run_initialization_goals.
file_load_cleanup(Evacuable, Error) :- file_load_cleanup(Evacuable, Error) :-
load_context(Module),
abolish(Module:'$initialization_goals'/1),
unload_evacuable(Evacuable), unload_evacuable(Evacuable),
'$print_message_and_fail'(Error), ( clause('$toplevel':argv(_), _) ->
throw(Error). % let the toplevel call loader:write_error/1
throw(Error)
; '$print_message_and_fail'(Error)
; throw(file_load_error)
).
file_load(Stream, Path, Evacuable) :- file_load(Stream, Path, Evacuable) :-
create_file_load_context(Stream, Path, Evacuable), create_file_load_context(Stream, Path, Evacuable),
@@ -373,6 +380,59 @@ remove_module(Module, Evacuable) :-
). ).
predicate_indicator(PI) :-
( var(PI) ->
throw(error(instantiation_error, _))
; PI = Name/Arity,
must_be(atom, Name),
must_be(integer, Arity),
Arity >= 0
).
predicate_indicator_sequence(PI_Seq) :-
( var(PI_Seq) ->
throw(error(instantiation_error, load/1))
; PI_Seq = (PI, PIs),
predicate_indicator(PI),
( predicate_indicator(PIs) ->
true
; predicate_indicator_sequence(PIs)
)
).
:- meta_predicate add_predicate_declaration(3, ?).
add_predicate_declaration(Handler, Name/Arity) :-
predicate_indicator(Name/Arity),
prolog_load_context(module, Module),
call(Handler, Module, Name, Arity).
add_predicate_declaration(Handler, Module:Name/Arity) :-
must_be(atom, Module),
predicate_indicator(Name/Arity),
call(Handler, Module, Name, Arity).
add_predicate_declaration(Handler, [PI|PIs]) :-
'$skip_max_list'(_, _, PIs, Tail),
( Tail == [],
maplist(loader:predicate_indicator, PIs) ->
maplist(loader:add_predicate_declaration(Handler), [PI|PIs])
; throw(error(type_error(predicate_indicator_list, [PI|PIs]), load/1))
).
add_predicate_declaration(Handler, (PI, PIs)) :-
( predicate_indicator_sequence((PI, PIs)) ->
add_predicate_declaration(Handler, PI),
add_predicate_declaration(Handler, PIs)
; throw(error(type_error(predicate_indicator_sequence, (PI, PIs)), load/1))
).
add_dynamic_predicate(Evacuable, Module, Name, Arity) :-
'$add_dynamic_predicate'(Module, Name, Arity, Evacuable).
add_multifile_predicate(Evacuable, Module, Name, Arity) :-
'$add_multifile_predicate'(Module, Name, Arity, Evacuable).
add_discontiguous_predicate(Evacuable, Module, Name, Arity) :-
'$add_discontiguous_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(use_module(Module), Evacuable) :- compile_declaration(use_module(Module), Evacuable) :-
use_module(Module, [], Evacuable). use_module(Module, [], Evacuable).
compile_declaration(use_module(Module, Exports), Evacuable) :- compile_declaration(use_module(Module, Exports), Evacuable) :-
@@ -385,39 +445,12 @@ compile_declaration(module(Module, Exports), Evacuable) :-
'$declare_module'(Module, Exports, Evacuable) '$declare_module'(Module, Exports, Evacuable)
; type_error(atom, Module, load/1) ; type_error(atom, Module, load/1)
). ).
compile_declaration(dynamic(Module:Name/Arity), Evacuable) :- compile_declaration(dynamic(PIs), Evacuable) :-
!, add_predicate_declaration(loader:add_dynamic_predicate(Evacuable), PIs).
must_be(atom, Module), compile_declaration(multifile(PIs), Evacuable) :-
must_be(atom, Name), add_predicate_declaration(loader:add_multifile_predicate(Evacuable), PIs).
must_be(integer, Arity), compile_declaration(discontiguous(PIs), Evacuable) :-
'$add_dynamic_predicate'(Module, Name, Arity, Evacuable). add_predicate_declaration(loader:add_discontiguous_predicate(Evacuable), PIs).
compile_declaration(dynamic(Name/Arity), Evacuable) :-
must_be(atom, Name),
must_be(integer, Arity),
prolog_load_context(module, Module),
'$add_dynamic_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(multifile(Module:Name/Arity), Evacuable) :-
!,
must_be(atom, Module),
must_be(atom, Name),
must_be(integer, Arity),
'$add_multifile_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(multifile(Name/Arity), Evacuable) :-
must_be(atom, Name),
must_be(integer, Arity),
prolog_load_context(module, Module),
'$add_multifile_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(discontiguous(Module:Name/Arity), Evacuable) :-
!,
must_be(atom, Module),
must_be(atom, Name),
must_be(integer, Arity),
'$add_discontiguous_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(discontiguous(Name/Arity), Evacuable) :-
must_be(atom, Name),
must_be(integer, Arity),
prolog_load_context(module, Module),
'$add_discontiguous_predicate'(Module, Name, Arity, Evacuable).
compile_declaration(initialization(Goal), Evacuable) :- compile_declaration(initialization(Goal), Evacuable) :-
prolog_load_context(module, Module), prolog_load_context(module, Module),
assertz(Module:'$initialization_goals'(Goal)). assertz(Module:'$initialization_goals'(Goal)).
@@ -504,7 +537,9 @@ consult(Item) :-
use_module(Module) :- use_module(Module) :-
'$push_load_state_payload'(Evacuable), '$push_load_state_payload'(Evacuable),
use_module(Module, [], Evacuable). catch('$call'(loader:use_module(Module, [], Evacuable)),
file_load_error,
'$call'(builtins:false)).
use_module(Module, Exports) :- use_module(Module, Exports) :-
'$push_load_state_payload'(Evacuable), '$push_load_state_payload'(Evacuable),
@@ -586,6 +621,12 @@ use_module(Module, Exports, Evacuable) :-
) )
). ).
consult_stream(Stream, PathFileName) :-
'$push_load_state_payload'(Evacuable),
file_load(Stream, PathFileName, Subevacuable),
'$use_module'(Evacuable, Subevacuable, _).
:- non_counted_backtracking check_predicate_property/5.
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :- check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
'$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
@@ -599,6 +640,7 @@ check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
'$discontiguous_property'(Module, Name, Arity). '$discontiguous_property'(Module, Name, Arity).
:- non_counted_backtracking extract_predicate_property/2.
extract_predicate_property(Property, PropertyType) :- extract_predicate_property(Property, PropertyType) :-
( var(Property) -> ( var(Property) ->
@@ -606,12 +648,16 @@ extract_predicate_property(Property, PropertyType) :-
; functor(Property, PropertyType, _) ; functor(Property, PropertyType, _)
). ).
:- non_counted_backtracking load_context/1.
load_context(Module) :- load_context(Module) :-
( prolog_load_context(module, Module) -> ( prolog_load_context(module, Module) ->
true true
; Module = user ; Module = user
). ).
:- non_counted_backtracking predicate_property/2.
predicate_property(Callable, Property) :- predicate_property(Callable, Property) :-
( var(Callable) -> ( var(Callable) ->
instantiation_error(predicate_property/2) instantiation_error(predicate_property/2)
@@ -648,8 +694,6 @@ strip_subst_module(Goal, M1, M2, G) :-
; true ; true
). ).
:- non_counted_backtracking subgoal_expansion/3.
/* /*
* subgoal_expansion differs from goal_expansion only in that it fails * subgoal_expansion differs from goal_expansion only in that it fails
* unconditionally after catching an(y) exception, aborting the * unconditionally after catching an(y) exception, aborting the
@@ -657,10 +701,14 @@ strip_subst_module(Goal, M1, M2, G) :-
* when expand_goal is later invoked at runtime. * when expand_goal is later invoked at runtime.
*/ */
:- non_counted_backtracking subgoal_expansion_fail/1.
subgoal_expansion_fail(B) :- subgoal_expansion_fail(B) :-
builtins:set_cp(B), builtins:set_cp(B),
fail. fail.
:- non_counted_backtracking subgoal_expansion/3.
subgoal_expansion(Goal, Module, ExpandedGoal) :- subgoal_expansion(Goal, Module, ExpandedGoal) :-
'$get_cp'(B), '$get_cp'(B),
( atom(Module), ( atom(Module),
@@ -695,7 +743,7 @@ expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :-
expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars) expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars)
; ExpandedGoals0 = UnexpandedGoals4 ; ExpandedGoals0 = UnexpandedGoals4
), ),
'$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1), '$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1, UnexpandedGoals0),
expand_module_name(ExpandedGoals1, MS, Module1, ExpandedGoals). expand_module_name(ExpandedGoals1, MS, Module1, ExpandedGoals).
@@ -890,7 +938,6 @@ thread_goals(Goals0, Goals1, Hole, Functor) :-
% n_call_clause(N, Clauses) :- % n_call_clause(N, Clauses) :-
% length(Args, N), % length(Args, N),
% Head =.. [call, G | Args], % Head =.. [call, G | Args],
% CallNHead =.. [call, '$call'(G) | Args],
% N1 is N + 1, % N1 is N + 1,
% StripModule =.. ['$strip_module', G, M1, G1], % StripModule =.. ['$strip_module', G, M1, G1],
% FastCall =.. ['$fast_call', G | Args], % FastCall =.. ['$fast_call', G | Args],
@@ -903,7 +950,7 @@ thread_goals(Goals0, Goals1, Hole, Functor) :-
% PrepareCallClause, % PrepareCallClause,
% expand_call_goal(G2, M1, G3), % expand_call_goal(G2, M1, G3),
% strip_subst_module(G3, M1, M2, G4), % strip_subst_module(G3, M1, M2, G4),
% '$call_with_inference_counting'(ModuleCall))]. % ModuleCall)].
% %
% generate_call_forms :- % generate_call_forms :-
% between(1, 64, N), % between(1, 64, N),
@@ -930,7 +977,7 @@ call(G0) :-
'$strip_module'(G0, M0, G1), '$strip_module'(G0, M0, G1),
expand_call_goal(G1, M0, G2), expand_call_goal(G1, M0, G2),
strip_subst_module(G2, M0, M1, G3), strip_subst_module(G2, M0, M1, G3),
'$call_with_inference_counting'('$module_call'(M1, G3)). '$module_call'(M1, G3).
:-non_counted_backtracking call/2. :-non_counted_backtracking call/2.
call(A,B) :- call(A,B) :-
@@ -943,7 +990,7 @@ call(A,B) :-
'$prepare_call_clause'(E,D,B), '$prepare_call_clause'(E,D,B),
expand_call_goal(E,C,F), expand_call_goal(E,C,F),
strip_subst_module(F,C,G,H), strip_subst_module(F,C,G,H),
'$call_with_inference_counting'('$module_call'(G,H)). '$module_call'(G,H).
:-non_counted_backtracking call/3. :-non_counted_backtracking call/3.
call(A,B,C) :- call(A,B,C) :-
@@ -956,7 +1003,7 @@ call(A,B,C) :-
'$prepare_call_clause'(F,E,B,C), '$prepare_call_clause'(F,E,B,C),
expand_call_goal(F,D,G), expand_call_goal(F,D,G),
strip_subst_module(G,D,H,I), strip_subst_module(G,D,H,I),
'$call_with_inference_counting'('$module_call'(H,I)). '$module_call'(H,I).
:-non_counted_backtracking call/4. :-non_counted_backtracking call/4.
call(A,B,C,D) :- call(A,B,C,D) :-
@@ -969,7 +1016,7 @@ call(A,B,C,D) :-
'$prepare_call_clause'(G,F,B,C,D), '$prepare_call_clause'(G,F,B,C,D),
expand_call_goal(G,E,H), expand_call_goal(G,E,H),
strip_subst_module(H,E,I,J), strip_subst_module(H,E,I,J),
'$call_with_inference_counting'('$module_call'(I,J)). '$module_call'(I,J).
:-non_counted_backtracking call/5. :-non_counted_backtracking call/5.
call(A,B,C,D,E) :- call(A,B,C,D,E) :-
@@ -982,7 +1029,7 @@ call(A,B,C,D,E) :-
'$prepare_call_clause'(H,G,B,C,D,E), '$prepare_call_clause'(H,G,B,C,D,E),
expand_call_goal(H,F,I), expand_call_goal(H,F,I),
strip_subst_module(I,F,J,K), strip_subst_module(I,F,J,K),
'$call_with_inference_counting'('$module_call'(J,K)). '$module_call'(J,K).
:-non_counted_backtracking call/6. :-non_counted_backtracking call/6.
call(A,B,C,D,E,F) :- call(A,B,C,D,E,F) :-
@@ -995,7 +1042,7 @@ call(A,B,C,D,E,F) :-
'$prepare_call_clause'(I,H,B,C,D,E,F), '$prepare_call_clause'(I,H,B,C,D,E,F),
expand_call_goal(I,G,J), expand_call_goal(I,G,J),
strip_subst_module(J,G,K,L), strip_subst_module(J,G,K,L),
'$call_with_inference_counting'('$module_call'(K,L)). '$module_call'(K,L).
:-non_counted_backtracking call/7. :-non_counted_backtracking call/7.
call(A,B,C,D,E,F,G) :- call(A,B,C,D,E,F,G) :-
@@ -1008,7 +1055,7 @@ call(A,B,C,D,E,F,G) :-
'$prepare_call_clause'(J,I,B,C,D,E,F,G), '$prepare_call_clause'(J,I,B,C,D,E,F,G),
expand_call_goal(J,H,K), expand_call_goal(J,H,K),
strip_subst_module(K,H,L,M), strip_subst_module(K,H,L,M),
'$call_with_inference_counting'('$module_call'(L,M)). '$module_call'(L,M).
:-non_counted_backtracking call/8. :-non_counted_backtracking call/8.
call(A,B,C,D,E,F,G,H) :- call(A,B,C,D,E,F,G,H) :-
@@ -1021,7 +1068,7 @@ call(A,B,C,D,E,F,G,H) :-
'$prepare_call_clause'(K,J,B,C,D,E,F,G,H), '$prepare_call_clause'(K,J,B,C,D,E,F,G,H),
expand_call_goal(K,I,L), expand_call_goal(K,I,L),
strip_subst_module(L,I,M,N), strip_subst_module(L,I,M,N),
'$call_with_inference_counting'('$module_call'(M,N)). '$module_call'(M,N).
:-non_counted_backtracking call/9. :-non_counted_backtracking call/9.
call(A,B,C,D,E,F,G,H,I) :- call(A,B,C,D,E,F,G,H,I) :-
@@ -1034,7 +1081,7 @@ call(A,B,C,D,E,F,G,H,I) :-
'$prepare_call_clause'(L,K,B,C,D,E,F,G,H,I), '$prepare_call_clause'(L,K,B,C,D,E,F,G,H,I),
expand_call_goal(L,J,M), expand_call_goal(L,J,M),
strip_subst_module(M,J,N,O), strip_subst_module(M,J,N,O),
'$call_with_inference_counting'('$module_call'(N,O)). '$module_call'(N,O).
:-non_counted_backtracking call/10. :-non_counted_backtracking call/10.
call(A,B,C,D,E,F,G,H,I,J) :- call(A,B,C,D,E,F,G,H,I,J) :-
@@ -1047,7 +1094,7 @@ call(A,B,C,D,E,F,G,H,I,J) :-
'$prepare_call_clause'(M,L,B,C,D,E,F,G,H,I,J), '$prepare_call_clause'(M,L,B,C,D,E,F,G,H,I,J),
expand_call_goal(M,K,N), expand_call_goal(M,K,N),
strip_subst_module(N,K,O,P), strip_subst_module(N,K,O,P),
'$call_with_inference_counting'('$module_call'(O,P)). '$module_call'(O,P).
:-non_counted_backtracking call/11. :-non_counted_backtracking call/11.
call(A,B,C,D,E,F,G,H,I,J,K) :- call(A,B,C,D,E,F,G,H,I,J,K) :-
@@ -1060,7 +1107,7 @@ call(A,B,C,D,E,F,G,H,I,J,K) :-
'$prepare_call_clause'(N,M,B,C,D,E,F,G,H,I,J,K), '$prepare_call_clause'(N,M,B,C,D,E,F,G,H,I,J,K),
expand_call_goal(N,L,O), expand_call_goal(N,L,O),
strip_subst_module(O,L,P,Q), strip_subst_module(O,L,P,Q),
'$call_with_inference_counting'('$module_call'(P,Q)). '$module_call'(P,Q).
:-non_counted_backtracking call/12. :-non_counted_backtracking call/12.
call(A,B,C,D,E,F,G,H,I,J,K,L) :- call(A,B,C,D,E,F,G,H,I,J,K,L) :-
@@ -1073,7 +1120,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L) :-
'$prepare_call_clause'(O,N,B,C,D,E,F,G,H,I,J,K,L), '$prepare_call_clause'(O,N,B,C,D,E,F,G,H,I,J,K,L),
expand_call_goal(O,M,P), expand_call_goal(O,M,P),
strip_subst_module(P,M,Q,R), strip_subst_module(P,M,Q,R),
'$call_with_inference_counting'('$module_call'(Q,R)). '$module_call'(Q,R).
:-non_counted_backtracking call/13. :-non_counted_backtracking call/13.
call(A,B,C,D,E,F,G,H,I,J,K,L,M) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M) :-
@@ -1086,7 +1133,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M) :-
'$prepare_call_clause'(P,O,B,C,D,E,F,G,H,I,J,K,L,M), '$prepare_call_clause'(P,O,B,C,D,E,F,G,H,I,J,K,L,M),
expand_call_goal(P,N,Q), expand_call_goal(P,N,Q),
strip_subst_module(Q,N,R,S), strip_subst_module(Q,N,R,S),
'$call_with_inference_counting'('$module_call'(R,S)). '$module_call'(R,S).
:-non_counted_backtracking call/14. :-non_counted_backtracking call/14.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N) :-
@@ -1099,7 +1146,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N) :-
'$prepare_call_clause'(Q,P,B,C,D,E,F,G,H,I,J,K,L,M,N), '$prepare_call_clause'(Q,P,B,C,D,E,F,G,H,I,J,K,L,M,N),
expand_call_goal(Q,O,R), expand_call_goal(Q,O,R),
strip_subst_module(R,O,S,T), strip_subst_module(R,O,S,T),
'$call_with_inference_counting'('$module_call'(S,T)). '$module_call'(S,T).
:-non_counted_backtracking call/15. :-non_counted_backtracking call/15.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) :-
@@ -1112,7 +1159,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) :-
'$prepare_call_clause'(R,Q,B,C,D,E,F,G,H,I,J,K,L,M,N,O), '$prepare_call_clause'(R,Q,B,C,D,E,F,G,H,I,J,K,L,M,N,O),
expand_call_goal(R,P,S), expand_call_goal(R,P,S),
strip_subst_module(S,P,T,U), strip_subst_module(S,P,T,U),
'$call_with_inference_counting'('$module_call'(T,U)). '$module_call'(T,U).
:-non_counted_backtracking call/16. :-non_counted_backtracking call/16.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) :-
@@ -1125,7 +1172,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) :-
'$prepare_call_clause'(S,R,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P), '$prepare_call_clause'(S,R,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P),
expand_call_goal(S,Q,T), expand_call_goal(S,Q,T),
strip_subst_module(T,Q,U,V), strip_subst_module(T,Q,U,V),
'$call_with_inference_counting'('$module_call'(U,V)). '$module_call'(U,V).
:-non_counted_backtracking call/17. :-non_counted_backtracking call/17.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) :-
@@ -1138,7 +1185,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) :-
'$prepare_call_clause'(T,S,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q), '$prepare_call_clause'(T,S,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q),
expand_call_goal(T,R,U), expand_call_goal(T,R,U),
strip_subst_module(U,R,V,W), strip_subst_module(U,R,V,W),
'$call_with_inference_counting'('$module_call'(V,W)). '$module_call'(V,W).
:-non_counted_backtracking call/18. :-non_counted_backtracking call/18.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) :-
@@ -1151,7 +1198,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) :-
'$prepare_call_clause'(U,T,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R), '$prepare_call_clause'(U,T,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R),
expand_call_goal(U,S,V), expand_call_goal(U,S,V),
strip_subst_module(V,S,W,X), strip_subst_module(V,S,W,X),
'$call_with_inference_counting'('$module_call'(W,X)). '$module_call'(W,X).
:-non_counted_backtracking call/19. :-non_counted_backtracking call/19.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) :-
@@ -1164,7 +1211,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) :-
'$prepare_call_clause'(V,U,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S), '$prepare_call_clause'(V,U,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S),
expand_call_goal(V,T,W), expand_call_goal(V,T,W),
strip_subst_module(W,T,X,Y), strip_subst_module(W,T,X,Y),
'$call_with_inference_counting'('$module_call'(X,Y)). '$module_call'(X,Y).
:-non_counted_backtracking call/20. :-non_counted_backtracking call/20.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) :-
@@ -1177,7 +1224,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) :-
'$prepare_call_clause'(W,V,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T), '$prepare_call_clause'(W,V,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T),
expand_call_goal(W,U,X), expand_call_goal(W,U,X),
strip_subst_module(X,U,Y,Z), strip_subst_module(X,U,Y,Z),
'$call_with_inference_counting'('$module_call'(Y,Z)). '$module_call'(Y,Z).
:-non_counted_backtracking call/21. :-non_counted_backtracking call/21.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) :-
@@ -1190,7 +1237,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) :-
'$prepare_call_clause'(X,W,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U), '$prepare_call_clause'(X,W,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U),
expand_call_goal(X,V,Y), expand_call_goal(X,V,Y),
strip_subst_module(Y,V,Z,A1), strip_subst_module(Y,V,Z,A1),
'$call_with_inference_counting'('$module_call'(Z,A1)). '$module_call'(Z,A1).
:-non_counted_backtracking call/22. :-non_counted_backtracking call/22.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V) :-
@@ -1203,7 +1250,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V) :-
'$prepare_call_clause'(Y,X,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V), '$prepare_call_clause'(Y,X,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V),
expand_call_goal(Y,W,Z), expand_call_goal(Y,W,Z),
strip_subst_module(Z,W,A1,B1), strip_subst_module(Z,W,A1,B1),
'$call_with_inference_counting'('$module_call'(A1,B1)). '$module_call'(A1,B1).
:-non_counted_backtracking call/23. :-non_counted_backtracking call/23.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W) :-
@@ -1216,7 +1263,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W) :-
'$prepare_call_clause'(Z,Y,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W), '$prepare_call_clause'(Z,Y,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W),
expand_call_goal(Z,X,A1), expand_call_goal(Z,X,A1),
strip_subst_module(A1,X,B1,C1), strip_subst_module(A1,X,B1,C1),
'$call_with_inference_counting'('$module_call'(B1,C1)). '$module_call'(B1,C1).
:-non_counted_backtracking call/24. :-non_counted_backtracking call/24.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X) :-
@@ -1229,7 +1276,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X) :-
'$prepare_call_clause'(A1,Z,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X), '$prepare_call_clause'(A1,Z,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X),
expand_call_goal(A1,Y,B1), expand_call_goal(A1,Y,B1),
strip_subst_module(B1,Y,C1,D1), strip_subst_module(B1,Y,C1,D1),
'$call_with_inference_counting'('$module_call'(C1,D1)). '$module_call'(C1,D1).
:-non_counted_backtracking call/25. :-non_counted_backtracking call/25.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y) :-
@@ -1242,7 +1289,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y) :-
'$prepare_call_clause'(B1,A1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y), '$prepare_call_clause'(B1,A1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y),
expand_call_goal(B1,Z,C1), expand_call_goal(B1,Z,C1),
strip_subst_module(C1,Z,D1,E1), strip_subst_module(C1,Z,D1,E1),
'$call_with_inference_counting'('$module_call'(D1,E1)). '$module_call'(D1,E1).
:-non_counted_backtracking call/26. :-non_counted_backtracking call/26.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z) :-
@@ -1255,7 +1302,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z) :-
'$prepare_call_clause'(C1,B1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z), '$prepare_call_clause'(C1,B1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z),
expand_call_goal(C1,A1,D1), expand_call_goal(C1,A1,D1),
strip_subst_module(D1,A1,E1,F1), strip_subst_module(D1,A1,E1,F1),
'$call_with_inference_counting'('$module_call'(E1,F1)). '$module_call'(E1,F1).
:-non_counted_backtracking call/27. :-non_counted_backtracking call/27.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1) :-
@@ -1268,7 +1315,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1) :-
'$prepare_call_clause'(D1,C1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1), '$prepare_call_clause'(D1,C1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1),
expand_call_goal(D1,B1,E1), expand_call_goal(D1,B1,E1),
strip_subst_module(E1,B1,F1,G1), strip_subst_module(E1,B1,F1,G1),
'$call_with_inference_counting'('$module_call'(F1,G1)). '$module_call'(F1,G1).
:-non_counted_backtracking call/28. :-non_counted_backtracking call/28.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1) :-
@@ -1281,7 +1328,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1) :-
'$prepare_call_clause'(E1,D1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1), '$prepare_call_clause'(E1,D1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1),
expand_call_goal(E1,C1,F1), expand_call_goal(E1,C1,F1),
strip_subst_module(F1,C1,G1,H1), strip_subst_module(F1,C1,G1,H1),
'$call_with_inference_counting'('$module_call'(G1,H1)). '$module_call'(G1,H1).
:-non_counted_backtracking call/29. :-non_counted_backtracking call/29.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1) :-
@@ -1294,7 +1341,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1) :-
'$prepare_call_clause'(F1,E1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1), '$prepare_call_clause'(F1,E1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1),
expand_call_goal(F1,D1,G1), expand_call_goal(F1,D1,G1),
strip_subst_module(G1,D1,H1,I1), strip_subst_module(G1,D1,H1,I1),
'$call_with_inference_counting'('$module_call'(H1,I1)). '$module_call'(H1,I1).
:-non_counted_backtracking call/30. :-non_counted_backtracking call/30.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1) :-
@@ -1307,7 +1354,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1) :-
'$prepare_call_clause'(G1,F1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1), '$prepare_call_clause'(G1,F1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1),
expand_call_goal(G1,E1,H1), expand_call_goal(G1,E1,H1),
strip_subst_module(H1,E1,I1,J1), strip_subst_module(H1,E1,I1,J1),
'$call_with_inference_counting'('$module_call'(I1,J1)). '$module_call'(I1,J1).
:-non_counted_backtracking call/31. :-non_counted_backtracking call/31.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1) :-
@@ -1320,7 +1367,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1) :-
'$prepare_call_clause'(H1,G1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1), '$prepare_call_clause'(H1,G1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1),
expand_call_goal(H1,F1,I1), expand_call_goal(H1,F1,I1),
strip_subst_module(I1,F1,J1,K1), strip_subst_module(I1,F1,J1,K1),
'$call_with_inference_counting'('$module_call'(J1,K1)). '$module_call'(J1,K1).
:-non_counted_backtracking call/32. :-non_counted_backtracking call/32.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1) :-
@@ -1333,7 +1380,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1) :-
'$prepare_call_clause'(I1,H1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1), '$prepare_call_clause'(I1,H1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1),
expand_call_goal(I1,G1,J1), expand_call_goal(I1,G1,J1),
strip_subst_module(J1,G1,K1,L1), strip_subst_module(J1,G1,K1,L1),
'$call_with_inference_counting'('$module_call'(K1,L1)). '$module_call'(K1,L1).
:-non_counted_backtracking call/33. :-non_counted_backtracking call/33.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1) :-
@@ -1346,7 +1393,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1) :
'$prepare_call_clause'(J1,I1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1), '$prepare_call_clause'(J1,I1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1),
expand_call_goal(J1,H1,K1), expand_call_goal(J1,H1,K1),
strip_subst_module(K1,H1,L1,M1), strip_subst_module(K1,H1,L1,M1),
'$call_with_inference_counting'('$module_call'(L1,M1)). '$module_call'(L1,M1).
:-non_counted_backtracking call/34. :-non_counted_backtracking call/34.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1) :-
@@ -1359,7 +1406,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(K1,J1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1), '$prepare_call_clause'(K1,J1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1),
expand_call_goal(K1,I1,L1), expand_call_goal(K1,I1,L1),
strip_subst_module(L1,I1,M1,N1), strip_subst_module(L1,I1,M1,N1),
'$call_with_inference_counting'('$module_call'(M1,N1)). '$module_call'(M1,N1).
:-non_counted_backtracking call/35. :-non_counted_backtracking call/35.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1) :-
@@ -1372,7 +1419,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(L1,K1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1), '$prepare_call_clause'(L1,K1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1),
expand_call_goal(L1,J1,M1), expand_call_goal(L1,J1,M1),
strip_subst_module(M1,J1,N1,O1), strip_subst_module(M1,J1,N1,O1),
'$call_with_inference_counting'('$module_call'(N1,O1)). '$module_call'(N1,O1).
:-non_counted_backtracking call/36. :-non_counted_backtracking call/36.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1) :-
@@ -1385,7 +1432,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(M1,L1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1), '$prepare_call_clause'(M1,L1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1),
expand_call_goal(M1,K1,N1), expand_call_goal(M1,K1,N1),
strip_subst_module(N1,K1,O1,P1), strip_subst_module(N1,K1,O1,P1),
'$call_with_inference_counting'('$module_call'(O1,P1)). '$module_call'(O1,P1).
:-non_counted_backtracking call/37. :-non_counted_backtracking call/37.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1) :-
@@ -1398,7 +1445,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(N1,M1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1), '$prepare_call_clause'(N1,M1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1),
expand_call_goal(N1,L1,O1), expand_call_goal(N1,L1,O1),
strip_subst_module(O1,L1,P1,Q1), strip_subst_module(O1,L1,P1,Q1),
'$call_with_inference_counting'('$module_call'(P1,Q1)). '$module_call'(P1,Q1).
:-non_counted_backtracking call/38. :-non_counted_backtracking call/38.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1) :-
@@ -1411,7 +1458,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(O1,N1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1), '$prepare_call_clause'(O1,N1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1),
expand_call_goal(O1,M1,P1), expand_call_goal(O1,M1,P1),
strip_subst_module(P1,M1,Q1,R1), strip_subst_module(P1,M1,Q1,R1),
'$call_with_inference_counting'('$module_call'(Q1,R1)). '$module_call'(Q1,R1).
:-non_counted_backtracking call/39. :-non_counted_backtracking call/39.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1) :-
@@ -1424,7 +1471,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(P1,O1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1), '$prepare_call_clause'(P1,O1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1),
expand_call_goal(P1,N1,Q1), expand_call_goal(P1,N1,Q1),
strip_subst_module(Q1,N1,R1,S1), strip_subst_module(Q1,N1,R1,S1),
'$call_with_inference_counting'('$module_call'(R1,S1)). '$module_call'(R1,S1).
:-non_counted_backtracking call/40. :-non_counted_backtracking call/40.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1) :-
@@ -1437,7 +1484,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(Q1,P1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1), '$prepare_call_clause'(Q1,P1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1),
expand_call_goal(Q1,O1,R1), expand_call_goal(Q1,O1,R1),
strip_subst_module(R1,O1,S1,T1), strip_subst_module(R1,O1,S1,T1),
'$call_with_inference_counting'('$module_call'(S1,T1)). '$module_call'(S1,T1).
:-non_counted_backtracking call/41. :-non_counted_backtracking call/41.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1) :-
@@ -1450,7 +1497,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(R1,Q1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1), '$prepare_call_clause'(R1,Q1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1),
expand_call_goal(R1,P1,S1), expand_call_goal(R1,P1,S1),
strip_subst_module(S1,P1,T1,U1), strip_subst_module(S1,P1,T1,U1),
'$call_with_inference_counting'('$module_call'(T1,U1)). '$module_call'(T1,U1).
:-non_counted_backtracking call/42. :-non_counted_backtracking call/42.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1) :-
@@ -1463,7 +1510,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(S1,R1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1), '$prepare_call_clause'(S1,R1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1),
expand_call_goal(S1,Q1,T1), expand_call_goal(S1,Q1,T1),
strip_subst_module(T1,Q1,U1,V1), strip_subst_module(T1,Q1,U1,V1),
'$call_with_inference_counting'('$module_call'(U1,V1)). '$module_call'(U1,V1).
:-non_counted_backtracking call/43. :-non_counted_backtracking call/43.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1) :-
@@ -1476,7 +1523,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(T1,S1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1), '$prepare_call_clause'(T1,S1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1),
expand_call_goal(T1,R1,U1), expand_call_goal(T1,R1,U1),
strip_subst_module(U1,R1,V1,W1), strip_subst_module(U1,R1,V1,W1),
'$call_with_inference_counting'('$module_call'(V1,W1)). '$module_call'(V1,W1).
:-non_counted_backtracking call/44. :-non_counted_backtracking call/44.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1) :-
@@ -1489,7 +1536,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(U1,T1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1), '$prepare_call_clause'(U1,T1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1),
expand_call_goal(U1,S1,V1), expand_call_goal(U1,S1,V1),
strip_subst_module(V1,S1,W1,X1), strip_subst_module(V1,S1,W1,X1),
'$call_with_inference_counting'('$module_call'(W1,X1)). '$module_call'(W1,X1).
:-non_counted_backtracking call/45. :-non_counted_backtracking call/45.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1) :-
@@ -1502,7 +1549,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(V1,U1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1), '$prepare_call_clause'(V1,U1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1),
expand_call_goal(V1,T1,W1), expand_call_goal(V1,T1,W1),
strip_subst_module(W1,T1,X1,Y1), strip_subst_module(W1,T1,X1,Y1),
'$call_with_inference_counting'('$module_call'(X1,Y1)). '$module_call'(X1,Y1).
:-non_counted_backtracking call/46. :-non_counted_backtracking call/46.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1) :-
@@ -1515,7 +1562,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(W1,V1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1), '$prepare_call_clause'(W1,V1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1),
expand_call_goal(W1,U1,X1), expand_call_goal(W1,U1,X1),
strip_subst_module(X1,U1,Y1,Z1), strip_subst_module(X1,U1,Y1,Z1),
'$call_with_inference_counting'('$module_call'(Y1,Z1)). '$module_call'(Y1,Z1).
:-non_counted_backtracking call/47. :-non_counted_backtracking call/47.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1) :-
@@ -1528,7 +1575,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(X1,W1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1), '$prepare_call_clause'(X1,W1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1),
expand_call_goal(X1,V1,Y1), expand_call_goal(X1,V1,Y1),
strip_subst_module(Y1,V1,Z1,A2), strip_subst_module(Y1,V1,Z1,A2),
'$call_with_inference_counting'('$module_call'(Z1,A2)). '$module_call'(Z1,A2).
:-non_counted_backtracking call/48. :-non_counted_backtracking call/48.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1) :-
@@ -1541,7 +1588,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(Y1,X1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1), '$prepare_call_clause'(Y1,X1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1),
expand_call_goal(Y1,W1,Z1), expand_call_goal(Y1,W1,Z1),
strip_subst_module(Z1,W1,A2,B2), strip_subst_module(Z1,W1,A2,B2),
'$call_with_inference_counting'('$module_call'(A2,B2)). '$module_call'(A2,B2).
:-non_counted_backtracking call/49. :-non_counted_backtracking call/49.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1) :-
@@ -1554,7 +1601,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(Z1,Y1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1), '$prepare_call_clause'(Z1,Y1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1),
expand_call_goal(Z1,X1,A2), expand_call_goal(Z1,X1,A2),
strip_subst_module(A2,X1,B2,C2), strip_subst_module(A2,X1,B2,C2),
'$call_with_inference_counting'('$module_call'(B2,C2)). '$module_call'(B2,C2).
:-non_counted_backtracking call/50. :-non_counted_backtracking call/50.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1) :-
@@ -1567,7 +1614,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(A2,Z1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1), '$prepare_call_clause'(A2,Z1,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1),
expand_call_goal(A2,Y1,B2), expand_call_goal(A2,Y1,B2),
strip_subst_module(B2,Y1,C2,D2), strip_subst_module(B2,Y1,C2,D2),
'$call_with_inference_counting'('$module_call'(C2,D2)). '$module_call'(C2,D2).
:-non_counted_backtracking call/51. :-non_counted_backtracking call/51.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1) :-
@@ -1580,7 +1627,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(B2,A2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1), '$prepare_call_clause'(B2,A2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1),
expand_call_goal(B2,Z1,C2), expand_call_goal(B2,Z1,C2),
strip_subst_module(C2,Z1,D2,E2), strip_subst_module(C2,Z1,D2,E2),
'$call_with_inference_counting'('$module_call'(D2,E2)). '$module_call'(D2,E2).
:-non_counted_backtracking call/52. :-non_counted_backtracking call/52.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1) :-
@@ -1593,7 +1640,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(C2,B2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1), '$prepare_call_clause'(C2,B2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1),
expand_call_goal(C2,A2,D2), expand_call_goal(C2,A2,D2),
strip_subst_module(D2,A2,E2,F2), strip_subst_module(D2,A2,E2,F2),
'$call_with_inference_counting'('$module_call'(E2,F2)). '$module_call'(E2,F2).
:-non_counted_backtracking call/53. :-non_counted_backtracking call/53.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2) :-
@@ -1606,7 +1653,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(D2,C2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2), '$prepare_call_clause'(D2,C2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2),
expand_call_goal(D2,B2,E2), expand_call_goal(D2,B2,E2),
strip_subst_module(E2,B2,F2,G2), strip_subst_module(E2,B2,F2,G2),
'$call_with_inference_counting'('$module_call'(F2,G2)). '$module_call'(F2,G2).
:-non_counted_backtracking call/54. :-non_counted_backtracking call/54.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2) :-
@@ -1619,7 +1666,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(E2,D2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2), '$prepare_call_clause'(E2,D2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2),
expand_call_goal(E2,C2,F2), expand_call_goal(E2,C2,F2),
strip_subst_module(F2,C2,G2,H2), strip_subst_module(F2,C2,G2,H2),
'$call_with_inference_counting'('$module_call'(G2,H2)). '$module_call'(G2,H2).
:-non_counted_backtracking call/55. :-non_counted_backtracking call/55.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2) :-
@@ -1632,7 +1679,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(F2,E2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2), '$prepare_call_clause'(F2,E2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2),
expand_call_goal(F2,D2,G2), expand_call_goal(F2,D2,G2),
strip_subst_module(G2,D2,H2,I2), strip_subst_module(G2,D2,H2,I2),
'$call_with_inference_counting'('$module_call'(H2,I2)). '$module_call'(H2,I2).
:-non_counted_backtracking call/56. :-non_counted_backtracking call/56.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2) :-
@@ -1645,7 +1692,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(G2,F2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2), '$prepare_call_clause'(G2,F2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2),
expand_call_goal(G2,E2,H2), expand_call_goal(G2,E2,H2),
strip_subst_module(H2,E2,I2,J2), strip_subst_module(H2,E2,I2,J2),
'$call_with_inference_counting'('$module_call'(I2,J2)). '$module_call'(I2,J2).
:-non_counted_backtracking call/57. :-non_counted_backtracking call/57.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2) :-
@@ -1658,7 +1705,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(H2,G2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2), '$prepare_call_clause'(H2,G2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2),
expand_call_goal(H2,F2,I2), expand_call_goal(H2,F2,I2),
strip_subst_module(I2,F2,J2,K2), strip_subst_module(I2,F2,J2,K2),
'$call_with_inference_counting'('$module_call'(J2,K2)). '$module_call'(J2,K2).
:-non_counted_backtracking call/58. :-non_counted_backtracking call/58.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2) :-
@@ -1671,7 +1718,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(I2,H2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2), '$prepare_call_clause'(I2,H2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2),
expand_call_goal(I2,G2,J2), expand_call_goal(I2,G2,J2),
strip_subst_module(J2,G2,K2,L2), strip_subst_module(J2,G2,K2,L2),
'$call_with_inference_counting'('$module_call'(K2,L2)). '$module_call'(K2,L2).
:-non_counted_backtracking call/59. :-non_counted_backtracking call/59.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2) :-
@@ -1684,7 +1731,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(J2,I2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2), '$prepare_call_clause'(J2,I2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2),
expand_call_goal(J2,H2,K2), expand_call_goal(J2,H2,K2),
strip_subst_module(K2,H2,L2,M2), strip_subst_module(K2,H2,L2,M2),
'$call_with_inference_counting'('$module_call'(L2,M2)). '$module_call'(L2,M2).
:-non_counted_backtracking call/60. :-non_counted_backtracking call/60.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2) :-
@@ -1697,7 +1744,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(K2,J2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2), '$prepare_call_clause'(K2,J2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2),
expand_call_goal(K2,I2,L2), expand_call_goal(K2,I2,L2),
strip_subst_module(L2,I2,M2,N2), strip_subst_module(L2,I2,M2,N2),
'$call_with_inference_counting'('$module_call'(M2,N2)). '$module_call'(M2,N2).
:-non_counted_backtracking call/61. :-non_counted_backtracking call/61.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2) :-
@@ -1710,7 +1757,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(L2,K2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2), '$prepare_call_clause'(L2,K2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2),
expand_call_goal(L2,J2,M2), expand_call_goal(L2,J2,M2),
strip_subst_module(M2,J2,N2,O2), strip_subst_module(M2,J2,N2,O2),
'$call_with_inference_counting'('$module_call'(N2,O2)). '$module_call'(N2,O2).
:-non_counted_backtracking call/62. :-non_counted_backtracking call/62.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2) :-
@@ -1723,7 +1770,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(M2,L2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2), '$prepare_call_clause'(M2,L2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2),
expand_call_goal(M2,K2,N2), expand_call_goal(M2,K2,N2),
strip_subst_module(N2,K2,O2,P2), strip_subst_module(N2,K2,O2,P2),
'$call_with_inference_counting'('$module_call'(O2,P2)). '$module_call'(O2,P2).
:-non_counted_backtracking call/63. :-non_counted_backtracking call/63.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2) :-
@@ -1736,7 +1783,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(N2,M2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2), '$prepare_call_clause'(N2,M2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2),
expand_call_goal(N2,L2,O2), expand_call_goal(N2,L2,O2),
strip_subst_module(O2,L2,P2,Q2), strip_subst_module(O2,L2,P2,Q2),
'$call_with_inference_counting'('$module_call'(P2,Q2)). '$module_call'(P2,Q2).
:-non_counted_backtracking call/64. :-non_counted_backtracking call/64.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2) :-
@@ -1749,7 +1796,7 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(O2,N2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2), '$prepare_call_clause'(O2,N2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2),
expand_call_goal(O2,M2,P2), expand_call_goal(O2,M2,P2),
strip_subst_module(P2,M2,Q2,R2), strip_subst_module(P2,M2,Q2,R2),
'$call_with_inference_counting'('$module_call'(Q2,R2)). '$module_call'(Q2,R2).
:-non_counted_backtracking call/65. :-non_counted_backtracking call/65.
call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2) :- call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2) :-
@@ -1762,4 +1809,4 @@ call(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1
'$prepare_call_clause'(P2,O2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2), '$prepare_call_clause'(P2,O2,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2),
expand_call_goal(P2,N2,Q2), expand_call_goal(P2,N2,Q2),
strip_subst_module(Q2,N2,R2,S2), strip_subst_module(Q2,N2,R2,S2),
'$call_with_inference_counting'('$module_call'(R2,S2)). '$module_call'(R2,S2).

View File

@@ -1,7 +1,8 @@
use dashu::base::Abs; use dashu::base::{Abs, Gcd, Signed, UnsignedAbs};
use dashu::base::Gcd;
use dashu::integer::IBig; use dashu::integer::IBig;
use dashu::integer::fast_div::ConstDivisor;
use divrem::*; use divrem::*;
use num_order::NumOrd;
use crate::arena::*; use crate::arena::*;
use crate::arithmetic::*; use crate::arithmetic::*;
@@ -50,9 +51,7 @@ macro_rules! drop_iter_on_err {
}; };
} }
fn zero_divisor_eval_error( fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
stub_gen: impl Fn() -> FunctorStub + 'static,
) -> MachineStubGen {
Box::new(move |machine_st| { Box::new(move |machine_st| {
let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor); let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
let stub = stub_gen(); let stub = stub_gen();
@@ -61,9 +60,7 @@ fn zero_divisor_eval_error(
}) })
} }
fn undefined_eval_error( fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
stub_gen: impl Fn() -> FunctorStub + 'static,
) -> MachineStubGen {
Box::new(move |machine_st| { Box::new(move |machine_st| {
let eval_error = machine_st.evaluation_error(EvalError::Undefined); let eval_error = machine_st.evaluation_error(EvalError::Undefined);
let stub = stub_gen(); let stub = stub_gen();
@@ -169,9 +166,7 @@ pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
} }
(Number::Integer(n1), Number::Rational(n2)) (Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => { | (Number::Rational(n2), Number::Integer(n1)) => Ok(Number::arena_from(&*n1 + &*n2, arena)),
Ok(Number::arena_from(&*n1 + &*n2, arena))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
@@ -179,9 +174,7 @@ pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number,
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(add_f(f1, f2)?)) Ok(Number::Float(add_f(f1, f2)?))
} }
(Number::Rational(r1), Number::Rational(r2)) => { (Number::Rational(r1), Number::Rational(r2)) => Ok(Number::arena_from(&*r1 + &*r2, arena)),
Ok(Number::arena_from(&*r1 + &*r2, arena))
}
} }
} }
@@ -197,12 +190,12 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
Number::Integer(n) => { Number::Integer(n) => {
let n_clone: Integer = (*n).clone(); let n_clone: Integer = (*n).clone();
Number::arena_from(-Integer::from(n_clone), arena) Number::arena_from(-Integer::from(n_clone), arena)
}, }
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => { Number::Rational(r) => {
let r_clone: Rational = (*r).clone(); let r_clone: Rational = (*r).clone();
Number::arena_from(-Rational::from(r_clone), arena) Number::arena_from(-Rational::from(r_clone), arena)
}, }
} }
} }
@@ -219,12 +212,12 @@ pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
Number::Integer(n) => { Number::Integer(n) => {
let n_clone: Integer = (*n).clone(); let n_clone: Integer = (*n).clone();
Number::arena_from(Integer::from(n_clone.abs()), arena) Number::arena_from(Integer::from(n_clone.abs()), arena)
}, }
Number::Float(f) => Number::Float(f.abs()), Number::Float(f) => Number::Float(f.abs()),
Number::Rational(r) => { Number::Rational(r) => {
let r_clone: Rational = (*r).clone(); let r_clone: Rational = (*r).clone();
Number::arena_from(Rational::from(r_clone.abs()), arena) Number::arena_from(Rational::from(r_clone.abs()), arena)
}, }
} }
} }
@@ -368,7 +361,11 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
(Number::Integer(n1), Number::Fixnum(n2)) => { (Number::Integer(n1), Number::Fixnum(n2)) => {
let n2_i = n2.get_num(); let n2_i = n2.get_num();
if !(&*n1 == &Integer::from(1) || &*n1 == &Integer::from(0) || &*n1 == &Integer::from(-1)) && n2_i < 0 { if !(&*n1 == &Integer::from(1)
|| &*n1 == &Integer::from(0)
|| &*n1 == &Integer::from(-1))
&& n2_i < 0
{
let n = Number::Integer(n1); let n = Number::Integer(n1);
Err(numerical_type_error(ValidType::Float, n, stub_gen)) Err(numerical_type_error(ValidType::Float, n, stub_gen))
} else { } else {
@@ -377,7 +374,11 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
} }
} }
(Number::Integer(n1), Number::Integer(n2)) => { (Number::Integer(n1), Number::Integer(n2)) => {
if !(&*n1 == &Integer::from(1) || &*n1 == &Integer::from(0) || &*n1 == &Integer::from(-1)) && &*n2 < &Integer::from(0) { if !(&*n1 == &Integer::from(1)
|| &*n1 == &Integer::from(0)
|| &*n1 == &Integer::from(-1))
&& &*n2 < &Integer::from(0)
{
let n = Number::Integer(n1); let n = Number::Integer(n1);
Err(numerical_type_error(ValidType::Float, n, stub_gen)) Err(numerical_type_error(ValidType::Float, n, stub_gen))
} else { } else {
@@ -454,14 +455,14 @@ pub(crate) fn max(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if &*n2 > &n1.get_num() { if (&*n2).num_gt(&n1.get_num()) {
Ok(Number::Integer(n2)) Ok(Number::Integer(n2))
} else { } else {
Ok(Number::Fixnum(n1)) Ok(Number::Fixnum(n1))
} }
} }
(Number::Integer(n1), Number::Fixnum(n2)) => { (Number::Integer(n1), Number::Fixnum(n2)) => {
if &*n1 > &n2.get_num() { if (&*n1).num_gt(&n2.get_num()) {
Ok(Number::Integer(n1)) Ok(Number::Integer(n1))
} else { } else {
Ok(Number::Fixnum(n2)) Ok(Number::Fixnum(n2))
@@ -498,14 +499,14 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if &*n2 < &n1.get_num() { if (&*n2).num_lt(&n1.get_num()) {
Ok(Number::Integer(n2)) Ok(Number::Integer(n2))
} else { } else {
Ok(Number::Fixnum(n1)) Ok(Number::Fixnum(n1))
} }
} }
(Number::Integer(n1), Number::Fixnum(n2)) => { (Number::Integer(n1), Number::Fixnum(n2)) => {
if &*n1 < &n2.get_num() { if (&*n1).num_lt(&n2.get_num()) {
Ok(Number::Integer(n1)) Ok(Number::Integer(n1))
} else { } else {
Ok(Number::Fixnum(n2)) Ok(Number::Fixnum(n2))
@@ -552,7 +553,7 @@ pub fn rational_from_number(
Number::Integer(n) => { Number::Integer(n) => {
let n_clone: Integer = (*n).clone(); let n_clone: Integer = (*n).clone();
Ok(arena_alloc!(Rational::from(n_clone), arena)) Ok(arena_alloc!(Rational::from(n_clone), arena))
}, }
} }
} }
@@ -560,7 +561,7 @@ pub(crate) fn rdiv(
r1: TypedArenaPtr<Rational>, r1: TypedArenaPtr<Rational>,
r2: TypedArenaPtr<Rational>, r2: TypedArenaPtr<Rational>,
) -> Result<Rational, MachineStubGen> { ) -> Result<Rational, MachineStubGen> {
if &*r2 == &0 { if r2.is_zero() {
let stub_gen = || { let stub_gen = || {
let rdiv_atom = atom!("rdiv"); let rdiv_atom = atom!("rdiv");
functor_stub(rdiv_atom, 2) functor_stub(rdiv_atom, 2)
@@ -594,7 +595,7 @@ pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number,
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if &*n2 == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
Ok(Number::arena_from(Integer::from(n1) / &*n2, arena)) Ok(Number::arena_from(Integer::from(n1) / &*n2, arena))
@@ -608,13 +609,10 @@ pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number,
} }
} }
(Number::Integer(n1), Number::Integer(n2)) => { (Number::Integer(n1), Number::Integer(n2)) => {
if &*n2 == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
Ok(Number::arena_from( Ok(Number::arena_from(&*n1 / &*n2, arena))
<(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).0,
arena,
))
} }
} }
(Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => {
@@ -659,31 +657,42 @@ pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
if let Ok(n2) = usize::try_from(n2_i) { if let Ok(n2) = usize::try_from(n2_i) {
return Ok(Number::arena_from(n1 >> n2, arena)); return Ok(Number::arena_from(n1 >> n2, arena));
} else { } else {
return Ok(Number::arena_from(n1 >> usize::max_value(), arena)); return Ok(Number::arena_from(n1 >> usize::max_value(), arena));
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
let n1 = Integer::from(n1.get_num()); let n1 = Integer::from(n1.get_num());
match n2.to_usize() { let result: Result<usize, _> = (&*n2).try_into();
Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
_ => { match result {
Ok(Number::arena_from(n1 >> usize::max_value(), arena)) Ok(n2) => {
}, Ok(Number::arena_from(n1 >> n2, arena))
}
Err(_) => {
Ok(Number::arena_from(n1 >> usize::max_value(), arena))
}
} }
} }
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) { (Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
_ => { _ => Ok(Number::arena_from(
Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()),arena)) Integer::from(&*n1 >> usize::max_value()),
}, arena,
)),
}, },
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_usize() { (Number::Integer(n1), Number::Integer(n2)) => {
Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), let result: Result<usize, _> = (&*n2).try_into();
_ => {
Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()), arena)) match result {
}, Ok(n2) => {
Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena))
}
Err(_) => {
Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()), arena))
}
}
}, },
(Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
(Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
@@ -710,15 +719,18 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
if let Ok(n2) = usize::try_from(n2_i) { if let Ok(n2) = usize::try_from(n2_i) {
return Ok(Number::arena_from(n1 << n2, arena)); return Ok(Number::arena_from(n1 << n2, arena));
} else { } else {
return Ok(Number::arena_from(n1 << usize::max_value(), arena)); return Ok(Number::arena_from(n1 << usize::max_value(), arena));
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
let n1 = Integer::from(n1.get_num()); let n1 = Integer::from(n1.get_num());
match n2.to_u32() { match (&*n2).try_into() as Result<u32, _> {
Some(n2) => Ok(Number::arena_from(n1.to_u64().unwrap() << n2, arena)), Ok(n2) => {
let n1: u64 = n1.try_into().unwrap();
Ok(Number::arena_from(n1 << n2, arena))
},
_ => { _ => {
Ok(Number::arena_from(n1 << usize::max_value(), arena)) Ok(Number::arena_from(n1 << usize::max_value(), arena))
} }
@@ -726,12 +738,16 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
} }
(Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) { (Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)), Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
_ => { _ => Ok(Number::arena_from(
Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena)) Integer::from(&*n1 << usize::max_value()),
} arena,
)),
}, },
(Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { (Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<u32, _> {
Some(n2) => Ok(Number::arena_from(Integer::from(n1.to_u64().unwrap() << n2), arena)), Ok(n2) => {
let n1: u64 = (&*n1).try_into().unwrap();
Ok(Number::arena_from(Integer::from(n1 << n2), arena))
},
_ => { _ => {
Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena)) Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena))
} }
@@ -833,6 +849,23 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number,
functor_stub(mod_atom, 2) functor_stub(mod_atom, 2)
}; };
fn ibig_rem_floor(n1: &Integer, n2: &Integer) -> Integer {
let ring = ConstDivisor::new(n2.unsigned_abs());
let n1 = n1.clone();
if n2.is_negative() {
let unsigned_result = IBig::from(ring.reduce(n1).residue());
if unsigned_result.is_zero() {
unsigned_result
} else {
unsigned_result + n2
}
} else {
IBig::from(ring.reduce(n1).residue())
}
}
match (x, y) { match (x, y) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => { (Number::Fixnum(n1), Number::Fixnum(n2)) => {
let n2_i = n2.get_num(); let n2_i = n2.get_num();
@@ -845,14 +878,11 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number,
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if &*n2 == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
let n1 = Integer::from(n1.get_num()); let n1 = Integer::from(n1.get_num());
Ok(Number::arena_from( Ok(Number::arena_from(ibig_rem_floor(&n1, &*n2), arena))
<(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1,
arena,
))
} }
} }
(Number::Integer(n1), Number::Fixnum(n2)) => { (Number::Integer(n1), Number::Fixnum(n2)) => {
@@ -862,20 +892,14 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number,
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
let n2 = Integer::from(n2_i); let n2 = Integer::from(n2_i);
Ok(Number::arena_from( Ok(Number::arena_from(ibig_rem_floor(&*n1, &n2), arena))
<(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1,
arena,
))
} }
} }
(Number::Integer(x), Number::Integer(y)) => { (Number::Integer(n1), Number::Integer(n2)) => {
if &*y == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
Ok(Number::arena_from( Ok(Number::arena_from(ibig_rem_floor(&*n1, &*n2), arena))
<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1,
arena,
))
} }
} }
(Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
@@ -903,7 +927,7 @@ pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result<Numbe
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if &*n2 == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
let n1 = Integer::from(n1.get_num()); let n1 = Integer::from(n1.get_num());
@@ -921,7 +945,7 @@ pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result<Numbe
} }
} }
(Number::Integer(n1), Number::Integer(n2)) => { (Number::Integer(n1), Number::Integer(n2)) => {
if &*n2 == &0 { if n2.is_zero() {
Err(zero_divisor_eval_error(stub_gen)) Err(zero_divisor_eval_error(stub_gen))
} else { } else {
Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena)) Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena))
@@ -948,11 +972,8 @@ pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
if let Some(result) = isize_gcd(n1_i, n2_i) { if let Some(result) = isize_gcd(n1_i, n2_i) {
Ok(Number::arena_from(result, arena)) Ok(Number::arena_from(result, arena))
} else { } else {
let value: IBig = Integer::from(n1_i).gcd(&Integer::from(n2_i)).into(); let value: Integer = Integer::from(n1_i).gcd(&Integer::from(n2_i)).into();
Ok(Number::arena_from( Ok(Number::arena_from(value, arena))
value,
arena,
))
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
@@ -961,8 +982,9 @@ pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
Ok(Number::arena_from(Integer::from(n2_clone.gcd(&n1)), arena)) Ok(Number::arena_from(Integer::from(n2_clone.gcd(&n1)), arena))
} }
(Number::Integer(n1), Number::Integer(n2)) => { (Number::Integer(n1), Number::Integer(n2)) => {
let n1_clone: Integer = (*n1).clone(); let n2: isize = (&*n2).try_into().unwrap();
Ok(Number::arena_from(Integer::from(n1_clone.gcd(&Integer::from(n2.to_isize().unwrap()))) as IBig, arena)) let value: Integer = (&*n1).gcd(&Integer::from(n2)).into();
Ok(Number::arena_from(value, arena))
} }
(Number::Float(f), _) | (_, Number::Float(f)) => { (Number::Float(f), _) | (_, Number::Float(f)) => {
let n = Number::Float(f); let n = Number::Float(f);
@@ -1031,53 +1053,6 @@ pub(crate) fn atan(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.atan()) unary_float_fn_template(n1, |f| f.atan())
} }
#[inline]
pub(crate) fn asinh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.asinh())
}
#[inline]
pub(crate) fn acosh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.acosh())
}
#[inline]
pub(crate) fn atanh(n1: Number) -> Result<f64, MachineStubGen> {
let stub_gen = || {
let is_atom = atom!("is");
functor_stub(is_atom, 2)
};
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
try_numeric_result!(if f1 == 1.0 || f1 == -1.0 {
Err(EvalError::Undefined)
} else {
result_f(&Number::Float(OrderedFloat(f1.atanh())))
},
stub_gen)
}
#[inline]
pub(crate) fn sinh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.sinh())
}
#[inline]
pub(crate) fn cosh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.cosh())
}
#[inline]
pub(crate) fn tanh(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.tanh())
}
#[inline]
pub(crate) fn log10(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.log(10f64))
}
#[inline] #[inline]
pub(crate) fn float_fractional_part(n1: Number) -> Result<f64, MachineStubGen> { pub(crate) fn float_fractional_part(n1: Number) -> Result<f64, MachineStubGen> {
unary_float_fn_template(n1, |f| f.fract()) unary_float_fn_template(n1, |f| f.fract())
@@ -1107,7 +1082,6 @@ pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number {
rnd_i(&n1, arena) rnd_i(&n1, arena)
} }
#[inline] #[inline]
pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number { pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number {
let n1 = neg(n1, arena); let n1 = neg(n1, arena);
@@ -1160,16 +1134,17 @@ impl MachineState {
pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> { pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
match at { match at {
&ArithmeticTerm::Reg(r) => { &ArithmeticTerm::Reg(r) => {
let value = self.store(self.deref(self[r])); let value = self.store(self.deref(self[r]));
match Number::try_from(value) { match Number::try_from(value) {
Ok(n) => Ok(n), Ok(n) => Ok(n),
Err(_) => self.arith_eval_by_metacall(value), Err(_) => self.arith_eval_by_metacall(value),
} }
} }
&ArithmeticTerm::Interm(i) => { &ArithmeticTerm::Interm(i) => Ok(mem::replace(
Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(Fixnum::build_with(0)))) &mut self.interms[i - 1],
} Number::Fixnum(Fixnum::build_with(0)),
)),
&ArithmeticTerm::Number(n) => Ok(n), &ArithmeticTerm::Number(n) => Ok(n),
} }
} }
@@ -1183,13 +1158,17 @@ impl MachineState {
match rational_from_number(n, caller, &mut self.arena) { match rational_from_number(n, caller, &mut self.arena) {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(e_gen) => Err(e_gen(self)) Err(e_gen) => Err(e_gen(self)),
} }
} }
pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> { pub(crate) fn arith_eval_by_metacall(
&mut self,
value: HeapCellValue,
) -> Result<Number, MachineStub> {
let stub_gen = || functor_stub(atom!("is"), 2); let stub_gen = || functor_stub(atom!("is"), 2);
let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, value); let mut iter = stackful_post_order_iter::<NonListElider>
(&mut self.heap, &mut self.stack, value);
while let Some(value) = iter.next() { while let Some(value) = iter.next() {
if value.get_forwarding_bit() { if value.get_forwarding_bit() {
@@ -1338,27 +1317,6 @@ impl MachineState {
atom!("tan") => self.interms.push(Number::Float(OrderedFloat( atom!("tan") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, tan(a1)) drop_iter_on_err!(self, iter, tan(a1))
))), ))),
atom!("cosh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, cosh(a1))
))),
atom!("sinh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, sinh(a1))
))),
atom!("tanh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, tanh(a1))
))),
atom!("acosh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, acosh(a1))
))),
atom!("asinh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, asinh(a1))
))),
atom!("atanh") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, atanh(a1))
))),
atom!("log10") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, log10(a1))
))),
atom!("float_fractional_part") => self.interms.push(Number::Float(OrderedFloat( atom!("float_fractional_part") => self.interms.push(Number::Float(OrderedFloat(
drop_iter_on_err!(self, iter, float_fractional_part(a1)) drop_iter_on_err!(self, iter, float_fractional_part(a1))
))), ))),
@@ -1493,26 +1451,11 @@ mod tests {
let mut wam = MachineState::new(); let mut wam = MachineState::new();
let mut op_dir = default_op_dir(); let mut op_dir = default_op_dir();
op_dir.insert( op_dir.insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX as u8));
(atom!("+"), Fixity::In), op_dir.insert((atom!("-"), Fixity::In), OpDesc::build_with(500, YFX as u8));
OpDesc::build_with(500, YFX as u8), op_dir.insert((atom!("-"), Fixity::Pre), OpDesc::build_with(200, FY as u8));
); op_dir.insert((atom!("*"), Fixity::In), OpDesc::build_with(400, YFX as u8));
op_dir.insert( op_dir.insert((atom!("/"), Fixity::In), OpDesc::build_with(400, YFX as u8));
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("-"), Fixity::Pre),
OpDesc::build_with(200, FY as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
let term_write_result = let term_write_result =
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();

View File

@@ -118,12 +118,9 @@ impl MachineState {
and_frame[i] = self.registers[i]; and_frame[i] = self.registers[i];
} }
and_frame[arity + 1] = and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
and_frame[arity + 2] = and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
and_frame[arity + 3] =
fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
self.verify_attributes(); self.verify_attributes();
@@ -136,7 +133,8 @@ impl MachineState {
let mut seen_set = IndexSet::new(); let mut seen_set = IndexSet::new();
let mut seen_vars = vec![]; let mut seen_vars = vec![];
let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, cell); let mut iter = stackful_preorder_iter::<NonListElider>
(&mut self.heap, &mut self.stack, cell);
while let Some(value) = iter.next() { while let Some(value) = iter.next() {
read_heap_cell!(value, read_heap_cell!(value,

View File

@@ -8,7 +8,9 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
&Instruction::TryMeElse(offset) if offset > 0 => { &Instruction::TryMeElse(offset) if offset > 0 => {
stack.push(index + offset); stack.push(index + offset);
} }
&Instruction::DefaultRetryMeElse(offset) | &Instruction::RetryMeElse(offset) if offset > 0 => { &Instruction::DefaultRetryMeElse(offset) | &Instruction::RetryMeElse(offset)
if offset > 0 =>
{
stack.push(index + offset); stack.push(index + offset);
} }
&Instruction::DynamicElse(_, _, NextOrFail::Next(offset)) if offset > 0 => { &Instruction::DynamicElse(_, _, NextOrFail::Next(offset)) if offset > 0 => {

View File

@@ -28,17 +28,15 @@ pub(super) fn bootstrapping_compile(
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st();
let term_stream = BootstrappingTermStream::from_char_reader( let term_stream = BootstrappingTermStream::from_char_reader(stream, machine_st, listing_src);
stream,
machine_st,
listing_src,
);
let payload = BootstrappingLoadState( let payload =
LoadStatePayload::new(wam_prelude.code.len(), term_stream) BootstrappingLoadState(LoadStatePayload::new(wam_prelude.code.len(), term_stream));
);
let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude }; let loader: Loader<'_, BootstrappingLoadState> = Loader {
payload,
wam_prelude,
};
loader.load()?; loader.load()?;
Ok(()) Ok(())
@@ -98,8 +96,8 @@ fn derelictize_try_me_else(
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o)); retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
Some(mem::replace(o, 0)) Some(mem::replace(o, 0))
} }
Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) | Instruction::DynamicElse(_, _, NextOrFail::Fail(_))
Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => None, | Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => None,
Instruction::TryMeElse(0) => None, Instruction::TryMeElse(0) => None,
Instruction::TryMeElse(ref mut o) => { Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o)); retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o));
@@ -154,8 +152,8 @@ fn merge_indices(
fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize { fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
loop { loop {
match &code[index] { match &code[index] {
Instruction::DynamicElse(_, _, NextOrFail::Next(i)) | Instruction::DynamicElse(_, _, NextOrFail::Next(i))
Instruction::DynamicInternalElse(_, _, NextOrFail::Next(i)) | Instruction::DynamicInternalElse(_, _, NextOrFail::Next(i))
if *i > 0 => if *i > 0 =>
{ {
index += i; index += i;
@@ -170,42 +168,37 @@ fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize { fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize {
loop { loop {
match &code[index] { match &code[index] {
Instruction::TryMeElse(o) | Instruction::TryMeElse(o) | Instruction::RetryMeElse(o) => {
Instruction::RetryMeElse(o) => {
if *o > 0 { if *o > 0 {
return index; return index;
} else { } else {
index = index_loc; index = index_loc;
} }
} }
&Instruction::DynamicElse(_, _, next_or_fail) => { &Instruction::DynamicElse(_, _, next_or_fail) => match next_or_fail {
match next_or_fail { NextOrFail::Next(i) => {
NextOrFail::Next(i) => { if i == 0 {
if i == 0 {
index = index_loc;
} else {
return index;
}
}
NextOrFail::Fail(_) => {
index = index_loc; index = index_loc;
} } else {
}
}
&Instruction::DynamicInternalElse(_, _, next_or_fail) => {
match next_or_fail {
NextOrFail::Next(i) => {
if i == 0 {
index = index_loc;
} else {
return index;
}
}
NextOrFail::Fail(_) => {
return index; return index;
} }
} }
} NextOrFail::Fail(_) => {
index = index_loc;
}
},
&Instruction::DynamicInternalElse(_, _, next_or_fail) => match next_or_fail {
NextOrFail::Next(i) => {
if i == 0 {
index = index_loc;
} else {
return index;
}
}
NextOrFail::Fail(_) => {
return index;
}
},
Instruction::TrustMe(_) => { Instruction::TrustMe(_) => {
return index; return index;
} }
@@ -215,11 +208,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
index += v; index += v;
} }
IndexingCodePtr::DynamicExternal(v) => match &code[index + v] { IndexingCodePtr::DynamicExternal(v) => match &code[index + v] {
&Instruction::DynamicInternalElse( &Instruction::DynamicInternalElse(_, _, NextOrFail::Next(0)) => {
_,
_,
NextOrFail::Next(0),
) => {
return index + v; return index + v;
} }
_ => { _ => {
@@ -309,8 +298,7 @@ fn merge_indexed_subsequences(
code[inner_try_me_else_loc] = Instruction::TrustMe(o); code[inner_try_me_else_loc] = Instruction::TrustMe(o);
} }
_ => { _ => {
code[inner_try_me_else_loc] = code[inner_try_me_else_loc] = Instruction::RetryMeElse(o);
Instruction::RetryMeElse(o);
} }
}, },
} }
@@ -376,7 +364,9 @@ fn delete_from_skeleton(
} }
if skeleton.core.is_dynamic { if skeleton.core.is_dynamic {
skeleton.core.add_retracted_dynamic_clause_info(clause_index_info); skeleton
.core
.add_retracted_dynamic_clause_info(clause_index_info);
retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause( retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause(
compilation_target, compilation_target,
@@ -409,8 +399,8 @@ fn blunt_leading_choice_instr(
code[instr_loc] = Instruction::TryMeElse(*o); code[instr_loc] = Instruction::TryMeElse(*o);
return instr_loc; return instr_loc;
} }
Instruction::DynamicElse(_, _, NextOrFail::Next(_)) | Instruction::DynamicElse(_, _, NextOrFail::Next(_))
Instruction::DynamicInternalElse(_, _, NextOrFail::Next(_)) => { | Instruction::DynamicInternalElse(_, _, NextOrFail::Next(_)) => {
return instr_loc; return instr_loc;
} }
&mut Instruction::DynamicElse(b, d, NextOrFail::Fail(o)) => { &mut Instruction::DynamicElse(b, d, NextOrFail::Fail(o)) => {
@@ -422,26 +412,19 @@ fn blunt_leading_choice_instr(
code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(0)); code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(0));
return instr_loc; return instr_loc;
} }
&mut Instruction::DynamicInternalElse( &mut Instruction::DynamicInternalElse(b, d, NextOrFail::Fail(o)) => {
b,
d,
NextOrFail::Fail(o),
) => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail( retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
instr_loc, instr_loc,
NextOrFail::Fail(o), NextOrFail::Fail(o),
)); ));
code[instr_loc] = Instruction::DynamicInternalElse( code[instr_loc] = Instruction::DynamicInternalElse(b, d, NextOrFail::Next(0));
b,
d,
NextOrFail::Next(0),
);
return instr_loc; return instr_loc;
} }
Instruction::TrustMe(o) => { Instruction::TrustMe(o) => {
retraction_info.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false)); retraction_info
.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
code[instr_loc] = Instruction::TryMeElse(0); code[instr_loc] = Instruction::TryMeElse(0);
return instr_loc + 1; return instr_loc + 1;
@@ -481,9 +464,9 @@ fn set_switch_var_offset_to_choice_instr(
}; };
match &code[index_loc + v] { match &code[index_loc + v] {
Instruction::TryMeElse(_) | Instruction::TryMeElse(_)
Instruction::DynamicElse(..) | | Instruction::DynamicElse(..)
Instruction::DynamicInternalElse(..) => {} | Instruction::DynamicInternalElse(..) => {}
_ => { _ => {
set_switch_var_offset(code, index_loc, offset, retraction_info); set_switch_var_offset(code, index_loc, offset, retraction_info);
} }
@@ -523,9 +506,8 @@ fn internalize_choice_instr_at(
retraction_info: &mut RetractionInfo, retraction_info: &mut RetractionInfo,
) { ) {
match &mut code[instr_loc] { match &mut code[instr_loc] {
Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) | Instruction::DynamicElse(_, _, NextOrFail::Fail(_))
Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => { | Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => {}
}
Instruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0)) => { Instruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0)); retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
*o = NextOrFail::Fail(0); *o = NextOrFail::Fail(0);
@@ -554,18 +536,10 @@ fn internalize_choice_instr_at(
match &mut code[instr_loc + o] { match &mut code[instr_loc + o] {
Instruction::RevJmpBy(p) if *p == 0 => { Instruction::RevJmpBy(p) if *p == 0 => {
code[instr_loc] = Instruction::DynamicInternalElse( code[instr_loc] = Instruction::DynamicInternalElse(b, d, NextOrFail::Fail(o));
b,
d,
NextOrFail::Fail(o),
);
} }
_ => { _ => {
code[instr_loc] = Instruction::DynamicInternalElse( code[instr_loc] = Instruction::DynamicInternalElse(b, d, NextOrFail::Next(o));
b,
d,
NextOrFail::Next(o),
);
} }
} }
} }
@@ -609,23 +583,20 @@ fn thread_choice_instr_at_to(
*o = target_loc - instr_loc; *o = target_loc - instr_loc;
return; return;
} }
Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) | Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))
Instruction::DynamicInternalElse( | Instruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))
_, if target_loc >= instr_loc =>
_, {
NextOrFail::Next(ref mut o),
) if target_loc >= instr_loc => {
retraction_info retraction_info
.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o)); .push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o));
*o = target_loc - instr_loc; *o = target_loc - instr_loc;
return; return;
} }
Instruction::DynamicElse(_, _, NextOrFail::Next(o)) | Instruction::DynamicElse(_, _, NextOrFail::Next(o))
Instruction::DynamicInternalElse(_, _, NextOrFail::Next(o)) => { | Instruction::DynamicInternalElse(_, _, NextOrFail::Next(o)) => {
instr_loc += *o; instr_loc += *o;
} }
Instruction::TryMeElse(o) Instruction::TryMeElse(o) | Instruction::RetryMeElse(o) => {
| Instruction::RetryMeElse(o) => {
instr_loc += *o; instr_loc += *o;
} }
Instruction::RevJmpBy(ref mut o) if instr_loc >= target_loc => { Instruction::RevJmpBy(ref mut o) if instr_loc >= target_loc => {
@@ -642,7 +613,8 @@ fn thread_choice_instr_at_to(
{ {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail)); retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
code[instr_loc] = instr!("dynamic_else", code[instr_loc] = instr!(
"dynamic_else",
birth, birth,
death, death,
NextOrFail::Next(target_loc - instr_loc) NextOrFail::Next(target_loc - instr_loc)
@@ -653,14 +625,13 @@ fn thread_choice_instr_at_to(
Instruction::DynamicElse(_, _, NextOrFail::Fail(o)) if *o > 0 => { Instruction::DynamicElse(_, _, NextOrFail::Fail(o)) if *o > 0 => {
instr_loc += *o; instr_loc += *o;
} }
&mut Instruction::DynamicInternalElse( &mut Instruction::DynamicInternalElse(birth, death, ref mut fail)
birth, if target_loc >= instr_loc =>
death, {
ref mut fail,
) if target_loc >= instr_loc => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail)); retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
code[instr_loc] = instr!("dynamic_internal_else", code[instr_loc] = instr!(
"dynamic_internal_else",
birth, birth,
death, death,
NextOrFail::Next(target_loc - instr_loc) NextOrFail::Next(target_loc - instr_loc)
@@ -668,9 +639,7 @@ fn thread_choice_instr_at_to(
return; return;
} }
Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)) Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)) if *o > 0 => {
if *o > 0 =>
{
instr_loc += *o; instr_loc += *o;
} }
Instruction::TrustMe(ref mut o) if target_loc >= instr_loc => { Instruction::TrustMe(ref mut o) if target_loc >= instr_loc => {
@@ -711,33 +680,31 @@ fn remove_non_leading_clause(
None None
} }
Instruction::TrustMe(_) => { Instruction::TrustMe(_) => match &mut code[preceding_choice_instr_loc] {
match &mut code[preceding_choice_instr_loc] { Instruction::RetryMeElse(o) => {
Instruction::RetryMeElse(o) => { retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(
retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse( preceding_choice_instr_loc,
preceding_choice_instr_loc, *o,
*o, ));
));
code[preceding_choice_instr_loc] = Instruction::TrustMe(0); code[preceding_choice_instr_loc] = Instruction::TrustMe(0);
None None
}
Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
preceding_choice_instr_loc,
*o,
));
*o = 0;
Some(IndexPtr::index(preceding_choice_instr_loc + 1))
}
_ => {
unreachable!();
}
} }
} Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
preceding_choice_instr_loc,
*o,
));
*o = 0;
Some(IndexPtr::index(preceding_choice_instr_loc + 1))
}
_ => {
unreachable!();
}
},
_ => { _ => {
unreachable!(); unreachable!();
} }
@@ -988,11 +955,7 @@ fn prepend_compiled_clause(
Instruction::TryMeElse(ref mut o) if *o == 0 => { Instruction::TryMeElse(ref mut o) if *o == 0 => {
*o = prepend_queue_len - 2; *o = prepend_queue_len - 2;
} }
Instruction::DynamicInternalElse( Instruction::DynamicInternalElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
_,
_,
ref mut o @ NextOrFail::Next(0),
) => {
*o = NextOrFail::Fail(prepend_queue_len - 2); *o = NextOrFail::Fail(prepend_queue_len - 2);
} }
_ => { _ => {
@@ -1258,7 +1221,11 @@ fn print_overwrite_warning(
_ => {} _ => {}
} }
println!("Warning: overwriting {}/{} because the clauses are discontiguous", key.0.as_str(), key.1); println!(
"Warning: overwriting {}/{} because the clauses are discontiguous",
key.0.as_str(),
key.1
);
} }
impl<'a, LS: LoadState<'a>> Loader<'a, LS> { impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
@@ -1270,8 +1237,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
if let Some(path_str) = load_context.path.to_str() { if let Some(path_str) = load_context.path.to_str() {
if !path_str.is_empty() { if !path_str.is_empty() {
return Some(LS::machine_st(&mut self.payload).atom_tbl.build_with( return Some(AtomTable::build_with(
path_str &LS::machine_st(&mut self.payload).atom_tbl,
path_str,
)); ));
} }
} }
@@ -1290,10 +1258,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let clause = self.try_term_to_tl(term, &mut preprocessor)?; let clause = self.try_term_to_tl(term, &mut preprocessor)?;
// let queue = preprocessor.parse_queue(self)?; // let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new( let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
&mut LS::machine_st(&mut self.payload).atom_tbl,
settings,
);
let clause_code = cg.compile_predicate(vec![clause])?; let clause_code = cg.compile_predicate(vec![clause])?;
@@ -1323,10 +1288,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
} }
let mut cg = CodeGenerator::new( let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
&mut LS::machine_st(&mut self.payload).atom_tbl,
settings,
);
let mut code = cg.compile_predicate(clauses)?; let mut code = cg.compile_predicate(clauses)?;
@@ -1361,26 +1323,23 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.clause_clause_locs .clause_clause_locs
.extend(&clause_clause_locs.make_contiguous()[0..]); .extend(&clause_clause_locs.make_contiguous()[0..]);
self.payload.retraction_info self.payload.retraction_info.push_record(
.push_record(RetractionRecord::SkeletonClauseTruncateBack( RetractionRecord::SkeletonClauseTruncateBack(
predicates.compilation_target, predicates.compilation_target,
key, key,
skeleton_clause_len, skeleton_clause_len,
)); ),
);
} }
None => { None => {
cg.skeleton cg.skeleton
.core .core
.clause_clause_locs .clause_clause_locs
.extend(&clause_clause_locs.make_contiguous()[0..]); .extend(&clause_clause_locs.make_contiguous()[0..]);
let skeleton = cg.skeleton; let skeleton = cg.skeleton;
self.add_extensible_predicate( self.add_extensible_predicate(key, skeleton, predicates.compilation_target);
key,
skeleton,
predicates.compilation_target,
);
} }
}; };
@@ -1450,11 +1409,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut skeleton = LocalPredicateSkeleton::new(); let mut skeleton = LocalPredicateSkeleton::new();
skeleton.clause_clause_locs = clause_clause_locs; skeleton.clause_clause_locs = clause_clause_locs;
self.add_local_extensible_predicate( self.add_local_extensible_predicate(*compilation_target, *key, skeleton);
*compilation_target,
*key,
skeleton,
);
} }
} }
} }
@@ -1490,11 +1445,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut skeleton = LocalPredicateSkeleton::new(); let mut skeleton = LocalPredicateSkeleton::new();
skeleton.clause_clause_locs.push_front(code_len); skeleton.clause_clause_locs.push_front(code_len);
self.add_local_extensible_predicate( self.add_local_extensible_predicate(*compilation_target, *key, skeleton);
*compilation_target,
*key,
skeleton,
);
} }
} }
} }
@@ -1530,11 +1481,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut skeleton = LocalPredicateSkeleton::new(); let mut skeleton = LocalPredicateSkeleton::new();
skeleton.clause_clause_locs.push_back(code_len); skeleton.clause_clause_locs.push_back(code_len);
self.add_local_extensible_predicate( self.add_local_extensible_predicate(*compilation_target, *key, skeleton);
*compilation_target,
*key,
skeleton,
);
} }
} }
} }
@@ -1606,7 +1553,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.core.clause_clause_locs.push_back(code_len); skeleton.core.clause_clause_locs.push_back(code_len);
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::SkeletonClausePopBack( .push_record(RetractionRecord::SkeletonClausePopBack(
compilation_target, compilation_target,
key, key,
@@ -1624,8 +1572,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len); self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index = let code_index = self.get_or_insert_code_index(key, compilation_target);
self.get_or_insert_code_index(key, compilation_target);
if let Some(new_code_ptr) = result { if let Some(new_code_ptr) = result {
set_code_index( set_code_index(
@@ -1646,7 +1593,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.core.clause_clause_locs.push_front(code_len); skeleton.core.clause_clause_locs.push_front(code_len);
skeleton.core.clause_assert_margin += 1; skeleton.core.clause_assert_margin += 1;
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::SkeletonClausePopFront( .push_record(RetractionRecord::SkeletonClausePopFront(
compilation_target, compilation_target,
key, key,
@@ -1666,8 +1614,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len); self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index = let code_index = self.get_or_insert_code_index(key, compilation_target);
self.get_or_insert_code_index(key, compilation_target);
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
@@ -1698,19 +1645,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.opt_arg_index_key .opt_arg_index_key
.switch_on_term_loc() .switch_on_term_loc()
{ {
Some(index_loc) => { Some(index_loc) => find_inner_choice_instr(
find_inner_choice_instr( &self.wam_prelude.code,
&self.wam_prelude.code, skeleton.clauses[target_pos].clause_start,
skeleton.clauses[target_pos].clause_start, index_loc,
index_loc, ),
)
}
None => skeleton.clauses[target_pos].clause_start, None => skeleton.clauses[target_pos].clause_start,
}; };
match &mut self.wam_prelude.code[clause_loc] { match &mut self.wam_prelude.code[clause_loc] {
Instruction::DynamicElse(_, ref mut d, _) | Instruction::DynamicElse(_, ref mut d, _)
Instruction::DynamicInternalElse(_, ref mut d, _) => { | Instruction::DynamicInternalElse(_, ref mut d, _) => {
*d = Death::Finite(LS::machine_st(&mut self.payload).global_clock); *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock);
} }
_ => unreachable!(), _ => unreachable!(),
@@ -1797,11 +1742,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.clauses[target_pos + 1].clause_start = skeleton.clauses[target_pos + 1].clause_start =
skeleton.clauses[target_pos].clause_start; skeleton.clauses[target_pos].clause_start;
let update_code_index = target_pos == 0 && let update_code_index = target_pos == 0
skeleton.clauses[target_pos + 1] && skeleton.clauses[target_pos + 1]
.opt_arg_index_key .opt_arg_index_key
.switch_on_term_loc() .switch_on_term_loc()
.is_none(); .is_none();
let index_ptr_opt = if update_code_index { let index_ptr_opt = if update_code_index {
Some(IndexPtr::index(clause_loc)) Some(IndexPtr::index(clause_loc))
@@ -1964,7 +1909,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
index_loc, index_loc,
); );
let lower_bound_clause_start = skeleton.clauses[lower_bound].clause_start; let lower_bound_clause_start =
skeleton.clauses[lower_bound].clause_start;
let preceding_choice_instr_loc; let preceding_choice_instr_loc;
match &mut code[clause_start] { match &mut code[clause_start] {
@@ -2093,13 +2039,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
clause_clauses: ClauseIter, clause_clauses: ClauseIter,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let clause_predicates = clause_clauses.map(|(head, body)| { let clause_predicates = clause_clauses
Term::Clause( .map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body]));
Cell::default(),
atom!("$clause"),
vec![head, body],
)
});
let clause_clause_compilation_target = match compilation_target { let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
@@ -2132,21 +2073,21 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.cloned() .cloned()
.collect() .collect()
} }
Some(skeleton) => { Some(skeleton) => skeleton.core.clause_clause_locs.make_contiguous()
skeleton.core.clause_clause_locs.make_contiguous()[0..num_clause_predicates] [0..num_clause_predicates]
.iter() .iter()
.cloned() .cloned()
.collect() .collect(),
}
None => { None => {
unreachable!() unreachable!()
} }
}; };
match self.wam_prelude.indices.get_predicate_skeleton_mut( match self
&clause_clause_compilation_target, .wam_prelude
&(atom!("$clause"), 2), .indices
) { .get_predicate_skeleton_mut(&clause_clause_compilation_target, &(atom!("$clause"), 2))
{
Some(skeleton) if append_or_prepend.is_append() => { Some(skeleton) if append_or_prepend.is_append() => {
for _ in 0..num_clause_predicates { for _ in 0..num_clause_predicates {
skeleton.core.clause_clause_locs.pop_back(); skeleton.core.clause_clause_locs.pop_back();
@@ -2270,25 +2211,25 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
println!( println!(
"Warning: overwriting multifile predicate {}:{}/{} because \ "Warning: overwriting multifile predicate {}:{}/{} because \
it was not locally declared multifile.", it was not locally declared multifile.",
self.payload.predicates.compilation_target, key.0.as_str(), key.1 self.payload.predicates.compilation_target,
key.0.as_str(),
key.1
); );
} }
if let Some(skeleton) = self if let Some(skeleton) = self.wam_prelude.indices.remove_predicate_skeleton(
.wam_prelude &self.payload.predicates.compilation_target,
.indices &key,
.remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key) ) {
{
let compilation_target = self.payload.predicates.compilation_target; let compilation_target = self.payload.predicates.compilation_target;
if predicate_info.is_dynamic { if predicate_info.is_dynamic {
let clause_clause_compilation_target = let clause_clause_compilation_target = match compilation_target {
match compilation_target { CompilationTarget::User => {
CompilationTarget::User => { CompilationTarget::Module(atom!("builtins"))
CompilationTarget::Module(atom!("builtins")) }
} module => module,
module => module, };
};
self.retract_local_clauses_by_locs( self.retract_local_clauses_by_locs(
clause_clause_compilation_target, clause_clause_compilation_target,
@@ -2301,11 +2242,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
self.payload.retraction_info.push_record( self.payload.retraction_info.push_record(
RetractionRecord::RemovedSkeleton( RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton),
compilation_target,
key,
skeleton,
),
); );
} }
} }
@@ -2328,9 +2265,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
match self.wam_prelude.indices.modules.get_mut(&filename) { match self.wam_prelude.indices.modules.get_mut(&filename) {
Some(ref mut module) => { Some(ref mut module) => {
let index_ptr = code_index.get(); let index_ptr = code_index.get();
let code_index = module.code_dir.entry(key) let code_index = module.code_dir.entry(key).or_insert(code_index).clone();
.or_insert(code_index)
.clone();
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
@@ -2349,8 +2284,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
LS::machine_st(&mut self.payload).global_clock += 1; LS::machine_st(&mut self.payload).global_clock += 1;
let clause_clauses_len = self.payload.clause_clauses.len(); let clause_clauses_len = self.payload.clause_clauses.len();
let clauses_vec: Vec<_> = self.payload let clauses_vec: Vec<_> = self
.clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len)) .payload
.clause_clauses
.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect(); .collect();
let compilation_target = self.payload.predicates.compilation_target; let compilation_target = self.payload.predicates.compilation_target;
@@ -2374,10 +2311,7 @@ impl Machine {
module_name: HeapCellValue, module_name: HeapCellValue,
key: PredicateKey, key: PredicateKey,
) -> CodeIndex { ) -> CodeIndex {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new( let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {});
self,
InlineTermStream {},
);
let module_name = if module_name.get_tag() == HeapCellValueTag::Atom { let module_name = if module_name.get_tag() == HeapCellValueTag::Atom {
cell_as_atom!(module_name) cell_as_atom!(module_name)
@@ -2394,12 +2328,10 @@ impl Machine {
vars: &[Term], vars: &[Term],
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let mut compile = || { let mut compile = || {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new( let mut loader: Loader<'_, InlineLoadState<'_>> =
self, Loader::new(self, InlineTermStream {});
InlineTermStream {},
);
let term = loader.read_term_from_heap(term_loc)?; let term = loader.read_term_from_heap(term_loc);
let clause = build_rule_body(vars, term); let clause = build_rule_body(vars, term);
let settings = CodeGenSettings { let settings = CodeGenSettings {

32
src/machine/config.rs Normal file
View File

@@ -0,0 +1,32 @@
pub struct MachineConfig {
pub streams: StreamConfig,
pub toplevel: &'static str,
}
pub enum StreamConfig {
Stdio,
Memory,
}
impl Default for MachineConfig {
fn default() -> Self {
MachineConfig {
streams: StreamConfig::Stdio,
toplevel: include_str!("../toplevel.pl"),
}
}
}
impl MachineConfig {
pub fn in_memory() -> Self {
MachineConfig {
streams: StreamConfig::Memory,
..Default::default()
}
}
pub fn with_toplevel(mut self, toplevel: &'static str) -> Self {
self.toplevel = toplevel;
self
}
}

View File

@@ -91,12 +91,16 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target.push(hcv); self.target.push(hcv);
} }
let cdr = self.target.store(self.target.deref(heap_loc_as_cell!(addr + 1))); let cdr = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
if !cdr.is_var() { if !cdr.is_var() {
self.trail_list_cell(addr + 1, threshold); self.trail_list_cell(addr + 1, threshold);
} else { } else {
let car = self.target.store(self.target.deref(heap_loc_as_cell!(addr))); let car = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr)));
if !car.is_var() { if !car.is_var() {
self.trail_list_cell(addr, threshold); self.trail_list_cell(addr, threshold);
@@ -188,10 +192,10 @@ impl<T: CopierTarget> CopyTermState<T> {
while let HeapCellValueTag::Lis = list_addr.get_tag() { while let HeapCellValueTag::Lis = list_addr.get_tag() {
let threshold = self.target.threshold(); let threshold = self.target.threshold();
let heap_loc = list_addr.get_value() as usize; let heap_loc = list_addr.get_value() as usize;
let str_loc = self.target[heap_loc].get_value() as usize; let str_loc = self.target[heap_loc].get_value() as usize;
self.target.push(heap_loc_as_cell!(threshold+2)); self.target.push(heap_loc_as_cell!(threshold + 2));
self.target.push(heap_loc_as_cell!(threshold+1)); self.target.push(heap_loc_as_cell!(threshold + 1));
read_heap_cell!(self.target[str_loc], read_heap_cell!(self.target[str_loc],
(HeapCellValueTag::Atom) => { (HeapCellValueTag::Atom) => {
@@ -377,8 +381,9 @@ mod tests {
let a_atom = atom!("a"); let a_atom = atom!("a");
let b_atom = atom!("b"); let b_atom = atom!("b");
wam.machine_st.heap wam.machine_st
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); .heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
@@ -401,20 +406,26 @@ mod tests {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); let pstr_var_cell =
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2)); wam.machine_st.heap.push(pstr_loc_as_cell!(2));
let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); let pstr_second_var_cell =
put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st
.heap
.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
{ {
let wam = TermCopyingMockWAM { wam: &mut wam }; let wam = TermCopyingMockWAM { wam: &mut wam };
@@ -428,14 +439,20 @@ mod tests {
assert_eq!(wam.machine_st.heap[2], pstr_second_cell); assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4)); assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!(
wam.machine_st.heap[5],
fixnum_as_cell!(Fixnum::build_with(0i64))
);
assert_eq!(wam.machine_st.heap[7], pstr_cell); assert_eq!(wam.machine_st.heap[7], pstr_cell);
assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9)); assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
assert_eq!(wam.machine_st.heap[9], pstr_second_cell); assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11)); assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7)); assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!(
wam.machine_st.heap[12],
fixnum_as_cell!(Fixnum::build_with(0i64))
);
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();

View File

@@ -0,0 +1,429 @@
use crate::atom_table::*;
use crate::types::*;
/* Use the pointer reversal technique of the Deutsch-Schorr-Waite
* algorithm to detect cycles in Prolog terms.
*
* Much of the structure and nomenclature of the GC marking algorithm
* is adapted here but there are a few significant changes:
*
* - Forwarded cells now form a trail of bread crumbs leading back to self.start
* - Cells are only marked during the backward phase
* - Visiting subterms of a visited compound does not immediately shift to the backward phase
* - The heads of LIS structures are both marked and forwarded rather
* than just forwarded to distinguish them from tails;
* continue_forwarding() checks for this before entering the forward
* phase
*
* Commonalities with the GC marking algorithm:
* - The contents of forwarded cells are modified only when they are unforwarded
* - Marked (but unforwarded!) cells immediately shift to the backward phase
*/
#[derive(Debug)]
pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
pub(crate) heap: &'a mut [HeapCellValue],
start: usize,
current: usize,
next: u64,
cycle_found: bool,
mark_phase: bool,
}
impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
heap[start].set_forwarding_bit(true);
let next = heap[start].get_value();
Self {
heap,
start,
current: start,
next,
cycle_found: false,
mark_phase: true,
}
}
#[inline]
pub(crate) fn cycle_found(&self) -> bool {
self.cycle_found
}
#[inline]
fn cycle_detection_active(&self) -> bool {
STOP_AT_CYCLES && self.mark_phase && !self.cycle_found
}
fn backward_and_return(&mut self) -> HeapCellValue {
let mut current = self.heap[self.current];
current.set_value(self.next);
if self.backward() {
// set the f and m bits on the heap cell at start
// so we invoke backward() and return None next call.
self.heap[self.current].set_forwarding_bit(false);
self.heap[self.current].set_mark_bit(self.mark_phase);
}
current
}
fn traverse_subterm(&mut self, h: usize, arity: usize) -> Option<usize> {
let mut last_cell_loc = h + arity - 1;
for idx in (h .. h + arity).rev() {
if self.heap[idx].get_forwarding_bit() {
if self.cycle_detection_active() {
self.cycle_found = true;
return None;
}
last_cell_loc -= 1;
} else if self.heap[idx].get_mark_bit() == self.mark_phase {
last_cell_loc -= 1;
} else {
break;
}
}
Some(last_cell_loc)
}
#[inline]
fn continue_forwarding(&self) -> bool {
self.heap[self.current].get_mark_bit() != self.mark_phase ||
self.heap[self.current].get_forwarding_bit()
}
fn forward(&mut self) -> Option<HeapCellValue> {
loop {
if self.continue_forwarding() {
match self.heap[self.current].get_tag() {
tag @ HeapCellValueTag::AttrVar | tag @ HeapCellValueTag::Var => {
let next = self.next as usize;
if self.heap[next].get_forwarding_bit() {
return if self.current != next {
if self.cycle_detection_active() {
self.cycle_found = true;
None
} else {
Some(self.backward_and_return())
}
} else {
Some(self.backward_and_return())
};
} else if self.heap[next].get_mark_bit() == self.mark_phase {
return Some(self.backward_and_return());
}
self.heap[next].set_forwarding_bit(true);
let temp = self.heap[next].get_value();
self.heap[next].set_value(self.current as u64);
self.current = next;
self.next = temp;
if self.next < self.heap.len() as u64 {
return Some(HeapCellValue::build_with(tag, next as u64));
}
}
HeapCellValueTag::Str => {
let h = self.next as usize;
let cell = self.heap[h];
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
let last_cell_loc = match self.traverse_subterm(h + 1, arity) {
Some(last_cell_loc) => last_cell_loc,
None => return None,
};
if last_cell_loc == h {
if self.backward() {
return None;
}
continue;
}
if self.cycle_detection_active() {
for idx in (h + 1 .. last_cell_loc).rev() {
if self.heap[idx].get_forwarding_bit() {
self.cycle_found = true;
return None;
}
}
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
return Some(cell);
}
HeapCellValueTag::Lis => {
let mut cell = self.heap[self.current];
cell.set_value(self.next);
let last_cell_loc = match self.traverse_subterm(self.next as usize, 2) {
Some(last_cell_loc) => last_cell_loc,
None => return None,
};
if self.cycle_detection_active() {
for idx in (self.next as usize .. last_cell_loc).rev() {
if self.heap[idx].get_forwarding_bit() {
self.cycle_found = true;
return None;
}
}
}
if (last_cell_loc + 1) as u64 == self.next {
if self.backward() {
return None;
}
continue;
} else if last_cell_loc as u64 == self.next {
// car cells of lists are both marked and forwarded.
self.heap[last_cell_loc].set_mark_bit(self.mark_phase);
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
return Some(cell);
}
HeapCellValueTag::PStrLoc => {
let h = self.next as usize;
let cell = self.heap[h];
let last_cell_loc = h + 1;
if self.heap[last_cell_loc].get_forwarding_bit() {
if self.cycle_detection_active() {
self.cycle_found = true;
return None;
} else if self.backward() {
return None;
}
continue;
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
return Some(cell);
}
HeapCellValueTag::PStrOffset => {
let h = self.next as usize;
let cell = self.heap[h];
let last_cell_loc = h + 1;
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
if self.heap[last_cell_loc].get_forwarding_bit() {
if self.cycle_detection_active() {
self.cycle_found = true;
return None;
} else if self.backward() {
return None;
}
continue;
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
} else {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
self.next = self.heap[h].get_value();
self.heap[h].set_value(self.current as u64);
self.current = h;
}
return Some(cell);
}
tag @ HeapCellValueTag::Atom => {
let cell = HeapCellValue::build_with(tag, self.next);
let arity = AtomCell::from_bytes(cell.into_bytes()).get_arity();
if arity == 0 {
return Some(self.backward_and_return());
} else if self.backward() {
return None;
}
}
HeapCellValueTag::PStr => {
if self.backward() {
return None;
}
}
_ => {
return Some(self.backward_and_return());
}
}
} else if self.backward() {
return None;
}
}
}
fn pivot_subterm(&mut self) {
self.current -= 1;
let temp = self.heap[self.current + 1].get_value();
self.heap[self.current + 1].set_value(self.next);
self.next = self.heap[self.current].get_value();
self.heap[self.current].set_value(temp);
self.heap[self.current].set_forwarding_bit(true);
}
fn continue_backward(&mut self) -> bool {
self.heap[self.current].set_forwarding_bit(false);
if self.current == self.start {
return false;
}
let temp = self.heap[self.current].get_value();
match self.heap[temp as usize].get_tag() {
HeapCellValueTag::Str => {
let mut new_str_back_link = self.current;
for idx in (0 .. self.current).rev() {
if self.heap[idx].get_tag() == HeapCellValueTag::Atom {
if cell_as_atom_cell!(self.heap[idx]).get_arity() > 0 {
new_str_back_link = idx;
break;
}
}
if self.heap[idx].get_mark_bit() != self.mark_phase {
if !self.heap[idx].get_forwarding_bit() {
new_str_back_link = idx;
break;
}
}
}
self.heap[self.current].set_mark_bit(self.mark_phase);
self.heap[self.current].set_value(self.next);
let back_link_cell = self.heap[new_str_back_link];
self.next = back_link_cell.get_value();
self.heap[new_str_back_link].set_value(temp);
self.current = new_str_back_link;
read_heap_cell!(back_link_cell,
(HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 {
self.heap[self.current].set_mark_bit(self.mark_phase);
return true;
}
}
_ => {}
);
self.heap[self.current].set_forwarding_bit(true);
false
}
HeapCellValueTag::Lis => {
if self.heap[self.current].get_mark_bit() == self.mark_phase {
true
} else {
self.heap[self.current - 1].set_mark_bit(self.mark_phase);
self.heap[self.current].set_mark_bit(self.mark_phase);
if self.heap[self.current - 1].get_forwarding_bit() {
self.heap[self.current].set_value(self.next);
self.next = self.current as u64 - 1;
self.current = temp as usize;
true
} else {
self.pivot_subterm();
false
}
}
}
_ => {
self.heap[self.current].set_mark_bit(self.mark_phase);
true
}
}
}
fn backward(&mut self) -> bool {
while self.continue_backward() {
let temp = self.heap[self.current].get_value();
self.heap[self.current].set_value(self.next);
self.next = self.current as u64;
self.current = temp as usize;
}
if self.current == self.start {
return true;
}
false
}
fn invert_marker(&mut self) {
self.cycle_found = false;
if self.heap[self.start].get_forwarding_bit() {
while !self.backward() {}
}
self.mark_phase = false;
self.heap[self.start].set_forwarding_bit(true);
self.next = self.heap[self.start].get_value();
self.current = self.start;
while let Some(_) = self.forward() {}
}
}
impl<'a, const STOP_AT_CYCLES: bool> Iterator for CycleDetectingIter<'a, STOP_AT_CYCLES> {
type Item = HeapCellValue;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.forward()
}
}
impl<'a, const STOP_AT_CYCLES: bool> Drop for CycleDetectingIter<'a, STOP_AT_CYCLES> {
fn drop(&mut self) {
self.invert_marker();
if self.current == self.start {
return;
}
while !self.backward() {}
}
}

View File

@@ -74,7 +74,7 @@ impl BranchNumber {
fn halve_delta(&self) -> BranchNumber { fn halve_delta(&self) -> BranchNumber {
BranchNumber { BranchNumber {
branch_num: self.branch_num.clone(), branch_num: self.branch_num.clone(),
delta : &self.delta / Rational::from(2), delta: &self.delta / Rational::from(2),
} }
} }
} }
@@ -108,7 +108,10 @@ pub struct BranchInfo {
impl BranchInfo { impl BranchInfo {
fn new(branch_num: BranchNumber) -> Self { fn new(branch_num: BranchNumber) -> Self {
Self { branch_num, chunks: vec![] } Self {
branch_num,
chunks: vec![],
}
} }
} }
@@ -149,11 +152,14 @@ enum TraversalState {
// where it leaves off. // where it leaves off.
BuildFinalDisjunct(usize), BuildFinalDisjunct(usize),
Fail, Fail,
GetCutPoint{ var_num: usize, prev_b: bool }, GetCutPoint { var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool }, Cut { var_num: usize, is_global: bool },
CutPrev(usize),
ResetCallPolicy(CallPolicy), ResetCallPolicy(CallPolicy),
Term(Term), Term(Term),
RemoveBranchNum, // pop the current_branch_num and from the root set. OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
RemoveBranchNum, // pop the current_branch_num and from the root set.
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
} }
@@ -168,6 +174,7 @@ pub struct VariableClassifier {
var_num: usize, var_num: usize,
root_set: RootSet, root_set: RootSet,
global_cut_var_num: Option<usize>, global_cut_var_num: Option<usize>,
global_cut_var_num_override: Option<usize>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@@ -179,22 +186,22 @@ pub struct VarData {
impl VarData { impl VarData {
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) { fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
let global_cut_var_num = let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num {
if let &Some(global_cut_var_num) = &self.global_cut_var_num { match &self.records[global_cut_var_num].allocation {
match &self.records[global_cut_var_num].allocation { VarAlloc::Perm(..) => Some(global_cut_var_num),
VarAlloc::Perm(..) => Some(global_cut_var_num), VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => { Some(global_cut_var_num)
Some(global_cut_var_num)
}
_ => None
} }
} else { _ => None,
None }
}; } else {
None
};
if let Some(global_cut_var_num) = global_cut_var_num { if let Some(global_cut_var_num) = global_cut_var_num {
let term = QueryTerm::GetLevel(global_cut_var_num); let term = QueryTerm::GetLevel(global_cut_var_num);
self.records[global_cut_var_num].allocation = VarAlloc::Perm(0, PermVarAllocation::Pending); self.records[global_cut_var_num].allocation =
VarAlloc::Perm(0, PermVarAllocation::Pending);
match build_stack.front_mut() { match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => { Some(ChunkedTerms::Branch(_)) => {
@@ -229,7 +236,7 @@ fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
} }
fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) { fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
let branch_vec = build_stack.drain(preceding_len + 1 ..).collect(); let branch_vec = build_stack.drain(preceding_len + 1..).collect();
if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] { if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
disjuncts.push(branch_vec); disjuncts.push(branch_vec);
@@ -249,16 +256,20 @@ impl VariableClassifier {
root_set: RootSet::new(), root_set: RootSet::new(),
var_num: 0, var_num: 0,
global_cut_var_num: None, global_cut_var_num: None,
global_cut_var_num_override: None,
} }
} }
pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> { pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
self.classify_head_variables(&term)?; self.classify_head_variables(&term)?;
Ok((term, self.branch_map.separate_and_classify_variables( Ok((
self.var_num, term,
self.global_cut_var_num, self.branch_map.separate_and_classify_variables(
self.current_chunk_num, self.var_num,
))) self.global_cut_var_num,
self.current_chunk_num,
),
))
} }
pub fn classify_rule<'a, LS: LoadState<'a>>( pub fn classify_rule<'a, LS: LoadState<'a>>(
@@ -298,7 +309,7 @@ impl VariableClassifier {
} }
} }
let iter = old_branches.drain(old_branches_len - 1 ..); let iter = old_branches.drain(old_branches_len - 1..);
branches.push(merge_branch_seq(iter)); branches.push(merge_branch_seq(iter));
} }
@@ -346,9 +357,13 @@ impl VariableClassifier {
} }
fn probe_body_var(&mut self, var_info: VarInfo) { fn probe_body_var(&mut self, var_info: VarInfo) {
let term_loc = self.current_chunk_type.to_gen_context(self.current_chunk_num); let term_loc = self
.current_chunk_type
.to_gen_context(self.current_chunk_num);
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()) let branch_info_v = self
.branch_map
.entry(var_info.var_ptr.clone())
.or_insert_with(|| vec![]); .or_insert_with(|| vec![]);
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
@@ -396,12 +411,14 @@ impl VariableClassifier {
fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> { fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
match term { match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => { Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {}
}
_ => return Err(CompilationError::InvalidRuleHead), _ => return Err(CompilationError::InvalidRuleHead),
} }
let mut classify_info = ClassifyInfo { arg_c: 1, arity: term.arity() }; let mut classify_info = ClassifyInfo {
arg_c: 1,
arity: term.arity(),
};
match term { match term {
Term::Clause(_, _, terms) => { Term::Clause(_, _, terms) => {
@@ -414,13 +431,16 @@ impl VariableClassifier {
// the body of the if let here is an inlined // the body of the if let here is an inlined
// "probe_head_var". note the difference between it // "probe_head_var". note the difference between it
// and "probe_body_var". // and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone()) let branch_info_v = self
.branch_map
.entry(var_ptr.clone())
.or_insert_with(|| vec![]); .or_insert_with(|| vec![]);
let needs_new_branch = branch_info_v.is_empty(); let needs_new_branch = branch_info_v.is_empty();
if needs_new_branch { if needs_new_branch {
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); branch_info_v
.push(BranchInfo::new(self.current_branch_num.clone()));
} }
let branch_info = branch_info_v.last_mut().unwrap(); let branch_info = branch_info_v.last_mut().unwrap();
@@ -502,6 +522,12 @@ impl VariableClassifier {
self.probe_in_situ_var(var_num); self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b }); build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
} }
TraversalState::OverrideGlobalCutVar(var_num) => {
self.global_cut_var_num_override = Some(var_num);
}
TraversalState::ResetGlobalCutVarOverride(old_override) => {
self.global_cut_var_num_override = old_override;
}
TraversalState::Cut { var_num, is_global } => { TraversalState::Cut { var_num, is_global } => {
if self.try_set_chunk_at_inlined_boundary() { if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk(); build_stack.add_chunk();
@@ -509,13 +535,20 @@ impl VariableClassifier {
self.probe_in_situ_var(var_num); self.probe_in_situ_var(var_num);
build_stack.push_chunk_term( build_stack.push_chunk_term(if is_global {
if is_global { QueryTerm::GlobalCut(var_num)
QueryTerm::GlobalCut(var_num) } else {
} else { QueryTerm::LocalCut { var_num, cut_prev: false }
QueryTerm::LocalCut(var_num) });
} }
); TraversalState::CutPrev(var_num) => {
if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::LocalCut { var_num, cut_prev: true });
} }
TraversalState::Fail => { TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail); build_stack.push_chunk_term(QueryTerm::Fail);
@@ -539,22 +572,28 @@ impl VariableClassifier {
classifier.probe_body_term(arg_c + 1, terms.len(), term); classifier.probe_body_term(arg_c + 1, terms.len(), term);
} }
build_stack.push_chunk_term( build_stack.push_chunk_term(clause_to_query_term(
clause_to_query_term( loader,
loader, name,
name, terms,
terms, classifier.call_policy,
classifier.call_policy, ));
),
);
}; };
match term { match term {
Term::Clause(_, name @ (atom!("->") | atom!(";") | atom!(",")), mut terms) if terms.len() == 3 => { Term::Clause(
_,
name @ (atom!("->") | atom!(";") | atom!(",")),
mut terms,
) if terms.len() == 3 => {
if let Some(last_arg) = terms.last() { if let Some(last_arg) = terms.last() {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
terms.pop(); terms.pop();
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), name, terms))); state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
name,
terms,
)));
} else { } else {
add_chunk(self, name, terms); add_chunk(self, name, terms);
} }
@@ -583,7 +622,7 @@ impl VariableClassifier {
let mut branch_numbers = vec![first_branch_num]; let mut branch_numbers = vec![first_branch_num];
for idx in 1 .. branches.len() { for idx in 1..branches.len() {
let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
branch_numbers.push(if idx + 1 < branches.len() { branch_numbers.push(if idx + 1 < branches.len() {
@@ -610,8 +649,11 @@ impl VariableClassifier {
state_stack.push(TraversalState::AddBranchNum(branch_num)); state_stack.push(TraversalState::AddBranchNum(branch_num));
} }
if let TraversalState::BuildDisjunct(build_stack_len) = state_stack[final_disjunct_loc] { if let TraversalState::BuildDisjunct(build_stack_len) =
state_stack[final_disjunct_loc] = TraversalState::BuildFinalDisjunct(build_stack_len); state_stack[final_disjunct_loc]
{
state_stack[final_disjunct_loc] =
TraversalState::BuildFinalDisjunct(build_stack_len);
} }
self.current_chunk_type = ChunkType::Mid; self.current_chunk_type = ChunkType::Mid;
@@ -621,18 +663,30 @@ impl VariableClassifier {
let then_term = terms.pop().unwrap(); let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap(); let if_term = terms.pop().unwrap();
let prev_b = if matches!(state_stack.last(), Some(TraversalState::RemoveBranchNum)) { let prev_b = if matches!(
state_stack.last(),
Some(TraversalState::RemoveBranchNum)
) {
// check if the second-to-last element is a regular BuildDisjunct, as we don't // check if the second-to-last element is a regular BuildDisjunct, as we don't
// want to add GetPrevLevel in case of a TrustMe. // want to add GetPrevLevel in case of a TrustMe.
matches!(state_stack.iter().rev().nth(1), Some(TraversalState::BuildDisjunct(..))) matches!(
state_stack.iter().rev().nth(1),
Some(TraversalState::BuildDisjunct(..))
)
} else { } else {
false false
}; };
state_stack.push(TraversalState::Term(then_term)); state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false }); state_stack.push(TraversalState::Cut {
var_num: self.var_num,
is_global: false,
});
state_stack.push(TraversalState::Term(if_term)); state_stack.push(TraversalState::Term(if_term));
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b }); state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b,
});
self.var_num += 1; self.var_num += 1;
} }
@@ -643,12 +697,21 @@ impl VariableClassifier {
build_stack.reserve_branch(2); build_stack.reserve_branch(2);
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), atom!("$succeed"), vec![]))); state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
atom!("$succeed"),
vec![],
)));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail); state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false }); state_stack.push(TraversalState::CutPrev(self.var_num));
state_stack.push(TraversalState::ResetGlobalCutVarOverride(self.global_cut_var_num_override));
state_stack.push(TraversalState::Term(not_term)); state_stack.push(TraversalState::Term(not_term));
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b: true }); state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b: false,
});
self.current_chunk_type = ChunkType::Mid; self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1; self.current_chunk_num += 1;
@@ -668,15 +731,13 @@ impl VariableClassifier {
build_stack.add_chunk(); build_stack.add_chunk();
} }
build_stack.push_chunk_term( build_stack.push_chunk_term(qualified_clause_to_query_term(
qualified_clause_to_query_term( loader,
loader, module_name,
module_name, predicate_name,
predicate_name, vec![],
vec![], self.call_policy,
self.call_policy, ));
),
);
} }
( (
Term::Literal(_, Literal::Atom(module_name)), Term::Literal(_, Literal::Atom(module_name)),
@@ -690,15 +751,13 @@ impl VariableClassifier {
self.probe_body_term(arg_c + 1, terms.len(), term); self.probe_body_term(arg_c + 1, terms.len(), term);
} }
build_stack.push_chunk_term( build_stack.push_chunk_term(qualified_clause_to_query_term(
qualified_clause_to_query_term( loader,
loader, module_name,
module_name, name,
name, terms,
terms, self.call_policy,
self.call_policy, ));
),
);
} }
(module_name, predicate_name) => { (module_name, predicate_name) => {
if update_chunk_data(self, atom!("call"), 2) { if update_chunk_data(self, atom!("call"), 2) {
@@ -711,18 +770,18 @@ impl VariableClassifier {
terms.push(module_name); terms.push(module_name);
terms.push(predicate_name); terms.push(predicate_name);
build_stack.push_chunk_term( build_stack.push_chunk_term(clause_to_query_term(
clause_to_query_term( loader,
loader, atom!("call"),
atom!("call"), vec![Term::Clause(Cell::default(), atom!(":"), terms)],
vec![Term::Clause(Cell::default(), atom!(":"), terms)], self.call_policy,
self.call_policy, ));
),
);
} }
} }
} }
Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) if terms.len() == 1 => { Term::Clause(_, atom!("$call_with_inference_counting"), mut terms)
if terms.len() == 1 =>
{
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
state_stack.push(TraversalState::Term(terms.pop().unwrap())); state_stack.push(TraversalState::Term(terms.pop().unwrap()));
@@ -738,41 +797,43 @@ impl VariableClassifier {
self.probe_body_term(1, 1, &var); self.probe_body_term(1, 1, &var);
build_stack.push_chunk_term( build_stack.push_chunk_term(clause_to_query_term(
clause_to_query_term( loader,
loader, atom!("call"),
atom!("call"), vec![var],
vec![var], self.call_policy,
self.call_policy, ));
),
);
} }
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => { Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
if self.global_cut_var_num.is_none() { let (var_num, is_global) =
self.global_cut_var_num = Some(self.var_num); if let Some(var_num) = self.global_cut_var_num_override {
self.var_num += 1; (var_num, false)
} } else if let Some(var_num) = self.global_cut_var_num {
(var_num, true)
} else {
let var_num = self.var_num;
self.probe_in_situ_var(self.global_cut_var_num.unwrap()); self.global_cut_var_num = Some(var_num);
self.var_num += 1;
state_stack.push(TraversalState::Cut { (var_num, true)
var_num: self.global_cut_var_num.unwrap(), };
is_global: true,
}); self.probe_in_situ_var(var_num);
state_stack.push(TraversalState::Cut { var_num, is_global });
} }
Term::Literal(_, Literal::Atom(name)) => { Term::Literal(_, Literal::Atom(name)) => {
if update_chunk_data(self, name, 0) { if update_chunk_data(self, name, 0) {
build_stack.add_chunk(); build_stack.add_chunk();
} }
build_stack.push_chunk_term( build_stack.push_chunk_term(clause_to_query_term(
clause_to_query_term( loader,
loader, name,
name, vec![],
vec![], self.call_policy,
self.call_policy, ));
),
);
} }
_ => { _ => {
return Err(CompilationError::InadmissibleQueryTerm); return Err(CompilationError::InadmissibleQueryTerm);
@@ -800,12 +861,11 @@ impl BranchMap {
}; };
for (var, branches) in self.iter_mut() { for (var, branches) in self.iter_mut() {
let (mut var_num, var_num_incr) = let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() {
if let Var::InSitu(var_num) = *var.borrow() { (var_num, false)
(var_num, false) } else {
} else { (var_data.records.len(), true)
(var_data.records.len(), true) };
};
for branch in branches.iter_mut() { for branch in branches.iter_mut() {
if var_num_incr { if var_num_incr {
@@ -813,7 +873,8 @@ impl BranchMap {
var_data.records.push(VariableRecord::default()); var_data.records.push(VariableRecord::default());
} }
if branch.chunks.len() <= 1 { // true iff var is a temporary variable. if branch.chunks.len() <= 1 {
// true iff var is a temporary variable.
debug_assert_eq!(branch.chunks.len(), 1); debug_assert_eq!(branch.chunks.len(), 1);
let chunk = &mut branch.chunks[0]; let chunk = &mut branch.chunks[0];
@@ -822,7 +883,9 @@ impl BranchMap {
for var_info in chunk.vars.iter_mut() { for var_info in chunk.vars.iter_mut() {
if var_info.lvl == Level::Shallow { if var_info.lvl == Level::Shallow {
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num); let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
temp_var_data.use_set.insert((term_loc, var_info.classify_info.arg_c)); temp_var_data
.use_set
.insert((term_loc, var_info.classify_info.arg_c));
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -130,11 +130,7 @@ pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: u
} }
#[inline] #[inline]
pub(crate) fn put_complete_string( pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
heap: &mut Heap,
s: &str,
atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) { match allocate_pstr(heap, s, atom_tbl) {
Some(h) => { Some(h) => {
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr. heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
@@ -157,11 +153,7 @@ pub(crate) fn put_complete_string(
} }
#[inline] #[inline]
pub(crate) fn put_partial_string( pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
heap: &mut Heap,
s: &str,
atom_tbl: &mut AtomTable,
) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) { match allocate_pstr(heap, s, atom_tbl) {
Some(h) => { Some(h) => {
pstr_loc_as_cell!(h) pstr_loc_as_cell!(h)
@@ -173,11 +165,7 @@ pub(crate) fn put_partial_string(
} }
#[inline] #[inline]
pub(crate) fn allocate_pstr( pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option<usize> {
heap: &mut Heap,
mut src: &str,
atom_tbl: &mut AtomTable,
) -> Option<usize> {
let orig_h = heap.len(); let orig_h = heap.len();
loop { loop {
@@ -258,7 +246,10 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usiz
let extract_integer = |s: usize| -> Option<usize> { let extract_integer = |s: usize| -> Option<usize> {
match Number::try_from(heap[s]) { match Number::try_from(heap[s]) {
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
Ok(Number::Integer(n)) => n.to_usize(), Ok(Number::Integer(n)) => {
let value: usize = (&*n).try_into().unwrap();
Some(value)
},
_ => None, _ => None,
} }
}; };

File diff suppressed because it is too large Load Diff

484
src/machine/lib_machine.rs Normal file
View File

@@ -0,0 +1,484 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use crate::atom_table;
use crate::heap_print::{HCPrinter, HCValueOutputter, PrinterOutputter};
use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
use crate::machine::mock_wam::CompositeOpDir;
use crate::parser::parser::{Parser, Tokens};
use crate::read::write_term_to_heap;
use crate::machine::machine_indices::VarKey;
use crate::parser::ast::{Var, VarPtr};
use indexmap::IndexMap;
use super::{
Machine, MachineConfig, QueryResult, QueryResolutionLine,
Atom, AtomCell, HeapCellValue, HeapCellValueTag, Value, QueryResolution,
streams::Stream
};
impl Machine {
pub fn new_lib() -> Self {
Machine::new(MachineConfig::in_memory())
}
pub fn load_module_string(&mut self, module_name: &str, program: String) {
let stream = Stream::from_owned_string(program, &mut self.machine_st.arena);
self.load_file(module_name, stream);
}
pub fn consult_module_string(&mut self, module_name: &str, program: String) {
let stream = Stream::from_owned_string(program, &mut self.machine_st.arena);
self.machine_st.registers[1] = stream_as_cell!(stream);
self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(&self.machine_st.atom_tbl, module_name));
self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
}
fn allocate_stub_choice_point(&mut self) {
// NOTE: create a choice point to terminate the dispatch_loop
// if an exception is thrown. since the and/or stack is presumed empty,
let stub_b = self.machine_st.stack.allocate_or_frame(0);
let or_frame = self.machine_st.stack.index_or_frame_mut(0);
or_frame.prelude.num_cells = 0;
or_frame.prelude.e = 0;
or_frame.prelude.cp = 0;
or_frame.prelude.b = 0;
or_frame.prelude.bp = BREAK_FROM_DISPATCH_LOOP_LOC;
or_frame.prelude.boip = 0;
or_frame.prelude.biip = 0;
or_frame.prelude.tr = 0;
or_frame.prelude.h = 0;
or_frame.prelude.b0 = 0;
or_frame.prelude.attr_var_queue_len = 0;
self.machine_st.b = stub_b;
}
pub fn run_query(&mut self, query: String) -> QueryResult {
println!("Query: {}", query);
// Parse the query so we can analyze and then call the term
let mut parser = Parser::new(
Stream::from_owned_string(query, &mut self.machine_st.arena),
&mut self.machine_st
);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
let term = parser.read_term(&op_dir, Tokens::Default).expect("Failed to parse query");
// Write parsed term to heap
let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap, &mut self.machine_st.atom_tbl).expect("couldn't write term to heap");
// Write term to heap
self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
self.machine_st.p = self.indices.code_dir.get(&(atom!("call"), 1)).expect("couldn't get code index").local().unwrap();
let var_names: IndexMap<_, _> = term_write_result.var_dict.iter()
.map(|(var_key, cell)| match var_key {
// NOTE: not the intention behind Var::InSitu here but
// we can hijack it to store anonymous variables
// without creating problems.
VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
})
.collect();
self.allocate_stub_choice_point();
let stub_b = self.machine_st.b;
let mut matches: Vec<QueryResolutionLine> = Vec::new();
// Call the term
loop {
self.dispatch_loop();
//println!("b: {}", self.machine_st.b);
//println!("stub_b: {}", stub_b);
//println!("fail: {}", self.machine_st.fail);
if self.machine_st.ball.stub.len() != 0 {
// NOTE: this means an exception was thrown, at which
// point we backtracked to the stub choice point.
// this should halt the search for solutions as it
// does in the Scryer top-level. the exception term is
// contained in self.machine_st.ball.
let error_string = self.machine_st.ball.stub
.iter()
.filter(|h| match h.get_tag() {
HeapCellValueTag::Atom => true,
HeapCellValueTag::Fixnum => true,
_ => false,
})
.map(|h| match h.get_tag() {
HeapCellValueTag::Atom => {
let (name, _) = cell_as_atom_cell!(h).get_name_and_arity();
name.as_str().to_string()
}
HeapCellValueTag::Fixnum => {
h.get_value().clone().to_string()
},
_ => unreachable!(),
})
.collect::<Vec<String>>()
.join(" ");
return Err(error_string);
}
/*
if self.machine_st.fail {
// NOTE: only print results on success
self.machine_st.fail = false;
println!("fail!");
matches.push(QueryResolutionLine::False);
break;
};
*/
if term_write_result.var_dict.is_empty() {
if self.machine_st.p == LIB_QUERY_SUCCESS {
matches.push(QueryResolutionLine::True);
break;
} else if self.machine_st.p == BREAK_FROM_DISPATCH_LOOP_LOC {
// NOTE: only print results on success
// self.machine_st.fail = false;
// println!("b == stub_b");
matches.push(QueryResolutionLine::False);
break;
}
}
let mut bindings: BTreeMap<String, Value> = BTreeMap::new();
for (var_key, term_to_be_printed) in &term_write_result.var_dict {
if var_key.to_string().starts_with("_") {
continue;
}
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
Arc::clone(&self.machine_st.atom_tbl),
&mut self.machine_st.stack,
&self.indices.op_dir,
PrinterOutputter::new(),
*term_to_be_printed,
);
printer.ignore_ops = false;
printer.numbervars = true;
printer.quoted = true;
printer.max_depth = 1000; // NOTE: set this to 0 for unbounded depth
printer.double_quotes = true;
printer.var_names = var_names.clone();
let outputter = printer.print();
let output: String = outputter.result();
println!("Result: {} = {}", var_key.to_string(), output);
bindings.insert(var_key.to_string(), Value::try_from(output).expect("asdfs"));
}
matches.push(QueryResolutionLine::Match(bindings));
// NOTE: there are outstanding choicepoints, backtrack
// through them for further solutions. if
// self.machine_st.b == stub_b we've backtracked to the stub
// choice point, so we should break.
self.machine_st.backtrack();
if self.machine_st.b <= stub_b {
// NOTE: out of choicepoints to backtrack through, no
// more solutions to gather.
break;
}
}
// NOTE: deallocate stub choice point
if self.machine_st.b == stub_b {
self.trust_me();
}
Ok(QueryResolution::from(matches))
}
}
#[cfg(test)]
mod tests {
use ordered_float::OrderedFloat;
use super::*;
use crate::machine::{QueryMatch, Value, QueryResolution};
#[test]
fn programatic_query() {
let mut machine = Machine::new_lib();
machine.load_module_string(
"facts",
String::from(
r#"
triple("a", "p1", "b").
triple("a", "p2", "b").
"#,
),
);
let query = String::from(r#"triple("a",P,"b")."#);
let output = machine.run_query(query);
assert_eq!(
output,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"P" => Value::from("p1"),
}),
QueryMatch::from(btreemap! {
"P" => Value::from("p2"),
}),
]))
);
assert_eq!(
machine.run_query(String::from(r#"triple("a","p1","b")."#)),
Ok(QueryResolution::True)
);
assert_eq!(
machine.run_query(String::from(r#"triple("x","y","z")."#)),
Ok(QueryResolution::False)
);
}
#[test]
fn failing_query() {
let mut machine = Machine::new_lib();
let query = String::from(r#"triple("a",P,"b")."#);
let output = machine.run_query(query);
assert_eq!(
output,
Err(String::from("error existence_error procedure / triple 3 / triple 3"))
);
}
#[test]
fn complex_results() {
let mut machine = Machine::new_lib();
machine.load_module_string(
"facts",
r#"
:- discontiguous(subject_class/2).
:- discontiguous(constructor/2).
subject_class("Todo", c).
constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]').
subject_class("Recipe", xyz).
constructor(xyz, '[{action: "addLink", source: "this", predicate: "recipe://title", target: "literal://string:Meta%20Muffins"}]').
"#.to_string());
let result = machine.run_query(String::from("subject_class(\"Todo\", C), constructor(C, Actions)."));
assert_eq!(
result,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"C" => Value::from("c"),
"Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"todo://state\", target: \"todo://ready\"}]"),
}),
]))
);
let result = machine.run_query(String::from("subject_class(\"Recipe\", C), constructor(C, Actions)."));
assert_eq!(
result,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"C" => Value::from("xyz"),
"Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"recipe://title\", target: \"literal://string:Meta%20Muffins\"}]"),
}),
]))
);
let result = machine.run_query(String::from("subject_class(Class, _)."));
assert_eq!(
result,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"Class" => Value::from("Todo")
}),
QueryMatch::from(btreemap! {
"Class" => Value::from("Recipe")
}),
]))
);
}
#[test]
fn list_results() {
let mut machine = Machine::new_lib();
machine.load_module_string(
"facts",
r#"
list([1,2,3]).
"#.to_string());
let result = machine.run_query(String::from("list(X)."));
assert_eq!(
result,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"X" => Value::List(
Vec::from([
Value::Float(OrderedFloat::from(1.0)),
Value::Float(OrderedFloat::from(2.0)),
Value::Float(OrderedFloat::from(3.0))
])
)
}),
]))
);
}
#[test]
fn consult() {
let mut machine = Machine::new_lib();
machine.consult_module_string(
"facts",
String::from(
r#"
triple("a", "p1", "b").
triple("a", "p2", "b").
"#,
),
);
let query = String::from(r#"triple("a",P,"b")."#);
let output = machine.run_query(query);
assert_eq!(
output,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"P" => Value::from("p1"),
}),
QueryMatch::from(btreemap! {
"P" => Value::from("p2"),
}),
]))
);
assert_eq!(
machine.run_query(String::from(r#"triple("a","p1","b")."#)),
Ok(QueryResolution::True)
);
assert_eq!(
machine.run_query(String::from(r#"triple("x","y","z")."#)),
Ok(QueryResolution::False)
);
machine.consult_module_string(
"facts",
String::from(
r#"
triple("a", "new", "b").
"#,
),
);
assert_eq!(
machine.run_query(String::from(r#"triple("a","p1","b")."#)),
Ok(QueryResolution::False)
);
assert_eq!(
machine.run_query(String::from(r#"triple("a","new","b")."#)),
Ok(QueryResolution::True)
);
}
#[ignore = "fails on windows"]
#[test]
fn stress_integration_test() {
let mut machine = Machine::new_lib();
// File with test commands, i.e. program code to consult and queries to run
let code = include_str!("./lib_integration_test_commands.txt");
// Split the code into blocks
let blocks = code.split("=====");
let mut i = 0;
// Iterate over the blocks
for block in blocks {
// Trim the block to remove any leading or trailing whitespace
let block = block.trim();
// Skip empty blocks
if block.is_empty() {
continue;
}
// Check if the block is a query
if block.starts_with("query") {
// Extract the query from the block
let query = &block[5..];
i += 1;
println!("query #{}: {}", i, query);
// Parse and execute the query
let result = machine.run_query(query.to_string());
assert!(result.is_ok());
// Print the result
println!("{:?}", result);
} else if block.starts_with("consult") {
// Extract the code from the block
let code = &block[7..];
println!("load code: {}", code);
// Load the code into the machine
machine.consult_module_string("facts", code.to_string());
}
}
}
#[test]
fn findall() {
let mut machine = Machine::new_lib();
machine.consult_module_string(
"facts",
String::from(
r#"
triple("a", "p1", "b").
triple("a", "p2", "b").
"#,
),
);
let query = String::from(r#"findall([Predicate, Target], triple(_,Predicate,Target), Result)."#);
let output = machine.run_query(query);
assert_eq!(
output,
Ok(QueryResolution::Matches(vec![
QueryMatch::from(btreemap! {
"Predicate" => Value::from("Predicate"),
"Result" => Value::List(
Vec::from([
Value::List([Value::from("p1"), Value::from("b")].into()),
Value::List([Value::from("p2"), Value::from("b")].into()),
])
),
"Target" => Value::from("Target"),
}),
]))
);
}
}

View File

@@ -9,7 +9,7 @@ use crate::parser::ast::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet; use indexmap::IndexSet;
use ref_thread_local::RefThreadLocal; pub use ref_thread_local::RefThreadLocal;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
@@ -63,21 +63,27 @@ fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
match op_decl.insert_into_op_dir(wam_op_dir) { match op_decl.insert_into_op_dir(wam_op_dir) {
Some(op_desc) => { Some(op_desc) => {
payload.retraction_info.push_record(RetractionRecord::ReplacedUserOp( payload
*op_decl, .retraction_info
op_desc, .push_record(RetractionRecord::ReplacedUserOp(*op_decl, op_desc));
));
payload.module_op_exports.push((*op_decl, Some(op_desc))); payload.module_op_exports.push((*op_decl, Some(op_desc)));
} }
None => { None => {
payload.retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); payload
.retraction_info
.push_record(RetractionRecord::AddedUserOp(*op_decl));
payload.module_op_exports.push((*op_decl, None)); payload.module_op_exports.push((*op_decl, None));
} }
} }
let compilation_target = payload.compilation_target; let compilation_target = payload.compilation_target;
add_op_decl(&mut payload.retraction_info, &compilation_target, module_op_dir, op_decl); add_op_decl(
&mut payload.retraction_info,
&compilation_target,
module_op_dir,
op_decl,
);
} }
pub(super) fn add_op_decl( pub(super) fn add_op_decl(
@@ -89,10 +95,7 @@ pub(super) fn add_op_decl(
match op_decl.insert_into_op_dir(op_dir) { match op_decl.insert_into_op_dir(op_dir) {
Some(op_desc) => match &compilation_target { Some(op_desc) => match &compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
retraction_info.push_record(RetractionRecord::ReplacedUserOp( retraction_info.push_record(RetractionRecord::ReplacedUserOp(*op_decl, op_desc));
*op_decl,
op_desc,
));
} }
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(RetractionRecord::ReplacedModuleOp( retraction_info.push_record(RetractionRecord::ReplacedModuleOp(
@@ -107,10 +110,8 @@ pub(super) fn add_op_decl(
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
} }
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(RetractionRecord::AddedModuleOp( retraction_info
*module_name, .push_record(RetractionRecord::AddedModuleOp(*module_name, *op_decl));
*op_decl,
));
} }
}, },
} }
@@ -160,7 +161,12 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(&mut payload.retraction_info, compilation_target, op_dir, op_decl); add_op_decl(
&mut payload.retraction_info,
compilation_target,
op_dir,
op_decl,
);
} }
} }
} }
@@ -209,12 +215,7 @@ fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export::<LS>( add_op_decl_as_module_export::<LS>(payload, op_dir, wam_op_dir, op_decl);
payload,
op_dir,
wam_op_dir,
op_decl,
);
} }
} }
} }
@@ -239,13 +240,18 @@ fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
let key = (*name, *arity); let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
wam_prelude.indices.meta_predicates.insert(key.clone(), meta_specs.clone()); wam_prelude
.indices
.meta_predicates
.insert(key.clone(), meta_specs.clone());
} }
if let Some(src_code_index) = imported_module.code_dir.get(&key) { if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena; let arena = &mut LS::machine_st(payload).arena;
let target_code_index = wam_prelude.indices.code_dir let target_code_index = wam_prelude
.indices
.code_dir
.entry(key.clone()) .entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
@@ -325,12 +331,7 @@ fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export::<LS>( add_op_decl_as_module_export::<LS>(payload, op_dir, wam_op_dir, op_decl);
payload,
op_dir,
wam_op_dir,
op_decl,
);
} }
} }
} }
@@ -378,10 +379,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
mut clause_target_poses: Vec<Option<usize>>, mut clause_target_poses: Vec<Option<usize>>,
is_dynamic: bool, is_dynamic: bool,
) { ) {
let old_compilation_target = mem::replace( let old_compilation_target =
&mut self.payload.compilation_target, mem::replace(&mut self.payload.compilation_target, compilation_target);
compilation_target,
);
while let Some(target_pos_opt) = clause_target_poses.pop() { while let Some(target_pos_opt) = clause_target_poses.pop() {
match target_pos_opt { match target_pos_opt {
@@ -482,7 +481,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let old_index_ptr = code_index.replace(IndexPtr::undefined()); let old_index_ptr = code_index.replace(IndexPtr::undefined());
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::ReplacedModulePredicate( .push_record(RetractionRecord::ReplacedModulePredicate(
module_name, module_name,
*key, *key,
@@ -491,7 +491,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
for (key, skeleton) in removed_module.extensible_predicates.drain(..) { for (key, skeleton) in removed_module.extensible_predicates.drain(..) {
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::RemovedSkeleton( .push_record(RetractionRecord::RemovedSkeleton(
CompilationTarget::Module(module_name), CompilationTarget::Module(module_name),
key, key,
@@ -499,7 +500,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
)); ));
} }
self.wam_prelude.indices.modules.insert(module_name, removed_module); self.wam_prelude
.indices
.modules
.insert(module_name, removed_module);
} }
pub(super) fn remove_module_exports(&mut self, module_name: Atom) { pub(super) fn remove_module_exports(&mut self, module_name: Atom) {
@@ -523,15 +527,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
(Some(module_code_index), Some(target_code_index)) (Some(module_code_index), Some(target_code_index))
if module_code_index.get() == target_code_index.get() => if module_code_index.get() == target_code_index.get() =>
{ {
let old_index_ptr = target_code_index.replace(IndexPtr::undefined()); let old_index_ptr =
retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); target_code_index.replace(IndexPtr::undefined());
retraction_info
.push_record(predicate_retractor(*key, old_index_ptr));
} }
_ => {} _ => {}
} }
} }
ModuleExport::OpDecl(op_decl) => { ModuleExport::OpDecl(op_decl) => {
let op_dir_value_opt = let op_dir_value_opt = op_dir
op_dir.remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32))); .remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32)));
if let Some(op_desc) = op_dir_value_opt { if let Some(op_desc) = op_dir_value_opt {
retraction_info.push_record(op_retractor(*op_decl, op_desc)); retraction_info.push_record(op_retractor(*op_decl, op_desc));
@@ -552,9 +558,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
RetractionRecord::ReplacedUserOp, RetractionRecord::ReplacedUserOp,
); );
} }
CompilationTarget::Module(target_module_name) CompilationTarget::Module(target_module_name) if target_module_name != module_name => {
if target_module_name != module_name =>
{
let predicate_retractor = |key, index_ptr| { let predicate_retractor = |key, index_ptr| {
RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr) RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr)
}; };
@@ -563,7 +567,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc) RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc)
}; };
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&target_module_name) { if let Some(module) = self
.wam_prelude
.indices
.modules
.get_mut(&target_module_name)
{
remove_module_exports( remove_module_exports(
&removed_module, &removed_module,
&mut module.code_dir, &mut module.code_dir,
@@ -579,7 +588,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
CompilationTarget::Module(_) => {} CompilationTarget::Module(_) => {}
}; };
self.wam_prelude.indices.modules.insert(module_name, removed_module); self.wam_prelude
.indices
.modules
.insert(module_name, removed_module);
} }
fn get_or_insert_local_code_index( fn get_or_insert_local_code_index(
@@ -591,10 +603,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => module Some(ref mut module) => module
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new( .or_insert_with(|| {
IndexPtr::undefined(), CodeIndex::new(
&mut LS::machine_st(&mut self.payload).arena, IndexPtr::undefined(),
)) &mut LS::machine_st(&mut self.payload).arena,
)
})
.clone(), .clone(),
None => { None => {
self.add_dynamically_generated_module(module_name); self.add_dynamically_generated_module(module_name);
@@ -603,10 +617,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => module Some(ref mut module) => module
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new( .or_insert_with(|| {
IndexPtr::undefined(), CodeIndex::new(
&mut LS::machine_st(&mut self.payload).arena, IndexPtr::undefined(),
)) &mut LS::machine_st(&mut self.payload).arena,
)
})
.clone(), .clone(),
None => { None => {
unreachable!() unreachable!()
@@ -771,10 +787,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
let idx = self.get_or_insert_code_index( let idx = self.get_or_insert_code_index((name, arity), payload_compilation_target);
(name, arity),
payload_compilation_target,
);
ClauseType::Named(arity, name, idx) ClauseType::Named(arity, name, idx)
} }
@@ -802,13 +815,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> { pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> {
self.wam_prelude self.wam_prelude.indices.get_meta_predicate_spec(
.indices name,
.get_meta_predicate_spec( arity,
name, &self.payload.compilation_target,
arity, )
&self.payload.compilation_target,
)
} }
pub(super) fn add_meta_predicate_record( pub(super) fn add_meta_predicate_record(
@@ -829,19 +840,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.insert(key, meta_specs) .insert(key, meta_specs)
{ {
Some(old_meta_specs) => { Some(old_meta_specs) => {
self.payload.retraction_info self.payload.retraction_info.push_record(
.push_record(RetractionRecord::ReplacedMetaPredicate( RetractionRecord::ReplacedMetaPredicate(
module_name, module_name,
key.0, key.0,
old_meta_specs, old_meta_specs,
)); ),
);
} }
None => { None => {
self.payload.retraction_info self.payload
.push_record(RetractionRecord::AddedMetaPredicate( .retraction_info
module_name, .push_record(RetractionRecord::AddedMetaPredicate(module_name, key));
key,
));
} }
} }
} }
@@ -868,17 +878,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
None => { None => {
self.add_dynamically_generated_module(module_name); self.add_dynamically_generated_module(module_name);
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name)
{
module.meta_predicates.insert(key.clone(), meta_specs); module.meta_predicates.insert(key.clone(), meta_specs);
} else { } else {
unreachable!() unreachable!()
} }
self.payload.retraction_info self.payload.retraction_info.push_record(
.push_record(RetractionRecord::AddedMetaPredicate( RetractionRecord::AddedMetaPredicate(module_name.clone(), key),
module_name.clone(), );
key,
));
} }
} }
} }
@@ -901,10 +910,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut module.meta_predicates, &mut module.meta_predicates,
); );
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::AddedModule(module_name.clone())); .push_record(RetractionRecord::AddedModule(module_name.clone()));
self.wam_prelude.indices.modules.insert(module_name.clone(), module); self.wam_prelude
.indices
.modules
.insert(module_name.clone(), module);
} }
fn import_builtins_in_module( fn import_builtins_in_module(
@@ -968,9 +981,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
if is_dynamic { if is_dynamic {
let clause_clause_compilation_target = match compilation_target { let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => { CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
CompilationTarget::Module(atom!("builtins"))
}
module => module.clone(), module => module.clone(),
}; };
@@ -981,7 +992,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} }
self.payload.retraction_info self.payload
.retraction_info
.push_record(RetractionRecord::ReplacedModule( .push_record(RetractionRecord::ReplacedModule(
old_module_decl, old_module_decl,
listing_src.clone(), listing_src.clone(),
@@ -992,10 +1004,22 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} }
pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { pub(crate) fn add_module(
self.reset_in_situ_module(module_decl.clone(), &listing_src); &mut self,
module_decl: ModuleDecl,
listing_src: ListingSource,
) -> Result<(), SessionError> {
let module_name = module_decl.name; let module_name = module_decl.name;
if let Some(module) = self.wam_prelude.indices.modules.get(&module_name) {
if let ListingSource::DynamicallyGenerated = module.listing_src {
} else {
LS::err_on_builtin_module_overwrite(module_name)?;
}
}
self.reset_in_situ_module(module_decl.clone(), &listing_src);
let mut module = match self.wam_prelude.indices.modules.remove(&module_name) { let mut module = match self.wam_prelude.indices.modules.remove(&module_name) {
Some(mut module) => { Some(mut module) => {
module.listing_src = listing_src; module.listing_src = listing_src;
@@ -1033,6 +1057,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
self.wam_prelude.indices.modules.insert(module_name, module); self.wam_prelude.indices.modules.insert(module_name, module);
Ok(())
} }
pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> { pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> {
@@ -1051,7 +1077,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
)?; )?;
} }
CompilationTarget::Module(ref defining_module_name) => { CompilationTarget::Module(ref defining_module_name) => {
match self.wam_prelude.indices.modules.get_mut(defining_module_name) { match self
.wam_prelude
.indices
.modules
.get_mut(defining_module_name)
{
Some(ref mut target_module) => { Some(ref mut target_module) => {
import_module_exports_into_module::<LS>( import_module_exports_into_module::<LS>(
&mut self.payload, &mut self.payload,
@@ -1091,17 +1122,20 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
let result = match &payload_compilation_target { let result = match &payload_compilation_target {
CompilationTarget::User => { CompilationTarget::User => import_qualified_module_exports::<LS>(
import_qualified_module_exports::<LS>( &mut self.payload,
&mut self.payload, &payload_compilation_target,
&payload_compilation_target, &module,
&module, &exports,
&exports, &mut self.wam_prelude,
&mut self.wam_prelude, ),
)
}
CompilationTarget::Module(ref defining_module_name) => { CompilationTarget::Module(ref defining_module_name) => {
match self.wam_prelude.indices.modules.get_mut(defining_module_name) { match self
.wam_prelude
.indices
.modules
.get_mut(defining_module_name)
{
Some(ref mut target_module) => { Some(ref mut target_module) => {
import_qualified_module_exports_into_module::<LS>( import_qualified_module_exports_into_module::<LS>(
&mut self.payload, &mut self.payload,
@@ -1113,9 +1147,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
) )
} }
None => { None => Err(SessionError::ModuleCannotImportSelf(module_name)),
Err(SessionError::ModuleCannotImportSelf(module_name))
}
} }
} }
}; };
@@ -1123,29 +1155,38 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.wam_prelude.indices.modules.insert(module_name, module); self.wam_prelude.indices.modules.insert(module_name, module);
result result
} else { } else {
Err(SessionError::ExistenceError(ExistenceError::Module(module_name))) Err(SessionError::ExistenceError(ExistenceError::Module(
module_name,
)))
} }
} }
pub(crate) fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> { pub(crate) fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> {
let (stream, listing_src) = match module_src { let (stream, listing_src) = match module_src {
ModuleSource::File(filename) => { ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(filename.as_str()); let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl"); path_buf.set_extension("pl");
let file = File::open(&path_buf)?; let file = File::open(&path_buf)?;
( (
Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), Stream::from_file_as_input(
filename,
file,
&mut LS::machine_st(&mut self.payload).arena,
),
ListingSource::File(filename, path_buf), ListingSource::File(filename, path_buf),
) )
} }
ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { ModuleSource::Library(library) => match LIBRARIES.borrow().get(&*library.as_str()) {
Some(code) => { Some(code) => {
if let Some(ref module) = self.wam_prelude.indices.modules.get(&library) { if let Some(ref module) = self.wam_prelude.indices.modules.get(&library) {
if let ListingSource::DynamicallyGenerated = &module.listing_src { if let ListingSource::DynamicallyGenerated = &module.listing_src {
( (
Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), Stream::from_static_string(
*code,
&mut LS::machine_st(&mut self.payload).arena,
),
ListingSource::User, ListingSource::User,
) )
} else { } else {
@@ -1153,7 +1194,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} else { } else {
( (
Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), Stream::from_static_string(
*code,
&mut LS::machine_st(&mut self.payload).arena,
),
ListingSource::User, ListingSource::User,
) )
} }
@@ -1172,9 +1216,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
); );
let subloader: Loader<'_, BootstrappingLoadState> = Loader { let subloader: Loader<'_, BootstrappingLoadState> = Loader {
payload: BootstrappingLoadState( payload: BootstrappingLoadState(LoadStatePayload::new(
LoadStatePayload::new(self.wam_prelude.code.len(), term_stream) self.wam_prelude.code.len(),
), term_stream,
)),
wam_prelude: MachinePreludeView { wam_prelude: MachinePreludeView {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,
@@ -1201,22 +1246,29 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let (stream, listing_src) = match module_src { let (stream, listing_src) = match module_src {
ModuleSource::File(filename) => { ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(filename.as_str()); let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl"); path_buf.set_extension("pl");
let file = File::open(&path_buf)?; let file = File::open(&path_buf)?;
( (
Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), Stream::from_file_as_input(
filename,
file,
&mut LS::machine_st(&mut self.payload).arena,
),
ListingSource::File(filename, path_buf), ListingSource::File(filename, path_buf),
) )
} }
ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { ModuleSource::Library(library) => match LIBRARIES.borrow().get(&*library.as_str()) {
Some(code) => { Some(code) => {
if self.wam_prelude.indices.modules.contains_key(&library) { if self.wam_prelude.indices.modules.contains_key(&library) {
return self.import_qualified_module(library, exports); return self.import_qualified_module(library, exports);
} else { } else {
( (
Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), Stream::from_static_string(
*code,
&mut LS::machine_st(&mut self.payload).arena,
),
ListingSource::User, ListingSource::User,
) )
} }
@@ -1235,9 +1287,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
); );
let subloader: Loader<'_, BootstrappingLoadState> = Loader { let subloader: Loader<'_, BootstrappingLoadState> = Loader {
payload: BootstrappingLoadState( payload: BootstrappingLoadState(LoadStatePayload::new(
LoadStatePayload::new(self.wam_prelude.code.len(), term_stream), self.wam_prelude.code.len(),
), term_stream,
)),
wam_prelude: MachinePreludeView { wam_prelude: MachinePreludeView {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,8 @@ pub(crate) enum ValidType {
InCharacter, InCharacter,
Integer, Integer,
List, List,
#[allow(unused)] Number, #[allow(unused)]
Number,
Pair, Pair,
// PredicateIndicator, // PredicateIndicator,
// Variable // Variable
@@ -76,6 +77,12 @@ impl ValidType {
} }
} }
#[derive(Debug, Clone, Copy)]
pub(crate) enum ResourceError {
FiniteMemory(HeapCellValue),
OutOfFiles
}
pub(crate) trait TypeError { pub(crate) trait TypeError {
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError; fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError;
} }
@@ -154,6 +161,26 @@ pub(crate) trait PermissionError {
) -> MachineError; ) -> MachineError;
} }
impl PermissionError for Atom {
fn permission_error(
self,
_machine_st: &mut MachineState,
index_atom: Atom,
perm: Permission,
) -> MachineError {
let stub = functor!(
atom!("permission_error"),
[atom(perm.as_atom()), atom(index_atom), cell(atom_as_cell!(self))]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl PermissionError for HeapCellValue { impl PermissionError for HeapCellValue {
fn permission_error( fn permission_error(
self, self,
@@ -254,9 +281,11 @@ pub(super) type FunctorStub = [HeapCellValue; 3];
#[inline(always)] #[inline(always)]
pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub { pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
[atom_as_cell!(atom!("/"), 2), [
atom_as_cell!(name), atom_as_cell!(atom!("/"), 2),
fixnum_as_cell!(Fixnum::build_with(arity as i64))] atom_as_cell!(name),
fixnum_as_cell!(Fixnum::build_with(arity as i64)),
]
} }
impl MachineState { impl MachineState {
@@ -281,11 +310,21 @@ impl MachineState {
} }
} }
pub(super) fn resource_error(&mut self, value: HeapCellValue) -> MachineError { pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
let stub = functor!( let stub = match err {
atom!("resource_error"), ResourceError::FiniteMemory(size_requested) => {
[atom(atom!("finite_memory")), cell(value)] functor!(
); atom!("resource_error"),
[atom(atom!("finite_memory")), cell(size_requested)]
)
}
ResourceError::OutOfFiles => {
functor!(
atom!("resource_error"),
[atom(atom!("file_descriptors"))]
)
}
};
MachineError { MachineError {
stub, stub,
@@ -302,26 +341,6 @@ impl MachineState {
culprit.type_error(self, valid_type) culprit.type_error(self, valid_type)
} }
pub(super) fn module_resolution_error(
&mut self,
mod_name: Atom,
name: Atom,
arity: usize,
) -> MachineError {
let h = self.heap.len();
let res_stub = functor!(atom!(":"), [atom(mod_name), atom(name)]);
let ind_stub = functor!(atom!("/"), [str(h + 2, 0), fixnum(arity)], [res_stub]);
let stub = functor!(atom!("evaluation_error"), [str(h, 0)], [ind_stub]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError { pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError {
match err { match err {
ExistenceError::Module(name) => { ExistenceError::Module(name) => {
@@ -336,6 +355,20 @@ impl MachineState {
from: ErrorProvenance::Received, from: ErrorProvenance::Received,
} }
} }
ExistenceError::QualifiedProcedure { module_name, name, arity } => {
let h = self.heap.len();
let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]);
let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]);
let stub = functor!(atom!("existence_error"), [atom(atom!("procedure")), str(h, 0)], [res_stub]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
ExistenceError::Procedure(name, arity) => { ExistenceError::Procedure(name, arity) => {
let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]); let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]);
@@ -440,17 +473,22 @@ impl MachineState {
pub(super) fn session_error(&mut self, err: SessionError) -> MachineError { pub(super) fn session_error(&mut self, err: SessionError) -> MachineError {
match err { match err {
SessionError::CannotOverwriteBuiltIn(key) => { SessionError::CannotOverwriteBuiltIn(key) => {
// SessionError::CannotOverwriteImport(pred_atom) => {
self.permission_error( self.permission_error(
Permission::Modify, Permission::Modify,
atom!("static_procedure"), atom!("static_procedure"),
functor_stub(key.0, key.1).into_iter().collect::<MachineStub>(), functor_stub(key.0, key.1)
.into_iter()
.collect::<MachineStub>(),
)
}
SessionError::CannotOverwriteBuiltInModule(module) => {
self.permission_error(
Permission::Modify,
atom!("static_module"),
module,
) )
} }
SessionError::ExistenceError(err) => self.existence_error(err), SessionError::ExistenceError(err) => self.existence_error(err),
// SessionError::InvalidFileName(filename) => {
// Self::existence_error(h, ExistenceError::Module(filename))
// }
SessionError::ModuleDoesNotContainExport(..) => { SessionError::ModuleDoesNotContainExport(..) => {
let error_atom = atom!("module_does_not_contain_claimed_export"); let error_atom = atom!("module_does_not_contain_claimed_export");
@@ -471,7 +509,11 @@ impl MachineState {
} }
SessionError::NamelessEntry => { SessionError::NamelessEntry => {
let error_atom = atom!("nameless_procedure"); let error_atom = atom!("nameless_procedure");
self.permission_error(Permission::Create, atom!("static_procedure"), functor!(error_atom)) self.permission_error(
Permission::Create,
atom!("static_procedure"),
functor!(error_atom),
)
} }
SessionError::OpIsInfixAndPostFix(op) => { SessionError::OpIsInfixAndPostFix(op) => {
self.permission_error(Permission::Create, atom!("operator"), functor!(op)) self.permission_error(Permission::Create, atom!("operator"), functor!(op))
@@ -541,21 +583,21 @@ impl MachineState {
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError { pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
let error_atom = match err { let error_atom = match err {
FFIError::ValueCast => atom!("value_cast"), FFIError::ValueCast => atom!("value_cast"),
FFIError::ValueDontFit => atom!("value_dont_fit"), FFIError::ValueDontFit => atom!("value_dont_fit"),
FFIError::InvalidFFIType => atom!("invalid_ffi_type"), FFIError::InvalidFFIType => atom!("invalid_ffi_type"),
FFIError::InvalidStructName => atom!("invalid_struct_name"), FFIError::InvalidStructName => atom!("invalid_struct_name"),
FFIError::FunctionNotFound => atom!("function_not_found"), FFIError::FunctionNotFound => atom!("function_not_found"),
FFIError::StructNotFound => atom!("struct_not_found"), FFIError::StructNotFound => atom!("struct_not_found"),
}; };
let stub = functor!(atom!("ffi_error"),[atom(error_atom)]); let stub = functor!(atom!("ffi_error"), [atom(error_atom)]);
MachineError { MachineError {
stub, stub,
location: None, location: None,
from: ErrorProvenance::Constructed, from: ErrorProvenance::Constructed,
} }
} }
pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub { pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
@@ -682,10 +724,12 @@ impl CompilationError {
&CompilationError::ExpectedRel => { &CompilationError::ExpectedRel => {
functor!(atom!("expected_relation")) functor!(atom!("expected_relation"))
} }
&CompilationError::InadmissibleFact => { // TODO: type_error(callable, _). &CompilationError::InadmissibleFact => {
// TODO: type_error(callable, _).
functor!(atom!("inadmissible_fact")) functor!(atom!("inadmissible_fact"))
} }
&CompilationError::InadmissibleQueryTerm => { // TODO: type_error(callable, _). &CompilationError::InadmissibleQueryTerm => {
// TODO: type_error(callable, _).
functor!(atom!("inadmissible_query_term")) functor!(atom!("inadmissible_query_term"))
} }
&CompilationError::InconsistentEntry => { &CompilationError::InconsistentEntry => {
@@ -820,10 +864,10 @@ pub enum CycleSearchResult {
Cyclic(usize), Cyclic(usize),
EmptyList, EmptyList,
NotList(usize, HeapCellValue), // the list length until the second argument in the heap NotList(usize, HeapCellValue), // the list length until the second argument in the heap
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length. ProperList(usize), // the list length.
PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address). UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
UntouchedCStr(Atom, usize), UntouchedCStr(Atom, usize),
} }
@@ -838,7 +882,7 @@ impl MachineState {
match BrentAlgState::detect_cycles(&self.heap, list) { match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::PartialList(..) => { CycleSearchResult::PartialList(..) => {
let err = self.instantiation_error(); let err = self.instantiation_error();
return Err(self.error_form(err, stub_gen())) return Err(self.error_form(err, stub_gen()));
} }
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => { CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
let err = self.type_error(ValidType::List, list); let err = self.type_error(ValidType::List, list);
@@ -942,6 +986,7 @@ pub enum ExistenceError {
Module(Atom), Module(Atom),
ModuleSource(ModuleSource), ModuleSource(ModuleSource),
Procedure(Atom, usize), Procedure(Atom, usize),
QualifiedProcedure { module_name: Atom, name: Atom, arity: usize },
SourceSink(HeapCellValue), SourceSink(HeapCellValue),
Stream(HeapCellValue), Stream(HeapCellValue),
} }
@@ -950,6 +995,7 @@ pub enum ExistenceError {
pub enum SessionError { pub enum SessionError {
CompilationError(CompilationError), CompilationError(CompilationError),
CannotOverwriteBuiltIn(PredicateKey), CannotOverwriteBuiltIn(PredicateKey),
CannotOverwriteBuiltInModule(Atom),
ExistenceError(ExistenceError), ExistenceError(ExistenceError),
ModuleDoesNotContainExport(Atom, PredicateKey), ModuleDoesNotContainExport(Atom, PredicateKey),
ModuleCannotImportSelf(Atom), ModuleCannotImportSelf(Atom),

View File

@@ -3,15 +3,15 @@ use crate::parser::ast::*;
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::machine::ClauseType;
use crate::machine::loader::*; use crate::machine::loader::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::streams::Stream; use crate::machine::streams::Stream;
use crate::machine::ClauseType;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use modular_bitfield::{BitfieldSpecifier, bitfield};
use modular_bitfield::specifiers::*; use modular_bitfield::specifiers::*;
use modular_bitfield::{bitfield, BitfieldSpecifier};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BTreeSet; use std::collections::BTreeSet;
@@ -21,14 +21,6 @@ use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DBRef {
NamedPred(Atom, usize),
Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
}
// 7.2 // 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TermOrderCategory { pub enum TermOrderCategory {
@@ -86,7 +78,8 @@ pub enum IndexPtrTag {
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IndexPtr { pub struct IndexPtr {
pub p: B56, pub p: B56,
#[allow(unused)] m: bool, #[allow(unused)]
m: bool,
pub tag: IndexPtrTag, pub tag: IndexPtrTag,
} }
@@ -143,10 +136,10 @@ impl IndexPtr {
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(TypedArenaPtr<IndexPtr>); pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
const_assert!(std::mem::align_of::<CodeIndex>() == 4); const_assert!(std::mem::align_of::<CodeIndex>() == 4);
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
const_assert!(std::mem::align_of::<CodeIndex>() == 8); const_assert!(std::mem::align_of::<CodeIndex>() == 8);
impl Deref for CodeIndex { impl Deref for CodeIndex {
@@ -293,7 +286,8 @@ impl IndexStore {
let (name, arity) = key; let (name, arity) = key;
if !ClauseType::is_inbuilt(name, arity) { if !ClauseType::is_inbuilt(name, arity) {
self.modules.get(&(atom!("builtins"))) self.modules
.get(&(atom!("builtins")))
.map(|module| module.code_dir.contains_key(&(name, arity))) .map(|module| module.code_dir.contains_key(&(name, arity)))
.unwrap_or(false) .unwrap_or(false)
} else { } else {
@@ -444,11 +438,7 @@ impl IndexStore {
} }
} }
pub(crate) fn is_dynamic_predicate( pub(crate) fn is_dynamic_predicate(&self, module_name: Atom, key: PredicateKey) -> bool {
&self,
module_name: Atom,
key: PredicateKey,
) -> bool {
match module_name { match module_name {
atom!("user") => self atom!("user") => self
.extensible_predicates .extensible_predicates

View File

@@ -3,7 +3,6 @@ use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_iter::*; use crate::heap_iter::*;
use crate::heap_print::*; use crate::heap_print::*;
use crate::machine::Machine;
use crate::machine::attributed_variables::*; use crate::machine::attributed_variables::*;
use crate::machine::copier::*; use crate::machine::copier::*;
use crate::machine::heap::*; use crate::machine::heap::*;
@@ -11,6 +10,7 @@ use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::machine::Machine;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::read::TermWriteResult; use crate::read::TermWriteResult;
use crate::types::*; use crate::types::*;
@@ -22,6 +22,7 @@ use indexmap::IndexMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::sync::Arc;
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -57,14 +58,14 @@ pub enum OnEOF {
} }
pub struct MachineState { pub struct MachineState {
pub atom_tbl: AtomTable, pub atom_tbl: Arc<AtomTable>,
pub arena: Arena, pub arena: Arena,
pub(super) pdl: Vec<HeapCellValue>, pub(super) pdl: Vec<HeapCellValue>,
pub(super) s: HeapPtr, pub(super) s: HeapPtr,
pub(super) s_offset: usize, pub(super) s_offset: usize,
pub(super) p: usize, pub(super) p: usize,
pub(super) oip: u32, // first internal code ptr pub(super) oip: u32, // first internal code ptr
pub(super) iip : u32, // second internal code ptr pub(super) iip: u32, // second internal code ptr
pub(super) b: usize, pub(super) b: usize,
pub(super) b0: usize, pub(super) b0: usize,
pub(super) e: usize, pub(super) e: usize,
@@ -79,7 +80,7 @@ pub struct MachineState {
pub(super) trail: Vec<TrailEntry>, pub(super) trail: Vec<TrailEntry>,
pub(super) tr: usize, pub(super) tr: usize,
pub(super) hb: usize, pub(super) hb: usize,
pub(super) block: usize, // an offset into the OR stack. pub(super) block: usize, // an offset into the OR stack.
pub(super) scc_block: usize, // an offset into the OR stack for setup_call_cleanup/3. pub(super) scc_block: usize, // an offset into the OR stack for setup_call_cleanup/3.
pub(super) ball: Ball, pub(super) ball: Ball,
pub(super) ball_stack: Vec<Ball>, // save current ball before jumping via, e.g., verify_attr interrupt. pub(super) ball_stack: Vec<Ball>, // save current ball before jumping via, e.g., verify_attr interrupt.
@@ -95,7 +96,7 @@ pub struct MachineState {
pub(crate) unify_fn: fn(&mut MachineState), pub(crate) unify_fn: fn(&mut MachineState),
pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool, pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult, pub(crate) increment_call_count_fn: fn(&mut MachineState) -> bool,
} }
impl fmt::Debug for MachineState { impl fmt::Debug for MachineState {
@@ -203,12 +204,12 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
fn push_var_eq_functors<'a>( fn push_var_eq_functors<'a>(
heap: &mut Heap, heap: &mut Heap,
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>, iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Vec<HeapCellValue> { ) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![]; let mut list_of_var_eqs = vec![];
for (var, binding) in iter { for (var, binding) in iter {
let var_atom = atom_tbl.build_with(&var.to_string()); let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
let h = heap.len(); let h = heap.len();
heap.push(atom_as_cell!(atom!("="), 2)); heap.push(atom_as_cell!(atom!("="), 2));
@@ -243,9 +244,11 @@ impl Ball {
pub(super) fn copy_and_align(&self, h: usize) -> Heap { pub(super) fn copy_and_align(&self, h: usize) -> Heap {
let diff = self.boundary as i64 - h as i64; let diff = self.boundary as i64 - h as i64;
self.stub.iter().cloned().map(|heap_value| { self.stub
heap_value - diff .iter()
}).collect() .cloned()
.map(|heap_value| heap_value - diff)
.collect()
} }
} }
@@ -409,28 +412,31 @@ impl MachineState {
self.fail = false; self.fail = false;
} }
pub(crate) fn increment_call_count(&mut self) -> CallResult { pub(crate) fn increment_call_count(&mut self) -> bool {
if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 { if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 {
return Ok(()); return true;
} }
if let Some(&(ref limit, bp)) = self.cwil.limits.last() { if let Some(&(ref limit, block)) = self.cwil.limits.last() {
if self.cwil.count == *limit { if self.cwil.count == *limit {
self.cwil.inference_limit_exceeded = true; self.cwil.inference_limit_exceeded = true;
self.block = block;
self.unwind_stack();
return Err( return false;
functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])
);
} else { } else {
self.cwil.count += 1; self.cwil.count += 1;
} }
} }
Ok(()) true
} }
#[allow(dead_code)] #[allow(dead_code)]
pub(super) fn try_char_list(&mut self, addrs: Vec<HeapCellValue>) -> Result<String, MachineError> { pub(super) fn try_char_list(
&mut self,
addrs: Vec<HeapCellValue>,
) -> Result<String, MachineError> {
let mut chars = String::new(); let mut chars = String::new();
for addr in addrs { for addr in addrs {
@@ -515,18 +521,25 @@ impl MachineState {
mut var_list: Vec<(VarKey, HeapCellValue, usize)>, mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
singleton_var_list: Vec<HeapCellValue>, singleton_var_list: Vec<HeapCellValue>,
) -> CallResult { ) -> CallResult {
var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2)); var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
let list_of_var_eqs = push_var_eq_functors( let list_of_var_eqs = push_var_eq_functors(
&mut self.heap, &mut self.heap,
var_list.iter().filter_map(|(var_name, var,_)| if var_name.is_anon() { None } else { Some((var_name,var)) }), var_list.iter().filter_map(|(var_name, var, _)| {
&mut self.atom_tbl, if var_name.is_anon() {
None
} else {
Some((var_name, var))
}
}),
&self.atom_tbl,
); );
let singleton_addr = self.registers[3]; let singleton_addr = self.registers[3];
let singletons_offset = heap_loc_as_cell!( let singletons_offset = heap_loc_as_cell!(iter_to_heap_list(
iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter()) &mut self.heap,
); singleton_var_list.into_iter()
));
unify_fn!(*self, singletons_offset, singleton_addr); unify_fn!(*self, singletons_offset, singleton_addr);
@@ -535,9 +548,10 @@ impl MachineState {
} }
let vars_addr = self.registers[4]; let vars_addr = self.registers[4];
let vars_offset = heap_loc_as_cell!( let vars_offset = heap_loc_as_cell!(iter_to_heap_list(
iter_to_heap_list(&mut self.heap, var_list.into_iter().map(|(_,cell,_)| cell)) &mut self.heap,
); var_list.into_iter().map(|(_, cell, _)| cell)
));
unify_fn!(*self, vars_offset, vars_addr); unify_fn!(*self, vars_offset, vars_addr);
@@ -546,9 +560,10 @@ impl MachineState {
} }
let var_names_addr = self.registers[5]; let var_names_addr = self.registers[5];
let var_names_offset = heap_loc_as_cell!( let var_names_offset = heap_loc_as_cell!(iter_to_heap_list(
iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter()) &mut self.heap,
); list_of_var_eqs.into_iter()
));
Ok(unify_fn!(*self, var_names_offset, var_names_addr)) Ok(unify_fn!(*self, var_names_offset, var_names_addr))
} }
@@ -575,7 +590,7 @@ impl MachineState {
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new(); let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
for cell in stackful_preorder_iter(&mut self.heap, &mut self.stack, heap_loc) { for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc) {
let cell = unmark_cell_bits!(cell); let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() { if let Some(var) = cell.as_var() {
@@ -589,18 +604,21 @@ impl MachineState {
let singleton_var_list = push_var_eq_functors( let singleton_var_list = push_var_eq_functors(
&mut self.heap, &mut self.heap,
term_write_result.var_dict.iter().filter(|(var_name, binding)| { term_write_result
if var_name.is_anon() { .var_dict
return false; .iter()
} .filter(|(var_name, binding)| {
if var_name.is_anon() {
return false;
}
if let Some(r) = binding.as_var() { if let Some(r) = binding.as_var() {
*singleton_var_set.get(&r).unwrap_or(&false) *singleton_var_set.get(&r).unwrap_or(&false)
} else { } else {
false false
} }
}), }),
&mut self.atom_tbl, &self.atom_tbl,
); );
for var in term_write_result.var_dict.values_mut() { for var in term_write_result.var_dict.values_mut() {
@@ -620,13 +638,11 @@ impl MachineState {
self.write_read_term_options(var_list, singleton_var_list) self.write_read_term_options(var_list, singleton_var_list)
} }
pub fn read_term_from_user_input_eof_handler(&mut self, stream: Stream) -> Result<OnEOF, MachineStub> { pub fn read_term_from_user_input_eof_handler(
self.eof_action( &mut self,
self.registers[2], stream: Stream,
stream, ) -> Result<OnEOF, MachineStub> {
atom!("read_term"), self.eof_action(self.registers[2], stream, atom!("read_term"), 3)?;
3,
)?;
if stream.options().eof_action() == EOFAction::Reset { if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false { if self.fail == false {
@@ -639,13 +655,15 @@ impl MachineState {
// Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr // Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr
// will always be valid. // will always be valid.
pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { pub fn read_term_from_user_input(
let atoms_ptr = (&self.atom_tbl.table) as *const indexmap::IndexSet<Atom>; &mut self,
stream: Stream,
indices: &mut IndexStore,
) -> CallResult {
if let Stream::Readline(ptr) = stream { if let Stream::Readline(ptr) = stream {
unsafe { unsafe {
let readline = ptr.as_ptr().as_mut().unwrap(); let readline = ptr.as_ptr().as_mut().unwrap();
readline.set_atoms_for_completion(atoms_ptr); readline.set_atoms_for_completion(&self.atom_tbl);
return self.read_term( return self.read_term(
stream, stream,
indices, indices,
@@ -654,6 +672,14 @@ impl MachineState {
} }
} }
if let Stream::Byte(_) = stream {
return self.read_term(
stream,
indices,
MachineState::read_term_from_user_input_eof_handler
)
}
unreachable!("Stream must be a Stream::Readline(_)") unreachable!("Stream must be a Stream::Readline(_)")
} }
@@ -663,12 +689,7 @@ impl MachineState {
stream.set_past_end_of_stream(true); stream.set_past_end_of_stream(true);
return Ok(OnEOF::Return); return Ok(OnEOF::Return);
} else if stream.past_end_of_stream() { } else if stream.past_end_of_stream() {
self.eof_action( self.eof_action(self.registers[2], stream, atom!("read_term"), 3)?;
self.registers[2],
stream,
atom!("read_term"),
3,
)?;
if stream.options().eof_action() == EOFAction::Reset { if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false { if self.fail == false {
@@ -709,7 +730,9 @@ impl MachineState {
match &err { match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => { CompilationError::ParserError(e) if e.is_unexpected_eof() => {
match eof_handler(self, stream)? { match eof_handler(self, stream)? {
OnEOF::Return => return self.write_read_term_options(vec![], vec![]), OnEOF::Return => {
return self.write_read_term_options(vec![], vec![])
}
OnEOF::Continue => continue, OnEOF::Continue => continue,
} }
} }
@@ -762,14 +785,14 @@ impl MachineState {
} }
(HeapCellValueTag::Atom, (name, _arity)) => { (HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0); debug_assert_eq!(_arity, 0);
var_names.insert(var, VarPtr::from(name.as_str())); var_names.insert(var, VarPtr::from(&*name.as_str()));
} }
(HeapCellValueTag::Str, s) => { (HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]) let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity(); .get_name_and_arity();
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
var_names.insert(var, VarPtr::from(name.as_str())); var_names.insert(var, VarPtr::from(&*name.as_str()));
} }
_ => { _ => {
unreachable!(); unreachable!();
@@ -850,7 +873,7 @@ impl MachineState {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.heap, &mut self.heap,
&mut self.atom_tbl, Arc::clone(&self.atom_tbl),
&mut self.stack, &mut self.stack,
op_dir, op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
@@ -872,8 +895,10 @@ impl MachineState {
} }
} }
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
if let Some(n) = n.to_usize() { let result = (&*n).try_into();
printer.max_depth = n;
if let Ok(value) = result {
printer.max_depth = value;
} else { } else {
self.fail = true; self.fail = true;
return Ok(None); return Ok(None);
@@ -896,7 +921,11 @@ impl MachineState {
Ok(Some(printer)) Ok(Some(printer))
} }
pub(super) fn read_predicate_key(&self, name: HeapCellValue, arity: HeapCellValue) -> (Atom, usize) { pub(super) fn read_predicate_key(
&self,
name: HeapCellValue,
arity: HeapCellValue,
) -> (Atom, usize) {
let name = cell_as_atom!(self.store(self.deref(name))); let name = cell_as_atom!(self.store(self.deref(name)));
let arity = cell_as_fixnum!(self.store(self.deref(arity))); let arity = cell_as_fixnum!(self.store(self.deref(arity)));
@@ -920,13 +949,32 @@ impl MachineState {
} }
); );
} }
#[inline(always)]
pub(super) fn cut_prev_body(&mut self, value: HeapCellValue) {
let b = self.b;
read_heap_cell!(value,
(HeapCellValueTag::CutPoint, b0) => {
let b0 = b0.get_num() as usize;
let b0 = self.stack.index_or_frame(b0).prelude.b;
if b > b0 {
self.b = b0;
}
}
_ => {
self.fail = true;
}
);
}
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CWIL { pub(crate) struct CWIL {
count: Integer, count: Integer,
limits: Vec<(Integer, usize)>, limits: Vec<(Integer, usize)>,
inference_limit_exceeded: bool, pub(crate) inference_limit_exceeded: bool,
} }
impl CWIL { impl CWIL {
@@ -938,22 +986,22 @@ impl CWIL {
} }
} }
pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer { pub(crate) fn add_limit(&mut self, limit: usize, block: usize) -> &Integer {
let mut limit = Integer::from(limit); let mut limit = Integer::from(limit);
limit += &self.count; limit += &self.count;
match self.limits.last() { match self.limits.last() {
Some((ref inner_limit, _)) if *inner_limit <= limit => {} Some((ref inner_limit, _)) if *inner_limit <= limit => {}
_ => self.limits.push((limit, b)), _ => self.limits.push((limit, block)),
}; };
&self.count &self.count
} }
#[inline(always)] #[inline(always)]
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { pub(crate) fn remove_limit(&mut self, block: usize) -> &Integer {
if let Some((_, bp)) = self.limits.last() { if let Some((_, bl)) = self.limits.last() {
if bp == &b { if bl == &block {
self.limits.pop(); self.limits.pop();
} }
} }

View File

@@ -1,6 +1,5 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::types::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_iter::*; use crate::heap_iter::*;
use crate::machine::attributed_variables::*; use crate::machine::attributed_variables::*;
@@ -14,6 +13,7 @@ use crate::machine::stack::*;
use crate::machine::unify::*; use crate::machine::unify::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
use indexmap::IndexSet; use indexmap::IndexSet;
@@ -50,7 +50,7 @@ impl MachineState {
ball: Ball::new(), ball: Ball::new(),
ball_stack: vec![], ball_stack: vec![],
lifted_heap: Heap::new(), lifted_heap: Heap::new(),
interms: vec![Number::default();256], interms: vec![Number::default(); 256],
cont_pts: Vec::with_capacity(256), cont_pts: Vec::with_capacity(256),
cwil: CWIL::new(), cwil: CWIL::new(),
flags: MachineFlags::default(), flags: MachineFlags::default(),
@@ -59,8 +59,8 @@ impl MachineState {
dynamic_mode: FirstOrNext::First, dynamic_mode: FirstOrNext::First,
unify_fn: MachineState::unify, unify_fn: MachineState::unify,
bind_fn: MachineState::bind, bind_fn: MachineState::bind,
run_cleaners_fn: |_| { false }, run_cleaners_fn: |_| false,
increment_call_count_fn: |_| { Ok(()) }, increment_call_count_fn: |_| true,
} }
} }
@@ -160,9 +160,8 @@ impl MachineState {
key_atom.index as u64, key_atom.index as u64,
)); ));
self.trail.push(TrailEntry::from_bytes( self.trail
value_cell.into_bytes(), .push(TrailEntry::from_bytes(value_cell.into_bytes()));
));
self.tr += 2; self.tr += 2;
} }
@@ -248,9 +247,7 @@ impl MachineState {
r: Ref, r: Ref,
value: HeapCellValue, value: HeapCellValue,
) { ) {
let mut unifier = CompositeUnifierForOccursCheckWithError::from( let mut unifier = CompositeUnifierForOccursCheckWithError::from(DefaultUnifier::from(self));
DefaultUnifier::from(self),
);
unifier.bind(r, value); unifier.bind(r, value);
} }
@@ -297,12 +294,12 @@ impl MachineState {
pub fn unify_big_int(&mut self, n1: TypedArenaPtr<Integer>, value: HeapCellValue) { pub fn unify_big_int(&mut self, n1: TypedArenaPtr<Integer>, value: HeapCellValue) {
let mut unifier = DefaultUnifier::from(self); let mut unifier = DefaultUnifier::from(self);
unifier.unify_big_num(n1, value); unifier.unify_big_integer(n1, value);
} }
pub fn unify_rational(&mut self, n1: TypedArenaPtr<Rational>, value: HeapCellValue) { pub fn unify_rational(&mut self, n1: TypedArenaPtr<Rational>, value: HeapCellValue) {
let mut unifier = DefaultUnifier::from(self); let mut unifier = DefaultUnifier::from(self);
unifier.unify_big_num(n1, value); unifier.unify_big_rational(n1, value);
} }
pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
@@ -316,9 +313,7 @@ impl MachineState {
} }
pub(super) fn unify_with_occurs_check_with_error(&mut self) { pub(super) fn unify_with_occurs_check_with_error(&mut self) {
let mut unifier = CompositeUnifierForOccursCheckWithError::from( let mut unifier = CompositeUnifierForOccursCheckWithError::from(DefaultUnifier::from(self));
DefaultUnifier::from(self),
);
unifier.unify_internal(); unifier.unify_internal();
} }
@@ -380,8 +375,7 @@ impl MachineState {
} }
) )
} }
&mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => {
&mut HeapPtr::PStrLocation(h, ref mut n) => {
read_heap_cell!(self.heap[h], read_heap_cell!(self.heap[h],
(HeapCellValueTag::PStr, pstr_atom) => { (HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom); let pstr = PartialString::from(pstr_atom);
@@ -509,7 +503,7 @@ impl MachineState {
} else { } else {
self.pdl.clear(); self.pdl.clear();
return Some( return Some(
n1.chars().next().cmp(&Some(c2)) n1.as_str().chars().next().cmp(&Some(c2))
.then(Ordering::Greater) .then(Ordering::Greater)
); );
} }
@@ -539,7 +533,7 @@ impl MachineState {
} else { } else {
self.pdl.clear(); self.pdl.clear();
return Some( return Some(
Some(c1).cmp(&n2.chars().next()) Some(c1).cmp(&n2.as_str().chars().next())
.then(Ordering::Less) .then(Ordering::Less)
); );
} }
@@ -562,7 +556,7 @@ impl MachineState {
} else { } else {
self.pdl.clear(); self.pdl.clear();
return Some( return Some(
Some(c1).cmp(&n2.chars().next()) Some(c1).cmp(&n2.as_str().chars().next())
.then(Ordering::Less) .then(Ordering::Less)
); );
} }
@@ -592,7 +586,7 @@ impl MachineState {
} else { } else {
self.pdl.clear(); self.pdl.clear();
return Some( return Some(
n1.chars().next().cmp(&Some(c2)) n1.as_str().chars().next().cmp(&Some(c2))
.then(Ordering::Greater) .then(Ordering::Greater)
); );
} }
@@ -639,7 +633,7 @@ impl MachineState {
// iter2 is continuable, so it // iter2 is continuable, so it
// has a tail in the heap at // has a tail in the heap at
// focus+1. // focus+1.
pdl.push(iter2.heap[focus+1]); pdl.push(iter2.heap[focus + 1]);
return None; return None;
} }
@@ -902,8 +896,12 @@ impl MachineState {
let s = string.as_str(); let s = string.as_str();
match heap_pstr_iter.compare_pstr_to_string(s) { match heap_pstr_iter.compare_pstr_to_string(&*s) {
Some(PStrPrefixCmpResult { focus, offset, prefix_len }) if prefix_len == s.len() => { Some(PStrPrefixCmpResult {
focus,
offset,
prefix_len,
}) if prefix_len == s.len() => {
let focus_addr = self.heap[focus]; let focus_addr = self.heap[focus];
read_heap_cell!(focus_addr, read_heap_cell!(focus_addr,
@@ -950,7 +948,10 @@ impl MachineState {
return; return;
} }
Some(PStrPrefixCmpResult { prefix_len: inner_prefix_len, .. }) => { Some(PStrPrefixCmpResult {
prefix_len: inner_prefix_len,
..
}) => {
prefix_len = inner_prefix_len; prefix_len = inner_prefix_len;
} }
None => { None => {
@@ -1002,9 +1003,9 @@ impl MachineState {
self.s_offset = 0; self.s_offset = 0;
self.mode = MachineMode::Read; self.mode = MachineMode::Read;
put_partial_string(&mut self.heap, pstr, &mut self.atom_tbl) put_partial_string(&mut self.heap, pstr, &self.atom_tbl)
} else { } else {
put_complete_string(&mut self.heap, pstr, &mut self.atom_tbl) put_complete_string(&mut self.heap, pstr, &self.atom_tbl)
} }
} }
@@ -1096,7 +1097,7 @@ impl MachineState {
(name, 0, 0) (name, 0, 0)
} }
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
(self.atom_tbl.build_with(&c.to_string()), 0, 0) (AtomTable::build_with(&self.atom_tbl, &c.to_string()), 0, 0)
} }
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
let stub = functor_stub(atom!("call"), arity + 1); let stub = functor_stub(atom!("call"), arity + 1);
@@ -1130,26 +1131,23 @@ impl MachineState {
#[inline] #[inline]
pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool { pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool {
if value.is_constant() { let value = self.store(self.deref(value));
if value.is_stack_var() || value.is_constant() {
return false; return false;
} }
let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, value); let h = self.heap.len();
self.heap.push(value);
while let Some(value) = iter.next() { let cycle_found = {
if value.get_forwarding_bit() { let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h);
let value = unmark_cell_bits!(heap_bound_store( while let Some(_) = iter.next() {}
iter.heap, iter.cycle_found()
heap_bound_deref(iter.heap, value), };
));
if value.is_compound(iter.heap) { self.heap.pop();
return true; cycle_found
}
}
}
false
} }
// arg(+N, +Term, ?Arg) // arg(+N, +Term, ?Arg)
@@ -1181,7 +1179,7 @@ impl MachineState {
let n = match n { let n = match n {
Number::Fixnum(n) => n.get_num() as usize, Number::Fixnum(n) => n.get_num() as usize,
Number::Integer(n) if *n >= 0 && *n <= std::usize::MAX => n.to_usize().unwrap(), Number::Integer(n) if usize::try_from(&*n).is_ok() => (&*n).try_into().unwrap(),
_ => { _ => {
self.fail = true; self.fail = true;
return Ok(()); return Ok(());
@@ -1324,7 +1322,7 @@ impl MachineState {
let f_a = if name == atom!(".") && arity == 2 { let f_a = if name == atom!(".") && arity == 2 {
self.heap.push(heap_loc_as_cell!(h)); self.heap.push(heap_loc_as_cell!(h));
self.heap.push(heap_loc_as_cell!(h+1)); self.heap.push(heap_loc_as_cell!(h + 1));
list_loc_as_cell!(h) list_loc_as_cell!(h)
} else { } else {
@@ -1398,9 +1396,15 @@ impl MachineState {
let err = self.domain_error(DomainErrorType::NotLessThanZero, n); let err = self.domain_error(DomainErrorType::NotLessThanZero, n);
return Err(self.error_form(err, stub_gen())); return Err(self.error_form(err, stub_gen()));
} }
Ok(Number::Rational(n)) => n.numerator().to_i64().unwrap(), Ok(Number::Rational(n)) => {
let value: i64 = n.numerator().try_into().unwrap();
value
},
Ok(Number::Fixnum(n)) => n.get_num(), Ok(Number::Fixnum(n)) => n.get_num(),
Ok(Number::Integer(n)) => n.to_i64().unwrap(), Ok(Number::Integer(n)) => {
let value: i64 = (&*n).try_into().unwrap();
value
},
Err(_) => { Err(_) => {
return type_error(arity); return type_error(arity);
} }
@@ -1435,7 +1439,7 @@ impl MachineState {
} }
} }
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
let c = self.atom_tbl.build_with(&c.to_string()); let c = AtomTable::build_with(&self.atom_tbl, &c.to_string());
self.try_functor_fabricate_struct( self.try_functor_fabricate_struct(
c, c,
@@ -1571,8 +1575,7 @@ impl MachineState {
while let Some(iteratee) = heap_pstr_iter.next() { while let Some(iteratee) = heap_pstr_iter.next() {
match iteratee { match iteratee {
PStrIteratee::Char(_, c) => PStrIteratee::Char(_, c) => chars.push(char_as_cell!(c)),
chars.push(char_as_cell!(c)),
PStrIteratee::PStrSegment(_, pstr_atom, n) => { PStrIteratee::PStrSegment(_, pstr_atom, n) => {
let pstr = PartialString::from(pstr_atom); let pstr = PartialString::from(pstr_atom);
chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c))); chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c)));
@@ -1614,47 +1617,12 @@ impl MachineState {
// returns true on failure. // returns true on failure.
pub fn ground_test(&mut self) -> bool { pub fn ground_test(&mut self) -> bool {
use fxhash::FxBuildHasher; let iter = eager_stackful_preorder_iter(&mut self.heap, self.registers[1]);
if self.registers[1].is_constant() { for term in iter {
return false; if term.is_var() {
} return true;
let value = self.store(self.deref(self.registers[1]));
if value.is_stack_var() {
return true;
}
let mut visited = IndexSet::with_hasher(FxBuildHasher::default());
let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, value);
let mut stack_len = 0;
while let Some(value) = iter.next() {
let mut value = unmark_cell_bits!(value);
if value.is_var() {
value = heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value),
);
if value.is_var() {
return true;
}
} }
if value.is_compound(iter.heap) {
if visited.contains(&value) {
for _ in stack_len .. iter.stack_len() {
iter.pop_stack();
}
} else {
visited.insert(value);
}
}
stack_len = iter.stack_len();
} }
false false
@@ -1681,9 +1649,9 @@ impl MachineState {
Err(_) => {} Err(_) => {}
}, },
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
if let Some(b) = n.to_u8() { let b: u8 = (&*n).try_into().unwrap();
bytes.push(b);
} bytes.push(b);
} }
_ => {} _ => {}
} }

View File

@@ -2,15 +2,16 @@ pub use crate::arena::*;
pub use crate::atom_table::*; pub use crate::atom_table::*;
use crate::heap_print::*; use crate::heap_print::*;
pub use crate::machine::heap::*; pub use crate::machine::heap::*;
pub use crate::machine::*;
pub use crate::machine::machine_state::*; pub use crate::machine::machine_state::*;
pub use crate::machine::stack::*; pub use crate::machine::stack::*;
pub use crate::machine::streams::*; pub use crate::machine::streams::*;
pub use crate::macros::*; pub use crate::machine::*;
pub use crate::parser::ast::*; pub use crate::parser::ast::*;
use crate::read::*; use crate::read::*;
pub use crate::types::*; pub use crate::types::*;
use std::sync::Arc;
#[cfg(test)] #[cfg(test)]
use crate::machine::copier::CopierTarget; use crate::machine::copier::CopierTarget;
@@ -61,7 +62,7 @@ impl MockWAM {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.machine_st.heap, &mut self.machine_st.heap,
&mut self.machine_st.atom_tbl, Arc::clone(&self.machine_st.atom_tbl),
&mut self.machine_st.stack, &mut self.machine_st.stack,
&self.op_dir, &self.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
@@ -71,11 +72,9 @@ impl MockWAM {
printer.var_names = term_write_result printer.var_names = term_write_result
.var_dict .var_dict
.into_iter() .into_iter()
.map(|(var, cell)| { .map(|(var, cell)| match var {
match var { VarKey::VarPtr(var) => (cell, var.clone()),
VarKey::VarPtr(var) => (cell, var.clone()), VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string()))
}
}) })
.collect(); .collect();
@@ -222,111 +221,10 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
impl Machine { impl Machine {
pub fn with_test_streams() -> Self { pub fn with_test_streams() -> Self {
use ref_thread_local::RefThreadLocal; Machine::new(MachineConfig::in_memory())
let mut machine_st = MachineState::new();
let user_input = Stream::Null(StreamOptions::default());
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena);
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let mut wam = Machine {
machine_st,
indices: IndexStore::new(),
code: Code::new(),
user_input,
user_output,
user_error,
load_contexts: vec![],
runtime,
#[cfg(feature = "ffi")]
foreign_function_table: Default::default(),
};
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
wam.add_impls_to_indices();
bootstrapping_compile(
Stream::from_static_string(
LIBRARIES.borrow()["ops_and_meta_predicates"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(
atom!("ops_and_meta_predicates.pl"),
lib_path.clone(),
),
)
.unwrap();
bootstrapping_compile(
Stream::from_static_string(
LIBRARIES.borrow()["builtins"],
&mut wam.machine_st.arena,
),
&mut wam,
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
)
.unwrap();
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
&mut wam.indices.meta_predicates,
&CompilationTarget::User,
builtins,
);
import_builtin_impls(&wam.indices.code_dir, builtins);
} else {
unreachable!()
}
lib_path.pop(); // remove the "lib" at the end
bootstrapping_compile(
Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
&mut wam,
ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
)
.unwrap();
wam.configure_modules();
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
&mut wam.indices.meta_predicates,
&CompilationTarget::User,
loader,
);
} else {
unreachable!()
}
wam.load_special_forms();
wam.load_top_level();
wam.configure_streams();
wam
} }
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> { pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
use std::io::Read;
let stream = Stream::from_owned_string( let stream = Stream::from_owned_string(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(), std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
&mut self.machine_st.arena, &mut self.machine_st.arena,
@@ -335,6 +233,17 @@ impl Machine {
self.load_file(file.into(), stream); self.load_file(file.into(), stream);
self.user_output.bytes().map(|b| b.unwrap()).collect() self.user_output.bytes().map(|b| b.unwrap()).collect()
} }
pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
let stream = Stream::from_owned_string(
code.to_owned(),
&mut self.machine_st.arena,
);
self.load_file("<stdin>".into(), stream);
self.user_output.bytes().map(|b| b.unwrap()).collect()
}
} }
#[cfg(test)] #[cfg(test)]
@@ -346,26 +255,11 @@ mod tests {
let mut wam = MachineState::new(); let mut wam = MachineState::new();
let mut op_dir = default_op_dir(); let mut op_dir = default_op_dir();
op_dir.insert( op_dir.insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX as u8));
(atom!("+"), Fixity::In), op_dir.insert((atom!("-"), Fixity::In), OpDesc::build_with(500, YFX as u8));
OpDesc::build_with(500, YFX as u8), op_dir.insert((atom!("*"), Fixity::In), OpDesc::build_with(500, YFX as u8));
); op_dir.insert((atom!("/"), Fixity::In), OpDesc::build_with(400, YFX as u8));
op_dir.insert( op_dir.insert((atom!("="), Fixity::In), OpDesc::build_with(700, XFX as u8));
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("="), Fixity::In),
OpDesc::build_with(700, XFX as u8),
);
{ {
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
@@ -582,22 +476,10 @@ mod tests {
let mut wam = MachineState::new(); let mut wam = MachineState::new();
let mut op_dir = default_op_dir(); let mut op_dir = default_op_dir();
op_dir.insert( op_dir.insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX as u8));
(atom!("+"), Fixity::In), op_dir.insert((atom!("-"), Fixity::In), OpDesc::build_with(500, YFX as u8));
OpDesc::build_with(500, YFX as u8), op_dir.insert((atom!("*"), Fixity::In), OpDesc::build_with(400, YFX as u8));
); op_dir.insert((atom!("/"), Fixity::In), OpDesc::build_with(400, YFX as u8));
op_dir.insert(
(atom!("-"), Fixity::In),
OpDesc::build_with(500, YFX as u8),
);
op_dir.insert(
(atom!("*"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
op_dir.insert(
(atom!("/"), Fixity::In),
OpDesc::build_with(400, YFX as u8),
);
{ {
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
@@ -688,20 +570,12 @@ mod tests {
wam.heap.push(heap_loc_as_cell!(1)); wam.heap.push(heap_loc_as_cell!(1));
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(0)
),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, heap_loc_as_cell!(0), atom_as_cell!(atom!("a"))),
wam,
heap_loc_as_cell!(0),
atom_as_cell!(atom!("a"))
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
@@ -724,29 +598,17 @@ mod tests {
wam.heap.push(empty_list_as_cell!()); wam.heap.push(empty_list_as_cell!());
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
wam,
heap_loc_as_cell!(7),
heap_loc_as_cell!(7)
),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(7)),
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(7)
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, empty_list_as_cell!(), heap_loc_as_cell!(7)),
wam,
empty_list_as_cell!(),
heap_loc_as_cell!(7)
),
Some(Ordering::Less) Some(Ordering::Less)
); );
@@ -769,40 +631,24 @@ mod tests {
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, empty_list_as_cell!(), atom_as_cell!(atom!("atom"))),
wam,
empty_list_as_cell!(),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, atom_as_cell!(atom!("atom")), empty_list_as_cell!()),
wam,
atom_as_cell!(atom!("atom")),
empty_list_as_cell!()
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena)); let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, one_p_one, fixnum_as_cell!(Fixnum::build_with(1))),
wam,
one_p_one,
fixnum_as_cell!(Fixnum::build_with(1))
),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(wam, fixnum_as_cell!(Fixnum::build_with(1)), one_p_one),
wam,
fixnum_as_cell!(Fixnum::build_with(1)),
one_p_one
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
} }
@@ -821,7 +667,8 @@ mod tests {
all_cells_unmarked(&wam.heap); all_cells_unmarked(&wam.heap);
wam.heap.clear(); wam.heap.clear();
wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))])); wam.heap
.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0))); assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));

View File

@@ -5,18 +5,22 @@ pub mod code_walker;
#[macro_use] #[macro_use]
pub mod loader; pub mod loader;
pub mod compile; pub mod compile;
pub mod config;
pub mod copier; pub mod copier;
pub mod cycle_detection;
pub mod disjuncts;
pub mod dispatch; pub mod dispatch;
pub mod gc; pub mod gc;
pub mod heap; pub mod heap;
pub mod lib_machine;
pub mod load_state; pub mod load_state;
pub mod machine_errors; pub mod machine_errors;
pub mod machine_indices; pub mod machine_indices;
pub mod machine_state; pub mod machine_state;
pub mod machine_state_impl; pub mod machine_state_impl;
pub mod mock_wam; pub mod mock_wam;
pub mod parsed_results;
pub mod partial_string; pub mod partial_string;
pub mod disjuncts;
pub mod preprocessor; pub mod preprocessor;
pub mod stack; pub mod stack;
pub mod streams; pub mod streams;
@@ -27,9 +31,9 @@ pub mod unify;
use crate::arena::*; use crate::arena::*;
use crate::arithmetic::*; use crate::arithmetic::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*;
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
use crate::ffi::ForeignFunctionTable; use crate::ffi::ForeignFunctionTable;
use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::args::*; use crate::machine::args::*;
use crate::machine::compile::*; use crate::machine::compile::*;
@@ -51,9 +55,14 @@ use ordered_float::OrderedFloat;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::env; use std::env;
use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use tokio::runtime::Runtime;
use self::config::MachineConfig;
use self::parsed_results::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
lazy_static! { lazy_static! {
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
@@ -68,9 +77,9 @@ pub struct Machine {
pub(super) user_output: Stream, pub(super) user_output: Stream,
pub(super) user_error: Stream, pub(super) user_error: Stream,
pub(super) load_contexts: Vec<LoadContext>, pub(super) load_contexts: Vec<LoadContext>,
pub(super) runtime: Runtime,
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
pub(super) foreign_function_table: ForeignFunctionTable, pub(super) foreign_function_table: ForeignFunctionTable,
pub(super) rng: StdRng,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -109,6 +118,7 @@ include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0; pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0;
pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1; pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1;
pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2; pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2;
pub static LIB_QUERY_SUCCESS: usize = 3;
pub struct MachinePreludeView<'a> { pub struct MachinePreludeView<'a> {
pub indices: &'a mut IndexStore, pub indices: &'a mut IndexStore,
@@ -163,7 +173,10 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
for key in keys { for key in keys {
let idx = code_dir.get(&key).unwrap(); let idx = code_dir.get(&key).unwrap();
builtins.code_dir.insert(key, idx.clone()); builtins.code_dir.insert(key, idx.clone());
builtins.module_decl.exports.push(ModuleExport::PredicateKey(key)); builtins
.module_decl
.exports
.push(ModuleExport::PredicateKey(key));
} }
} }
@@ -194,7 +207,7 @@ impl Machine {
code: &mut self.code, code: &mut self.code,
load_contexts: &mut self.load_contexts, load_contexts: &mut self.load_contexts,
}, },
&mut self.machine_st &mut self.machine_st,
) )
} }
@@ -206,7 +219,11 @@ impl Machine {
self.machine_st.throw_exception(err); self.machine_st.throw_exception(err);
} }
fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) -> std::process::ExitCode { fn run_module_predicate(
&mut self,
module_name: Atom,
key: PredicateKey,
) -> std::process::ExitCode {
if let Some(module) = self.indices.modules.get(&module_name) { if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(ref code_index) = module.code_dir.get(&key) { if let Some(ref code_index) = module.code_dir.get(&key) {
let p = code_index.local().unwrap(); let p = code_index.local().unwrap();
@@ -223,23 +240,21 @@ impl Machine {
pub fn load_file(&mut self, path: &str, stream: Stream) { pub fn load_file(&mut self, path: &str, stream: Stream) {
self.machine_st.registers[1] = stream_as_cell!(stream); self.machine_st.registers[1] = stream_as_cell!(stream);
self.machine_st.registers[2] = atom_as_cell!( self.machine_st.registers[2] =
self.machine_st.atom_tbl.build_with(path) atom_as_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, path));
);
self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2)); self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2));
} }
fn load_top_level(&mut self) { fn load_top_level(&mut self, program: &'static str) {
let mut path_buf = current_dir(); let mut path_buf = current_dir();
path_buf.push("src/toplevel.pl"); path_buf.push("src/toplevel.pl");
let path = path_buf.to_str().unwrap(); let path = path_buf.to_str().unwrap();
let toplevel_stream = Stream::from_static_string( let toplevel_stream =
include_str!("../toplevel.pl"), Stream::from_static_string(program, &mut self.machine_st.arena);
&mut self.machine_st.arena,
);
self.load_file(path, toplevel_stream); self.load_file(path, toplevel_stream);
@@ -285,26 +300,40 @@ impl Machine {
} }
} }
pub fn run_top_level(&mut self) -> std::process::ExitCode { pub fn run_top_level(&mut self, module_name: Atom, key: PredicateKey) -> std::process::ExitCode {
let mut arg_pstrs = vec![]; let mut arg_pstrs = vec![];
for arg in env::args() { for arg in env::args() {
arg_pstrs.push(put_complete_string( arg_pstrs.push(put_complete_string(
&mut self.machine_st.heap, &mut self.machine_st.heap,
&arg, &arg,
&mut self.machine_st.atom_tbl, &self.machine_st.atom_tbl,
)); ));
} }
self.machine_st.registers[1] = heap_loc_as_cell!( self.machine_st.registers[1] = heap_loc_as_cell!(iter_to_heap_list(
iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter()) &mut self.machine_st.heap,
); arg_pstrs.into_iter()
));
self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1)) self.run_module_predicate(module_name, key)
}
pub fn set_user_input(&mut self, input: String) {
self.user_input = Stream::from_owned_string(input, &mut self.machine_st.arena);
}
pub fn get_user_output(&self) -> String {
let output_bytes: Vec<_> = self.user_output.bytes().map(|b| b.unwrap()).collect();
String::from_utf8(output_bytes).unwrap()
} }
pub(crate) fn configure_modules(&mut self) { pub(crate) fn configure_modules(&mut self) {
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir, arena: &mut Arena) { fn update_call_n_indices(
loader: &Module,
target_code_dir: &mut CodeDir,
arena: &mut Arena,
) {
for arity in 1..66 { for arity in 1..66 {
let key = (atom!("call"), arity); let key = (atom!("call"), arity);
@@ -349,10 +378,18 @@ impl Machine {
} }
for (_, target_module) in self.indices.modules.iter_mut() { for (_, target_module) in self.indices.modules.iter_mut() {
update_call_n_indices(&loader, &mut target_module.code_dir, &mut self.machine_st.arena); update_call_n_indices(
&loader,
&mut target_module.code_dir,
&mut self.machine_st.arena,
);
} }
update_call_n_indices(&loader, &mut self.indices.code_dir, &mut self.machine_st.arena); update_call_n_indices(
&loader,
&mut self.indices.code_dir,
&mut self.machine_st.arena,
);
self.indices.modules.insert(atom!("loader"), loader); self.indices.modules.insert(atom!("loader"), loader);
} else { } else {
@@ -361,80 +398,90 @@ impl Machine {
} }
pub(crate) fn add_impls_to_indices(&mut self) { pub(crate) fn add_impls_to_indices(&mut self) {
let impls_offset = self.code.len() + 3; let impls_offset = self.code.len() + 4;
self.code.extend(vec![ self.code.extend(
Instruction::BreakFromDispatchLoop, vec![
Instruction::InstallVerifyAttr, Instruction::BreakFromDispatchLoop,
Instruction::VerifyAttrInterrupt, Instruction::InstallVerifyAttr,
Instruction::ExecuteTermGreaterThan, Instruction::VerifyAttrInterrupt,
Instruction::ExecuteTermLessThan, Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS
Instruction::ExecuteTermGreaterThanOrEqual, Instruction::ExecuteTermGreaterThan,
Instruction::ExecuteTermLessThanOrEqual, Instruction::ExecuteTermLessThan,
Instruction::ExecuteTermEqual, Instruction::ExecuteTermGreaterThanOrEqual,
Instruction::ExecuteTermNotEqual, Instruction::ExecuteTermLessThanOrEqual,
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), Instruction::ExecuteTermEqual,
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), Instruction::ExecuteTermNotEqual,
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), Instruction::ExecuteNumberGreaterThanOrEqual(
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))), ar_reg!(temp_v!(1)),
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))), ar_reg!(temp_v!(2)),
Instruction::ExecuteAcyclicTerm, ),
Instruction::ExecuteArg, Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteCompare, Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteCopyTerm, Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteFunctor, Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))),
Instruction::ExecuteGround, Instruction::ExecuteAcyclicTerm,
Instruction::ExecuteKeySort, Instruction::ExecuteArg,
Instruction::ExecuteSort, Instruction::ExecuteCompare,
Instruction::ExecuteN(1), Instruction::ExecuteCopyTerm,
Instruction::ExecuteN(2), Instruction::ExecuteFunctor,
Instruction::ExecuteN(3), Instruction::ExecuteGround,
Instruction::ExecuteN(4), Instruction::ExecuteKeySort,
Instruction::ExecuteN(5), Instruction::ExecuteSort,
Instruction::ExecuteN(6), Instruction::ExecuteN(1),
Instruction::ExecuteN(7), Instruction::ExecuteN(2),
Instruction::ExecuteN(8), Instruction::ExecuteN(3),
Instruction::ExecuteN(9), Instruction::ExecuteN(4),
Instruction::ExecuteIsAtom(temp_v!(1)), Instruction::ExecuteN(5),
Instruction::ExecuteIsAtomic(temp_v!(1)), Instruction::ExecuteN(6),
Instruction::ExecuteIsCompound(temp_v!(1)), Instruction::ExecuteN(7),
Instruction::ExecuteIsInteger(temp_v!(1)), Instruction::ExecuteN(8),
Instruction::ExecuteIsNumber(temp_v!(1)), Instruction::ExecuteN(9),
Instruction::ExecuteIsRational(temp_v!(1)), Instruction::ExecuteIsAtom(temp_v!(1)),
Instruction::ExecuteIsFloat(temp_v!(1)), Instruction::ExecuteIsAtomic(temp_v!(1)),
Instruction::ExecuteIsNonVar(temp_v!(1)), Instruction::ExecuteIsCompound(temp_v!(1)),
Instruction::ExecuteIsVar(temp_v!(1)) Instruction::ExecuteIsInteger(temp_v!(1)),
].into_iter()); Instruction::ExecuteIsNumber(temp_v!(1)),
Instruction::ExecuteIsRational(temp_v!(1)),
Instruction::ExecuteIsFloat(temp_v!(1)),
Instruction::ExecuteIsNonVar(temp_v!(1)),
Instruction::ExecuteIsVar(temp_v!(1)),
]
.into_iter(),
);
for (p, instr) in self.code[impls_offset ..].iter().enumerate() { for (p, instr) in self.code[impls_offset..].iter().enumerate() {
let key = instr.to_name_and_arity(); let key = instr.to_name_and_arity();
self.indices.code_dir.insert( self.indices.code_dir.insert(
key, key,
CodeIndex::new(IndexPtr::index(p + impls_offset), &mut self.machine_st.arena), CodeIndex::new(
IndexPtr::index(p + impls_offset),
&mut self.machine_st.arena,
),
); );
} }
} }
pub fn new() -> Self { pub fn new(config: MachineConfig) -> Self {
use ref_thread_local::RefThreadLocal; use ref_thread_local::RefThreadLocal;
let args = MachineArgs::new(); let args = MachineArgs::new();
let mut machine_st = MachineState::new(); let mut machine_st = MachineState::new();
let user_input = Stream::stdin(&mut machine_st.arena, args.add_history); let (user_input, user_output, user_error) = match config.streams {
let user_output = Stream::stdout(&mut machine_st.arena); config::StreamConfig::Stdio => (
let user_error = Stream::stderr(&mut machine_st.arena); Stream::stdin(&mut machine_st.arena, args.add_history),
Stream::stdout(&mut machine_st.arena),
#[cfg(not(target_os = "wasi"))] Stream::stderr(&mut machine_st.arena),
let runtime = tokio::runtime::Runtime::new() ),
.unwrap(); config::StreamConfig::Memory => (
#[cfg(target_os = "wasi")] Stream::Null(StreamOptions::default()),
let runtime = tokio::runtime::Builder::new_current_thread() Stream::from_owned_string("".to_owned(), &mut machine_st.arena),
.enable_all() Stream::stderr(&mut machine_st.arena),
.build() ),
.unwrap(); };
let mut wam = Machine { let mut wam = Machine {
machine_st, machine_st,
@@ -444,9 +491,9 @@ impl Machine {
user_output, user_output,
user_error, user_error,
load_contexts: vec![], load_contexts: vec![],
runtime,
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
foreign_function_table: Default::default(), foreign_function_table: Default::default(),
rng: StdRng::from_entropy(),
}; };
let mut lib_path = current_dir(); let mut lib_path = current_dir();
@@ -470,10 +517,7 @@ impl Machine {
.unwrap(); .unwrap();
bootstrapping_compile( bootstrapping_compile(
Stream::from_static_string( Stream::from_static_string(LIBRARIES.borrow()["builtins"], &mut wam.machine_st.arena),
LIBRARIES.borrow()["builtins"],
&mut wam.machine_st.arena,
),
&mut wam, &mut wam,
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()), ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
) )
@@ -519,14 +563,16 @@ impl Machine {
} }
wam.load_special_forms(); wam.load_special_forms();
wam.load_top_level(); wam.load_top_level(config.toplevel);
wam.configure_streams(); wam.configure_streams();
wam wam
} }
pub(crate) fn configure_streams(&mut self) { pub(crate) fn configure_streams(&mut self) {
self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input"))); self.user_input
.options_mut()
.set_alias_to_atom_opt(Some(atom!("user_input")));
self.indices self.indices
.stream_aliases .stream_aliases
@@ -534,7 +580,9 @@ impl Machine {
self.indices.streams.insert(self.user_input); self.indices.streams.insert(self.user_input);
self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output"))); self.user_output
.options_mut()
.set_alias_to_atom_opt(Some(atom!("user_output")));
self.indices self.indices
.stream_aliases .stream_aliases
@@ -564,9 +612,16 @@ impl Machine {
loop { loop {
let indexing_code_ptr = match &indexing_lines[oip] { let indexing_code_ptr = match &indexing_lines[oip] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, v, c, l, s)) => { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
arg,
v,
c,
l,
s,
)) => {
cell = self.deref_register(arg); cell = self.deref_register(arg);
self.machine_st.select_switch_on_term_index(cell, v, c, l, s) self.machine_st
.select_switch_on_term_index(cell, v, c, l, s)
} }
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
let lit = self.machine_st.constant_to_literal(cell); let lit = self.machine_st.constant_to_literal(cell);
@@ -676,7 +731,12 @@ impl Machine {
} }
); );
} }
&Instruction::GetPartialString(Level::Shallow, string, RegType::Temp(t), has_tail) => { &Instruction::GetPartialString(
Level::Shallow,
string,
RegType::Temp(t),
has_tail,
) => {
let cell = self.deref_register(t); let cell = self.deref_register(t);
read_heap_cell!(cell, read_heap_cell!(cell,
@@ -707,17 +767,17 @@ impl Machine {
} }
); );
} }
Instruction::GetConstant(..) | Instruction::GetConstant(..)
Instruction::GetList(..) | | Instruction::GetList(..)
Instruction::GetStructure(..) | | Instruction::GetStructure(..)
Instruction::GetPartialString(..) | | Instruction::GetPartialString(..)
&Instruction::UnifyVoid(..) | | &Instruction::UnifyVoid(..)
&Instruction::UnifyConstant(..) | | &Instruction::UnifyConstant(..)
&Instruction::GetVariable(..) | | &Instruction::GetVariable(..)
&Instruction::GetValue(..) | | &Instruction::GetValue(..)
&Instruction::UnifyVariable(..) | | &Instruction::UnifyVariable(..)
&Instruction::UnifyValue(..) | | &Instruction::UnifyValue(..)
&Instruction::UnifyLocalValue(..) => { | &Instruction::UnifyLocalValue(..) => {
offset += 1; offset += 1;
} }
_ => { _ => {
@@ -732,9 +792,10 @@ impl Machine {
fn next_applicable_clause(&mut self, mut offset: usize) -> Option<usize> { fn next_applicable_clause(&mut self, mut offset: usize) -> Option<usize> {
while !self.next_clause_applicable(self.machine_st.p + offset + 1) { while !self.next_clause_applicable(self.machine_st.p + offset + 1) {
match &self.code[self.machine_st.p + offset] { match &self.code[self.machine_st.p + offset] {
&Instruction::DefaultRetryMeElse(o) | &Instruction::RetryMeElse(o) | &Instruction::DefaultRetryMeElse(o)
&Instruction::DynamicElse(.., NextOrFail::Next(o)) | | &Instruction::RetryMeElse(o)
&Instruction::DynamicInternalElse(.., NextOrFail::Next(o)) => offset += o, | &Instruction::DynamicElse(.., NextOrFail::Next(o))
| &Instruction::DynamicInternalElse(.., NextOrFail::Next(o)) => offset += o,
_ => { _ => {
return None; return None;
} }
@@ -753,14 +814,16 @@ impl Machine {
match &indexing_lines[self.machine_st.oip as usize] { match &indexing_lines[self.machine_st.oip as usize] {
IndexingLine::IndexedChoice(indexed_choice) => { IndexingLine::IndexedChoice(indexed_choice) => {
match &indexed_choice[(self.machine_st.iip + inner_offset) as usize] { match &indexed_choice[(self.machine_st.iip + inner_offset) as usize] {
&IndexedChoiceInstruction::Retry(o) => { &IndexedChoiceInstruction::Retry(o)
| &IndexedChoiceInstruction::DefaultRetry(o) => {
if self.next_clause_applicable(self.machine_st.p + o) { if self.next_clause_applicable(self.machine_st.p + o) {
return Some(inner_offset); return Some(inner_offset);
} }
inner_offset += 1; inner_offset += 1;
} }
&IndexedChoiceInstruction::Trust(o) => { &IndexedChoiceInstruction::Trust(o)
| &IndexedChoiceInstruction::DefaultTrust(o) => {
return if self.next_clause_applicable(self.machine_st.p + o) { return if self.next_clause_applicable(self.machine_st.p + o) {
Some(inner_offset) Some(inner_offset)
} else { } else {
@@ -813,12 +876,13 @@ impl Machine {
or_frame.prelude.tr = self.machine_st.tr; or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len(); or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.b0 = self.machine_st.b0; or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); or_frame.prelude.attr_var_queue_len =
self.machine_st.attr_var_init.attr_var_queue.len();
self.machine_st.b = b; self.machine_st.b = b;
for i in 0..n { for i in 0..n {
or_frame[i] = self.machine_st.registers[i+1]; or_frame[i] = self.machine_st.registers[i + 1];
} }
self.machine_st.hb = self.machine_st.heap.len(); self.machine_st.hb = self.machine_st.heap.len();
@@ -844,12 +908,13 @@ impl Machine {
or_frame.prelude.tr = self.machine_st.tr; or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len(); or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.b0 = self.machine_st.b0; or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); or_frame.prelude.attr_var_queue_len =
self.machine_st.attr_var_init.attr_var_queue.len();
self.machine_st.b = b; self.machine_st.b = b;
for i in 0..n { for i in 0..n {
or_frame[i] = self.machine_st.registers[i+1]; or_frame[i] = self.machine_st.registers[i + 1];
} }
self.machine_st.hb = self.machine_st.heap.len(); self.machine_st.hb = self.machine_st.heap.len();
@@ -912,7 +977,7 @@ impl Machine {
let curr_tr = self.machine_st.tr; let curr_tr = self.machine_st.tr;
for i in 0..n { for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i]; self.machine_st.registers[i + 1] = or_frame[i];
} }
self.unwind_trail(old_tr, curr_tr); self.unwind_trail(old_tr, curr_tr);
@@ -956,7 +1021,7 @@ impl Machine {
let curr_tr = self.machine_st.tr; let curr_tr = self.machine_st.tr;
for i in 0..n { for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i]; self.machine_st.registers[i + 1] = or_frame[i];
} }
self.unwind_trail(old_tr, curr_tr); self.unwind_trail(old_tr, curr_tr);
@@ -999,7 +1064,7 @@ impl Machine {
let n = or_frame.prelude.num_cells; let n = or_frame.prelude.num_cells;
for i in 0..n { for i in 0..n {
self.machine_st.registers[i+1] = or_frame[i]; self.machine_st.registers[i + 1] = or_frame[i];
} }
let old_tr = or_frame.prelude.tr; let old_tr = or_frame.prelude.tr;
@@ -1038,15 +1103,17 @@ impl Machine {
#[inline(always)] #[inline(always)]
fn undefined_procedure(&mut self, name: Atom, arity: usize) -> CallResult { fn undefined_procedure(&mut self, name: Atom, arity: usize) -> CallResult {
match self.machine_st.flags.unknown { match self.machine_st.flags.unknown {
Unknown::Error => { Unknown::Error => Err(self.machine_st.throw_undefined_error(name, arity)),
Err(self.machine_st.throw_undefined_error(name, arity))
}
Unknown::Fail => { Unknown::Fail => {
self.machine_st.fail = true; self.machine_st.fail = true;
Ok(()) Ok(())
} }
Unknown::Warn => { Unknown::Warn => {
println!("warning: predicate {}/{} is undefined", name.as_str(), arity); println!(
"warning: predicate {}/{} is undefined",
name.as_str(),
arity
);
self.machine_st.fail = true; self.machine_st.fail = true;
Ok(()) Ok(())
} }
@@ -1091,9 +1158,7 @@ impl Machine {
self.machine_st.dynamic_mode = FirstOrNext::First; self.machine_st.dynamic_mode = FirstOrNext::First;
self.machine_st.execute_at_index(arity, compiled_tl_index); self.machine_st.execute_at_index(arity, compiled_tl_index);
} }
IndexPtrTag::Index => { IndexPtrTag::Index => self.machine_st.execute_at_index(arity, compiled_tl_index),
self.machine_st.execute_at_index(arity, compiled_tl_index)
}
} }
Ok(()) Ok(())
@@ -1118,7 +1183,9 @@ impl Machine {
} }
} else { } else {
let stub = functor_stub(name, arity); let stub = functor_stub(name, arity);
let err = self.machine_st.module_resolution_error(module_name, name, arity); let err = self
.machine_st
.existence_error(ExistenceError::QualifiedProcedure { module_name, name, arity });
Err(self.machine_st.error_form(err, stub)) Err(self.machine_st.error_form(err, stub))
} }
@@ -1144,7 +1211,9 @@ impl Machine {
} }
} else { } else {
let stub = functor_stub(name, arity); let stub = functor_stub(name, arity);
let err = self.machine_st.module_resolution_error(module_name, name, arity); let err = self
.machine_st
.existence_error(ExistenceError::QualifiedProcedure { module_name, name, arity });
Err(self.machine_st.error_form(err, stub)) Err(self.machine_st.error_form(err, stub))
} }
@@ -1178,12 +1247,16 @@ impl Machine {
let r_c_wo_h_atom = atom!("run_cleaners_without_handling"); let r_c_wo_h_atom = atom!("run_cleaners_without_handling");
let iso_ext = atom!("iso_ext"); let iso_ext = atom!("iso_ext");
RCWH = self.indices.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext) RCWH = self
.and_then(|item| item.local()) .indices
.unwrap(); .get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
RCWOH = self.indices.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext) .and_then(|item| item.local())
.and_then(|item| item.local()) .unwrap();
.unwrap(); RCWOH = self
.indices
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
.and_then(|item| item.local())
.unwrap();
}); });
(RCWH, RCWOH) (RCWH, RCWOH)
@@ -1194,9 +1267,8 @@ impl Machine {
let (idx, arity) = if self.machine_st.effective_block() > prev_block { let (idx, arity) = if self.machine_st.effective_block() > prev_block {
(r_c_w_h, 0) (r_c_w_h, 0)
} else { } else {
self.machine_st.registers[1] = fixnum_as_cell!( self.machine_st.registers[1] =
Fixnum::build_with(b_cutoff as i64) fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64));
);
(r_c_wo_h, 1) (r_c_wo_h, 1)
}; };
@@ -1263,9 +1335,8 @@ impl Machine {
None => unreachable!(), None => unreachable!(),
} }
} }
TrailEntryTag::TrailedAttachedValue => { TrailEntryTag::TrailedAttachedValue => {}
}
} }
} }
} }
} }

View File

@@ -0,0 +1,285 @@
use crate::atom_table::*;
use ordered_float::OrderedFloat;
use dashu::*;
use std::collections::BTreeMap;
use std::collections::HashMap;
pub type QueryResult = Result<QueryResolution, String>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryResolution {
True,
False,
Matches(Vec<QueryMatch>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryMatch {
pub bindings: BTreeMap<String, Value>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryResolutionLine {
True,
False,
Match(BTreeMap<String, Value>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
Integer(Integer),
Rational(Rational),
Float(OrderedFloat<f64>),
Atom(Atom),
String(String),
List(Vec<Value>),
Structure(Atom, Vec<Value>),
Var,
}
impl From<BTreeMap<&str, Value>> for QueryMatch {
fn from(bindings: BTreeMap<&str, Value>) -> Self {
QueryMatch {
bindings: bindings
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect::<BTreeMap<_, _>>(),
}
}
}
impl From<BTreeMap<String, Value>> for QueryMatch {
fn from(bindings: BTreeMap<String, Value>) -> Self {
QueryMatch { bindings }
}
}
impl From<Vec<QueryResolutionLine>> for QueryResolution {
fn from(query_result_lines: Vec<QueryResolutionLine>) -> Self {
// If there is only one line, and it is true or false, return that.
if query_result_lines.len() == 1 {
match query_result_lines[0].clone() {
QueryResolutionLine::True => return QueryResolution::True,
QueryResolutionLine::False => return QueryResolution::False,
_ => {}
}
}
// If there is only one line, and it is an empty match, return true.
if query_result_lines.len() == 1 {
match query_result_lines[0].clone() {
QueryResolutionLine::Match(m) => {
if m.is_empty() {
return QueryResolution::True;
}
}
_ => {}
}
}
// If there is at least one line with true and no matches, return true.
if query_result_lines
.iter()
.any(|l| l == &QueryResolutionLine::True)
&& !query_result_lines.iter().any(|l| {
if let &QueryResolutionLine::Match(_) = l {
true
} else {
false
}
})
{
return QueryResolution::True;
}
// If there is at least one match, return all matches.
let all_matches = query_result_lines
.into_iter()
.filter(|l| {
if let &QueryResolutionLine::Match(_) = l {
true
} else {
false
}
})
.map(|l| match l {
QueryResolutionLine::Match(m) => QueryMatch::from(m),
_ => unreachable!(),
})
.collect::<Vec<_>>();
if !all_matches.is_empty() {
return QueryResolution::Matches(all_matches);
}
QueryResolution::False
}
}
fn split_response_string(input: &str) -> Vec<String> {
let mut level_bracket = 0;
let mut level_parenthesis = 0;
let mut in_double_quotes = false;
let mut in_single_quotes = false;
let mut start = 0;
let mut result = Vec::new();
for (i, c) in input.chars().enumerate() {
match c {
'[' => level_bracket += 1,
']' => level_bracket -= 1,
'(' => level_parenthesis += 1,
')' => level_parenthesis -= 1,
'"' => in_double_quotes = !in_double_quotes,
'\'' => in_single_quotes = !in_single_quotes,
',' if level_bracket == 0 && level_parenthesis == 0 && !in_double_quotes && !in_single_quotes => {
result.push(input[start..i].trim().to_string());
start = i + 1;
}
_ => {}
}
}
result.push(input[start..].trim().to_string());
result
}
fn split_key_value_pairs(input: &str) -> Vec<(String, String)> {
let items = split_response_string(input);
let mut result = Vec::new();
for item in items {
let parts: Vec<&str> = item.splitn(2, '=').collect();
if parts.len() == 2 {
let key = parts[0].trim().to_string();
let value = parts[1].trim().to_string();
result.push((key, value));
}
}
result
}
fn parse_prolog_response(input: &str) -> HashMap<String, String> {
let mut map: HashMap<String, String> = HashMap::new();
// Use regex to match strings including commas inside them
for result in split_key_value_pairs(input) {
let key = result.0;
let value = result.1;
// cut off at given characters/strings:
let value = value.split("\n").next().unwrap().to_string();
let value = value.split(" ").next().unwrap().to_string();
let value = value.split("\t").next().unwrap().to_string();
let value = value.split("error").next().unwrap().to_string();
map.insert(key, value);
}
map
}
impl TryFrom<String> for QueryResolutionLine {
type Error = ();
fn try_from(string: String) -> Result<Self, Self::Error> {
match string.as_str() {
"true" => Ok(QueryResolutionLine::True),
"false" => Ok(QueryResolutionLine::False),
_ => Ok(QueryResolutionLine::Match(
parse_prolog_response(&string)
.iter()
.map(|(k, v)| -> Result<(String, Value), ()> {
let key = k.to_string();
let value = v.to_string();
Ok((key, Value::try_from(value)?))
})
.filter_map(Result::ok)
.collect::<BTreeMap<_, _>>()
)
),
}
}
}
fn split_nested_list(input: &str) -> Vec<String> {
let mut level = 0;
let mut start = 0;
let mut result = Vec::new();
for (i, c) in input.chars().enumerate() {
match c {
'[' => level += 1,
']' => level -= 1,
',' if level == 0 => {
result.push(input[start..i].trim().to_string());
start = i + 1;
}
_ => {}
}
}
result.push(input[start..].trim().to_string());
result
}
impl TryFrom<String> for Value {
type Error = ();
fn try_from(string: String) -> Result<Self, Self::Error> {
let trimmed = string.trim();
if let Ok(float_value) = string.parse::<f64>() {
Ok(Value::Float(OrderedFloat(float_value)))
} else if let Ok(int_value) = string.parse::<i128>() {
Ok(Value::Integer(int_value.into()))
} else if trimmed.starts_with("'") && trimmed.ends_with("'") {
Ok(Value::String(trimmed[1..trimmed.len() - 1].into()))
} else if trimmed.starts_with("\"") && trimmed.ends_with("\"") {
Ok(Value::String(trimmed[1..trimmed.len() - 1].into()))
} else if trimmed.starts_with("[") && trimmed.ends_with("]") {
let split = split_nested_list(&trimmed[1..trimmed.len() - 1]);
let values = split
.into_iter()
.map(Value::try_from)
.collect::<Result<Vec<_>, _>>()?;
Ok(Value::List(values))
} else if trimmed.starts_with("{") && trimmed.ends_with("}") {
let mut iter = trimmed[1..trimmed.len() - 1].split(",");
let mut values = vec![];
while let Some(value) = iter.next() {
let items: Vec<_> = value.split(":").collect();
if items.len() == 2 {
let _key = items[0].to_string();
let value = items[1].to_string();
values.push(Value::try_from(value)?);
}
}
Ok(Value::Structure(atom!("{}"), values))
} else if trimmed.starts_with("<<") && trimmed.ends_with(">>") {
let mut iter = trimmed[2..trimmed.len() - 2].split(",");
let mut values = vec![];
while let Some(value) = iter.next() {
let items: Vec<_> = value.split(":").collect();
if items.len() == 2 {
let _key = items[0].to_string();
let value = items[1].to_string();
values.push(Value::try_from(value)?);
}
}
Ok(Value::Structure(atom!("<<>>"), values))
} else if !trimmed.contains(",") && !trimmed.contains("'") && !trimmed.contains("\"") {
Ok(Value::String(trimmed.into()))
} else {
Err(())
}
}
}
impl From<&str> for Value {
fn from(str: &str) -> Self {
Value::String(str.to_string())
}
}

View File

@@ -43,11 +43,10 @@ impl Into<Atom> for PartialString {
impl PartialString { impl PartialString {
#[inline] #[inline]
pub(super) fn new<'a>(src: &'a str, atom_tbl: &mut AtomTable) -> Option<(Self, &'a str)> { pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> {
let terminator_idx = scan_for_terminator(src.chars()); let terminator_idx = scan_for_terminator(src.chars());
let pstr = PartialString(atom_tbl.build_with(&src[.. terminator_idx])); let pstr = PartialString(AtomTable::build_with(&atom_tbl, &src[..terminator_idx]));
Some(if terminator_idx < src.as_bytes().len() {
Some(if terminator_idx < src.as_bytes().len() {
(pstr, &src[terminator_idx + 1..]) (pstr, &src[terminator_idx + 1..])
} else { } else {
(pstr, "") (pstr, "")
@@ -55,8 +54,8 @@ impl PartialString {
} }
#[inline(always)] #[inline(always)]
pub(crate) fn as_str_from(&self, n: usize) -> &str { pub(crate) fn as_str_from(&self, n: usize) -> AtomString {
&self.0.as_str()[n..] self.0.as_str().map(|str| &str[n..])
} }
} }
@@ -124,11 +123,15 @@ impl<'a> HeapPStrIter<'a> {
let mut final_result = None; let mut final_result = None;
while let Some(PStrIterStep { iteratee, next_hare }) = self.step(self.brent_st.hare) { while let Some(PStrIterStep {
iteratee,
next_hare,
}) = self.step(self.brent_st.hare)
{
self.brent_st.hare = next_hare; self.brent_st.hare = next_hare;
self.focus = self.heap[iteratee.focus()]; self.focus = self.heap[iteratee.focus()];
result.focus = iteratee.focus(); result.focus = iteratee.focus();
result.offset = iteratee.offset(); result.offset = iteratee.offset();
match iteratee { match iteratee {
@@ -151,7 +154,7 @@ impl<'a> HeapPStrIter<'a> {
let s = &s[result.prefix_len..]; let s = &s[result.prefix_len..];
if s.len() >= t.len() { if s.len() >= t.len() {
if s.starts_with(t) { if (&*s).starts_with(&*t) {
result.prefix_len += t.len(); result.prefix_len += t.len();
result.offset += t.len(); result.offset += t.len();
} else { } else {
@@ -202,7 +205,7 @@ impl<'a> HeapPStrIter<'a> {
self.brent_st.hare = self.orig_focus; self.brent_st.hare = self.orig_focus;
self.brent_st.tortoise = self.orig_focus; self.brent_st.tortoise = self.orig_focus;
for _ in 0 .. self.brent_st.lam { for _ in 0..self.brent_st.lam {
self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare;
} }
@@ -225,7 +228,7 @@ impl<'a> HeapPStrIter<'a> {
} }
PStrIteratee::PStrSegment(_, pstr_atom, n) => { PStrIteratee::PStrSegment(_, pstr_atom, n) => {
let pstr = PartialString::from(pstr_atom); let pstr = PartialString::from(pstr_atom);
buf += pstr.as_str_from(n); buf += &*pstr.as_str_from(n);
} }
} }
} }
@@ -238,43 +241,43 @@ impl<'a> HeapPStrIter<'a> {
let mut focus = self.focus; let mut focus = self.focus;
loop { loop {
read_heap_cell!(focus, read_heap_cell!(focus,
(HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
return true; return true;
} }
(HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here? (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here?
return name == atom!(".") && arity == 2; return name == atom!(".") && arity == 2;
} }
(HeapCellValueTag::Lis, h) => { (HeapCellValueTag::Lis, h) => {
let value = self.heap[h]; let value = self.heap[h];
let value = heap_bound_store( let value = heap_bound_store(
self.heap, self.heap,
heap_bound_deref(self.heap, value), heap_bound_deref(self.heap, value),
); );
return read_heap_cell!(value, return read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
arity == 0 && name.as_char().is_some() arity == 0 && name.as_char().is_some()
} }
(HeapCellValueTag::Char) => { (HeapCellValueTag::Char) => {
true true
} }
_ => { _ => {
false false
} }
); );
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if focus == self.heap[h] { if focus == self.heap[h] {
return false; return false;
} }
focus = self.heap[h]; focus = self.heap[h];
} }
_ => { _ => {
return false; return false;
} }
); );
} }
} }
@@ -381,13 +384,15 @@ impl<'a> HeapPStrIter<'a> {
} }
fn pre_cycle_discovery_stepper(&mut self) -> Option<PStrIteratee> { fn pre_cycle_discovery_stepper(&mut self) -> Option<PStrIteratee> {
let PStrIterStep { iteratee, next_hare } = let PStrIterStep {
match self.step(self.brent_st.hare) { iteratee,
Some(results) => results, next_hare,
None => { } = match self.step(self.brent_st.hare) {
return None; Some(results) => results,
} None => {
}; return None;
}
};
self.focus = self.heap[iteratee.focus()]; self.focus = self.heap[iteratee.focus()];
@@ -421,13 +426,15 @@ impl<'a> HeapPStrIter<'a> {
return None; return None;
} }
let PStrIterStep { iteratee, next_hare } = let PStrIterStep {
match self.step(self.brent_st.hare) { iteratee,
Some(results) => results, next_hare,
None => { } = match self.step(self.brent_st.hare) {
return None; Some(results) => results,
} None => {
}; return None;
}
};
self.focus = self.heap[next_hare]; self.focus = self.heap[next_hare];
self.brent_st.hare = next_hare; self.brent_st.hare = next_hare;
@@ -515,11 +522,8 @@ impl<'a> Iterator for PStrCharsIter<'a> {
match pstr.as_str_from(n).chars().next() { match pstr.as_str_from(n).chars().next() {
Some(c) => { Some(c) => {
self.item = Some(PStrIteratee::PStrSegment( self.item =
f1, Some(PStrIteratee::PStrSegment(f1, pstr_atom, n + c.len_utf8()));
pstr_atom,
n + c.len_utf8(),
));
return Some(c); return Some(c);
} }
@@ -684,8 +688,10 @@ pub fn compare_pstr_prefixes<'a>(
} }
} }
} }
(PStrIteratee::PStrSegment(f1, pstr1_atom, n1), (
PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
PStrIteratee::PStrSegment(f2, pstr2_atom, n2),
) => {
if pstr1_atom == pstr2_atom && n1 == n2 { if pstr1_atom == pstr2_atom && n1 == n2 {
cycle_detection_step(i1, i2, &step_1); cycle_detection_step(i1, i2, &step_1);
let both_cyclic = cycle_detection_step(i2, i1, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
@@ -707,7 +713,7 @@ pub fn compare_pstr_prefixes<'a>(
let str2 = pstr2.as_str_from(n2); let str2 = pstr2.as_str_from(n2);
match str1.len().cmp(&str2.len()) { match str1.len().cmp(&str2.len()) {
Ordering::Equal if str1 == str2 => { Ordering::Equal if &*str1 == &*str2 => {
cycle_detection_step(i1, i2, &step_1); cycle_detection_step(i1, i2, &step_1);
let both_cyclic = cycle_detection_step(i2, i1, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
@@ -718,8 +724,9 @@ pub fn compare_pstr_prefixes<'a>(
continue; continue;
} }
} }
Ordering::Less if str2.starts_with(str1) => { Ordering::Less if str2.starts_with(&*str1) => {
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); step_2.iteratee =
PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len());
let c1_result = cycle_detection_step(i1, i2, &step_1); let c1_result = cycle_detection_step(i1, i2, &step_1);
r1 = step(i1, i1.brent_st.hare); r1 = step(i1, i1.brent_st.hare);
@@ -727,8 +734,9 @@ pub fn compare_pstr_prefixes<'a>(
continue; continue;
} }
} }
Ordering::Greater if str1.starts_with(str2) => { Ordering::Greater if str1.starts_with(&*str2) => {
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); step_1.iteratee =
PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len());
let c2_result = cycle_detection_step(i2, i1, &step_2); let c2_result = cycle_detection_step(i2, i1, &step_2);
r2 = step(i2, i2.brent_st.hare); r2 = step(i2, i2.brent_st.hare);
@@ -737,7 +745,7 @@ pub fn compare_pstr_prefixes<'a>(
} }
} }
_ => { _ => {
return PStrCmpResult::Ordered(str1.cmp(str2)); return PStrCmpResult::Ordered(str1.cmp(&*str2));
} }
} }
} }
@@ -796,11 +804,8 @@ mod test {
fn pstr_iter_tests() { fn pstr_iter_tests() {
let mut wam = MockWAM::new(); let mut wam = MockWAM::new();
let pstr_var_cell = put_partial_string( let pstr_var_cell =
&mut wam.machine_st.heap, put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
"abc ",
&mut wam.machine_st.atom_tbl,
);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
@@ -819,11 +824,8 @@ mod test {
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2)); wam.machine_st.heap.push(pstr_loc_as_cell!(2));
let pstr_second_var_cell = put_partial_string( let pstr_second_var_cell =
&mut wam.machine_st.heap, put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
"def",
&mut wam.machine_st.atom_tbl,
);
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
@@ -836,7 +838,11 @@ mod test {
); );
assert_eq!( assert_eq!(
iter.next(), iter.next(),
Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) Some(PStrIteratee::PStrSegment(
2,
cell_as_atom!(pstr_second_cell),
0
))
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
@@ -855,7 +861,11 @@ mod test {
); );
assert_eq!( assert_eq!(
iter.next(), iter.next(),
Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) Some(PStrIteratee::PStrSegment(
2,
cell_as_atom!(pstr_second_cell),
0
))
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
@@ -863,10 +873,14 @@ mod test {
} }
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st
.heap
.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0)));
{ {
let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
@@ -892,31 +906,25 @@ mod test {
// construct a structurally similar but different cyclic partial string // construct a structurally similar but different cyclic partial string
// matching the one beginning at wam.machine_st.heap[0]. // matching the one beginning at wam.machine_st.heap[0].
put_partial_string( put_partial_string(&mut wam.machine_st.heap, "ab", &wam.machine_st.atom_tbl);
&mut wam.machine_st.heap,
"ab",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+2)); wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 2));
put_partial_string( put_partial_string(&mut wam.machine_st.heap, "c ", &wam.machine_st.atom_tbl);
&mut wam.machine_st.heap,
"c ",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+4)); wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 4));
wam.machine_st.heap.push(pstr_second_cell); wam.machine_st.heap.push(pstr_second_cell);
wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+6)); wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 6));
wam.machine_st.heap.push(pstr_offset_as_cell!(second_h)); wam.machine_st.heap.push(pstr_offset_as_cell!(second_h));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0)));
let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h); let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h);
@@ -929,11 +937,7 @@ mod test {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
put_partial_string( put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
&mut wam.machine_st.heap,
"abc ",
&mut wam.machine_st.atom_tbl,
);
let pstr_cell = wam.machine_st.heap[0]; let pstr_cell = wam.machine_st.heap[0];
@@ -963,11 +967,8 @@ mod test {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
let cstr_var_cell = put_complete_string( let cstr_var_cell =
&mut wam.machine_st.heap, put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
"abc",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.push(list_loc_as_cell!(2)); wam.machine_st.heap.push(list_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2)); wam.machine_st.heap.push(heap_loc_as_cell!(2));
@@ -982,30 +983,18 @@ mod test {
unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
assert_eq!( assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
wam.machine_st.heap[2],
char_as_cell!('a'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
wam.machine_st.heap[4],
char_as_cell!('b'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
wam.machine_st.heap[6],
char_as_cell!('c'),
);
// test "abc" = [X,Y,Z|D]. // test "abc" = [X,Y,Z|D].
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
let cstr_var_cell = put_complete_string( let cstr_var_cell =
&mut wam.machine_st.heap, put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
"abc",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.push(list_loc_as_cell!(2)); wam.machine_st.heap.push(list_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X
@@ -1022,35 +1011,20 @@ mod test {
assert_eq!(wam.machine_st.fail, false); assert_eq!(wam.machine_st.fail, false);
assert_eq!( assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
wam.machine_st.heap[2],
char_as_cell!('a'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
wam.machine_st.heap[4],
char_as_cell!('b'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
wam.machine_st.heap[6],
char_as_cell!('c'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[7], empty_list_as_cell!(),);
wam.machine_st.heap[7],
empty_list_as_cell!(),
);
// test "d" = [d]. // test "d" = [d].
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
let cstr_var_cell = put_complete_string( let cstr_var_cell =
&mut wam.machine_st.heap, put_complete_string(&mut wam.machine_st.heap, "d", &wam.machine_st.atom_tbl);
"d",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.push(list_loc_as_cell!(2)); wam.machine_st.heap.push(list_loc_as_cell!(2));
wam.machine_st.heap.push(char_as_cell!('d')); wam.machine_st.heap.push(char_as_cell!('d'));
@@ -1064,11 +1038,8 @@ mod test {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
let cstr_var_cell = put_complete_string( let cstr_var_cell =
&mut wam.machine_st.heap, put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
"abc",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.push(list_loc_as_cell!(2)); wam.machine_st.heap.push(list_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2)); wam.machine_st.heap.push(heap_loc_as_cell!(2));
@@ -1085,30 +1056,17 @@ mod test {
assert_eq!(wam.machine_st.fail, false); assert_eq!(wam.machine_st.fail, false);
assert_eq!( assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
wam.machine_st.heap[2],
char_as_cell!('a'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
wam.machine_st.heap[4],
char_as_cell!('b'),
);
assert_eq!( assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
wam.machine_st.heap[6],
char_as_cell!('c'),
);
// test "abcdef" = [a,b,c|X]. // test "abcdef" = [a,b,c|X].
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
put_complete_string( put_complete_string(&mut wam.machine_st.heap, "abcdef", &wam.machine_st.atom_tbl);
&mut wam.machine_st.heap,
"abcdef",
&mut wam.machine_st.atom_tbl,
);
wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
wam.machine_st.heap.push(heap_loc_as_cell!(2)); wam.machine_st.heap.push(heap_loc_as_cell!(2));
@@ -1123,7 +1081,10 @@ mod test {
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1));
assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef"))); assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef")));
assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4)); assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4));
assert_eq!(wam.machine_st.heap[6], fixnum_as_cell!(Fixnum::build_with("abc".len() as i64))); assert_eq!(
wam.machine_st.heap[6],
fixnum_as_cell!(Fixnum::build_with("abc".len() as i64))
);
// test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset. // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset.
@@ -1132,7 +1093,9 @@ mod test {
wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
wam.machine_st.heap.push(pstr_loc_as_cell!(2)); wam.machine_st.heap.push(pstr_loc_as_cell!(2));
wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1)));
{ {
let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2); let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2);

View File

@@ -12,11 +12,7 @@ use indexmap::IndexSet;
use std::cell::Cell; use std::cell::Cell;
use std::convert::TryFrom; use std::convert::TryFrom;
pub(crate) fn to_op_decl( pub(crate) fn to_op_decl(prec: u16, spec: Atom, name: Atom) -> Result<OpDecl, CompilationError> {
prec: u16,
spec: Atom,
name: Atom,
) -> Result<OpDecl, CompilationError> {
match spec { match spec {
atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)), atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)),
atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)), atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)),
@@ -29,19 +25,16 @@ pub(crate) fn to_op_decl(
} }
} }
fn setup_op_decl( fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
mut terms: Vec<Term>,
atom_tbl: &mut AtomTable,
) -> Result<OpDecl, CompilationError> {
let name = match terms.pop().unwrap() { let name = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name, Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}; };
let spec = match terms.pop().unwrap() { let spec = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name, Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
_ => return Err(CompilationError::InconsistentEntry), _ => return Err(CompilationError::InconsistentEntry),
}; };
@@ -65,15 +58,17 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
let name = terms.pop().unwrap(); let name = terms.pop().unwrap();
let arity = match arity { let arity = match arity {
Term::Literal(_, Literal::Integer(n)) => n.to_usize(), Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
_ => None, _ => None,
}.ok_or(CompilationError::InvalidModuleExport)?; }
.ok_or(CompilationError::InvalidModuleExport)?;
let name = match name { let name = match name {
Term::Literal(_, Literal::Atom(name)) => Some(name), Term::Literal(_, Literal::Atom(name)) => Some(name),
_ => None, _ => None,
}.ok_or(CompilationError::InvalidModuleExport)?; }
.ok_or(CompilationError::InvalidModuleExport)?;
if *slash == atom!("/") { if *slash == atom!("/") {
Ok((name, arity)) Ok((name, arity))
@@ -87,7 +82,7 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
fn setup_module_export( fn setup_module_export(
mut term: Term, mut term: Term,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Result<ModuleExport, CompilationError> { ) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term) setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey) .map(ModuleExport::PredicateKey)
@@ -113,7 +108,7 @@ pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
pub(super) fn setup_module_export_list( pub(super) fn setup_module_export_list(
mut export_list: Term, mut export_list: Term,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Result<Vec<ModuleExport>, CompilationError> { ) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![]; let mut exports = vec![];
@@ -133,7 +128,7 @@ pub(super) fn setup_module_export_list(
fn setup_module_decl( fn setup_module_decl(
mut terms: Vec<Term>, mut terms: Vec<Term>,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Result<ModuleDecl, CompilationError> { ) -> Result<ModuleDecl, CompilationError> {
let export_list = terms.pop().unwrap(); let export_list = terms.pop().unwrap();
let name = terms.pop().unwrap(); let name = terms.pop().unwrap();
@@ -141,7 +136,8 @@ fn setup_module_decl(
let name = match name { let name = match name {
Term::Literal(_, Literal::Atom(name)) => Some(name), Term::Literal(_, Literal::Atom(name)) => Some(name),
_ => None, _ => None,
}.ok_or(CompilationError::InvalidModuleDecl)?; }
.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?; let exports = setup_module_export_list(export_list, atom_tbl)?;
@@ -150,9 +146,7 @@ fn setup_module_decl(
fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> { fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
match terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Clause(_, name, mut terms) Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
if name == atom!("library") && terms.len() == 1 =>
{
match terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
_ => Err(CompilationError::InvalidModuleDecl), _ => Err(CompilationError::InvalidModuleDecl),
@@ -167,13 +161,11 @@ type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import( fn setup_qualified_import(
mut terms: Vec<Term>, mut terms: Vec<Term>,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Result<UseModuleExport, CompilationError> { ) -> Result<UseModuleExport, CompilationError> {
let mut export_list = terms.pop().unwrap(); let mut export_list = terms.pop().unwrap();
let module_src = match terms.pop().unwrap() { let module_src = match terms.pop().unwrap() {
Term::Clause(_, name, mut terms) Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
if name == atom!("library") && terms.len() == 1 =>
{
match terms.pop().unwrap() { match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
_ => Err(CompilationError::InvalidModuleDecl), _ => Err(CompilationError::InvalidModuleDecl),
@@ -318,11 +310,11 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
} }
(atom!("module"), 2) => { (atom!("module"), 2) => {
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)) Ok(Declaration::Module(setup_module_decl(terms, &atom_tbl)?))
} }
(atom!("op"), 3) => { (atom!("op"), 3) => {
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)) Ok(Declaration::Op(setup_op_decl(terms, &atom_tbl)?))
} }
(atom!("non_counted_backtracking"), 1) => { (atom!("non_counted_backtracking"), 1) => {
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
@@ -331,7 +323,7 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
(atom!("use_module"), 2) => { (atom!("use_module"), 2) => {
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
let (name, exports) = setup_qualified_import(terms, atom_tbl)?; let (name, exports) = setup_qualified_import(terms, &atom_tbl)?;
Ok(Declaration::UseQualifiedModule(name, exports)) Ok(Declaration::UseQualifiedModule(name, exports))
} }
@@ -381,19 +373,28 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
} }
fn tag_with_module_name(module_name: Atom, term: Term) -> Term { fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
Term::Clause(Cell::default(), atom!(":"), vec![ Term::Clause(
Term::Literal(Cell::default(), Literal::Atom(module_name)), Cell::default(),
term atom!(":"),
]) vec![
Term::Literal(Cell::default(), Literal::Atom(module_name)),
term,
],
)
} }
let process_term: fn(Atom, Term) -> Term; let process_term: fn(Atom, Term) -> Term;
let (module_name, key, term) = match term { let (module_name, key, term) = match term {
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => { Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) { if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
{
process_term = tag_with_module_name; process_term = tag_with_module_name;
(module_name, (name, terms[1].arity() + supp_args), terms.pop().unwrap()) (
module_name,
(name, terms[1].arity() + supp_args),
terms.pop().unwrap(),
)
} else { } else {
arg_terms.push(Term::Clause(cell, atom!(":"), terms)); arg_terms.push(Term::Clause(cell, atom!(":"), terms));
continue; continue;
@@ -408,10 +409,8 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
let term = match term { let term = match term {
Term::Clause(cell, name, mut terms) => { Term::Clause(cell, name, mut terms) => {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
arg_terms.push(process_term( arg_terms
module_name, .push(process_term(module_name, Term::Clause(cell, name, terms)));
Term::Clause(cell, name, terms),
));
continue; continue;
} }
@@ -424,11 +423,14 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
Term::Literal(cell, Literal::Atom(name)) => { Term::Literal(cell, Literal::Atom(name)) => {
let idx = loader.get_or_insert_qualified_code_index(module_name, key); let idx = loader.get_or_insert_qualified_code_index(module_name, key);
process_term(module_name, Term::Clause( process_term(
cell, module_name,
name, Term::Clause(
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))], cell,
)) name,
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
),
)
} }
term => term, term => term,
}; };
@@ -462,12 +464,7 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
if let ClauseType::Named(arity, name, idx) = ct { if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name(); let module_name = loader.payload.compilation_target.module_name();
let terms = build_meta_predicate_clause( let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause( return QueryTerm::Clause(
Cell::default(), Cell::default(),
@@ -501,12 +498,7 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
if let ClauseType::Named(arity, name, idx) = ct { if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let terms = build_meta_predicate_clause( let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause( return QueryTerm::Clause(
Cell::default(), Cell::default(),
@@ -529,17 +521,13 @@ pub(crate) struct Preprocessor {
impl Preprocessor { impl Preprocessor {
pub(super) fn new(settings: CodeGenSettings) -> Self { pub(super) fn new(settings: CodeGenSettings) -> Self {
Preprocessor { Preprocessor { settings }
settings,
}
} }
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> { fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
match term { match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => { Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
let classifier = VariableClassifier::new( let classifier = VariableClassifier::new(self.settings.default_call_policy());
self.settings.default_call_policy(),
);
let (head, var_data) = classifier.classify_fact(term)?; let (head, var_data) = classifier.classify_fact(term)?;
Ok((Fact { head }, var_data)) Ok((Fact { head }, var_data))
@@ -554,21 +542,25 @@ impl Preprocessor {
head: Term, head: Term,
body: Term, body: Term,
) -> Result<(Rule, VarData), CompilationError> { ) -> Result<(Rule, VarData), CompilationError> {
let classifier = VariableClassifier::new( let classifier = VariableClassifier::new(self.settings.default_call_policy());
self.settings.default_call_policy(),
);
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?; let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
match head { match head {
Term::Clause(_, name, terms) => Ok((Rule { Term::Clause(_, name, terms) => Ok((
head: (name, terms), Rule {
clauses, head: (name, terms),
}, var_data)), clauses,
Term::Literal(_, Literal::Atom(name)) => Ok((Rule { },
head: (name, vec![]), var_data,
clauses, )),
}, var_data)), Term::Literal(_, Literal::Atom(name)) => Ok((
Rule {
head: (name, vec![]),
clauses,
},
var_data,
)),
_ => Err(CompilationError::InvalidRuleHead), _ => Err(CompilationError::InvalidRuleHead),
} }
} }

View File

@@ -30,12 +30,6 @@ pub struct Stack {
_marker: PhantomData<HeapCellValue>, _marker: PhantomData<HeapCellValue>,
} }
impl Drop for Stack {
fn drop(&mut self) {
self.buf.deallocate();
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct AndFramePrelude { pub(crate) struct AndFramePrelude {
pub(crate) num_cells: usize, pub(crate) num_cells: usize,
@@ -189,7 +183,7 @@ impl Stack {
let frame_size = AndFrame::size_of(num_cells); let frame_size = AndFrame::size_of(num_cells);
unsafe { unsafe {
let e = self.buf.ptr as usize - self.buf.base as usize; let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size); let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<AndFramePrelude>(); let mut offset = prelude_size::<AndFramePrelude>();
@@ -213,7 +207,7 @@ impl Stack {
let frame_size = OrFrame::size_of(num_cells); let frame_size = OrFrame::size_of(num_cells);
unsafe { unsafe {
let b = self.buf.ptr as usize - self.buf.base as usize; let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size); let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<OrFramePrelude>(); let mut offset = prelude_size::<OrFramePrelude>();
@@ -269,8 +263,8 @@ impl Stack {
pub(crate) fn truncate(&mut self, b: usize) { pub(crate) fn truncate(&mut self, b: usize) {
let base = self.buf.base as usize + b; let base = self.buf.base as usize + b;
if base < self.buf.ptr as usize { if base < (*self.buf.ptr.get_mut()) as usize {
self.buf.ptr = base as *mut _; *self.buf.ptr.get_mut() = base as *mut _;
} }
} }
} }
@@ -290,7 +284,7 @@ mod tests {
assert_eq!( assert_eq!(
e, e,
0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>() 0 // 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
); );
assert_eq!(and_frame.prelude.num_cells, 10); assert_eq!(and_frame.prelude.num_cells, 10);
@@ -315,7 +309,10 @@ mod tests {
let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e); let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
for idx in 0..9 { for idx in 0..9 {
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1)); assert_eq!(
and_frame[idx + 1],
stack_loc_as_cell!(AndFrame, next_e, idx + 1)
);
} }
let and_frame = wam.machine_st.stack.index_and_frame(e); let and_frame = wam.machine_st.stack.index_and_frame(e);

View File

@@ -4,13 +4,13 @@ use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::read::*; use crate::read::*;
#[cfg(feature = "http")]
use crate::http::HttpResponse;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::types::*; use crate::types::*;
#[cfg(feature = "http")]
use crate::http::HttpResponse;
pub use modular_bitfield::prelude::*; pub use modular_bitfield::prelude::*;
@@ -19,17 +19,22 @@ use std::error::Error;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::hash::{Hash}; use std::hash::Hash;
use std::io; use std::io;
use std::io::{BufRead, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
#[cfg(feature = "http")]
use std::io::BufRead;
use std::mem; use std::mem;
use std::net::{TcpStream, Shutdown}; use std::net::{Shutdown, TcpStream};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
use native_tls::TlsStream; use native_tls::TlsStream;
#[cfg(feature = "http")]
use warp::hyper;
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
#[bits = 1] #[bits = 1]
pub enum StreamType { pub enum StreamType {
@@ -154,8 +159,10 @@ impl StreamLayout<CharReader<InputFileStream>> {
fn position(&mut self) -> Option<u64> { fn position(&mut self) -> Option<u64> {
// stream is the internal CharReader. subtract // stream is the internal CharReader. subtract
// its pending buffer length from position. // its pending buffer length from position.
self.get_mut().file.seek(SeekFrom::Current(0)) self.get_mut()
.map(|pos| pos - self.stream.rem_buf_len() as u64) .file
.seek(SeekFrom::Current(0))
.map(|pos| pos - self.stream.rem_buf_len() as u64)
.ok() .ok()
} }
} }
@@ -195,7 +202,7 @@ impl CharRead for StaticStringStream {
#[inline(always)] #[inline(always)]
fn peek_char(&mut self) -> Option<std::io::Result<char>> { fn peek_char(&mut self) -> Option<std::io::Result<char>> {
let pos = self.stream.position() as usize; let pos = self.stream.position() as usize;
self.stream.get_ref()[pos ..].chars().next().map(Ok) self.stream.get_ref()[pos..].chars().next().map(Ok)
} }
#[inline(always)] #[inline(always)]
@@ -205,7 +212,9 @@ impl CharRead for StaticStringStream {
#[inline(always)] #[inline(always)]
fn put_back_char(&mut self, c: char) { fn put_back_char(&mut self, c: char) {
self.stream.seek(SeekFrom::Current(- (c.len_utf8() as i64))).unwrap(); self.stream
.seek(SeekFrom::Current(-(c.len_utf8() as i64)))
.unwrap();
} }
} }
@@ -286,15 +295,15 @@ impl Read for HttpReadStream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
pub struct HttpWriteStream { pub struct HttpWriteStream {
status_code: u16, status_code: u16,
headers: hyper::HeaderMap, headers: mem::ManuallyDrop<hyper::HeaderMap>,
response: TypedArenaPtr<HttpResponse>, response: TypedArenaPtr<HttpResponse>,
buffer: Vec<u8>, buffer: mem::ManuallyDrop<Vec<u8>>,
} }
#[cfg(feature = "http")] #[cfg(feature = "http")]
impl Debug for HttpWriteStream { impl Debug for HttpWriteStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Write Stream") write!(f, "Http Write Stream")
} }
} }
@@ -302,31 +311,39 @@ impl Debug for HttpWriteStream {
impl Write for HttpWriteStream { impl Write for HttpWriteStream {
#[inline] #[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.buffer.extend_from_slice(buf); self.buffer.extend_from_slice(buf);
Ok(buf.len()) Ok(buf.len())
} }
#[inline] #[inline]
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(feature = "http")]
impl HttpWriteStream {
fn drop(&mut self) {
let headers = unsafe { mem::ManuallyDrop::take(&mut self.headers) };
let buffer = unsafe { mem::ManuallyDrop::take(&mut self.buffer) };
let (ready, response, cvar) = &**self.response; let (ready, response, cvar) = &**self.response;
let mut ready = ready.lock().unwrap(); let mut ready = ready.lock().unwrap();
{ {
let mut response = response.lock().unwrap(); let mut response = response.lock().unwrap();
let bytes = bytes::Bytes::copy_from_slice(&self.buffer); let mut response_ = warp::http::Response::builder()
let mut response_ = hyper::Response::builder()
.status(self.status_code); .status(self.status_code);
*response_.headers_mut().unwrap() = self.headers.clone(); *response_.headers_mut().unwrap() = headers;
*response = Some(response_.body(http_body_util::Full::new(bytes)).unwrap()); *response = Some(response_.body(warp::hyper::Body::from(buffer)).unwrap());
} }
*ready = true; *ready = true;
cvar.notify_one(); cvar.notify_one();
Ok(())
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct StandardOutputStream {} pub struct StandardOutputStream {}
@@ -510,7 +527,9 @@ impl Stream {
#[inline] #[inline]
pub fn from_owned_string(string: String, arena: &mut Arena) -> Stream { pub fn from_owned_string(string: String, arena: &mut Arena) -> Stream {
Stream::Byte(arena_alloc!( Stream::Byte(arena_alloc!(
StreamLayout::new(CharReader::new(ByteStream(Cursor::new(string.into_bytes())))), StreamLayout::new(CharReader::new(ByteStream(Cursor::new(
string.into_bytes()
)))),
arena arena
)) ))
} }
@@ -546,7 +565,7 @@ impl Stream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
#[cfg(feature = "http")] #[cfg(feature = "http")]
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::StaticStringStream => { ArenaHeaderTag::StaticStringStream => {
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _)) Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
@@ -603,7 +622,7 @@ impl Stream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpRead(ptr) => ptr.header_ptr(), Stream::HttpRead(ptr) => ptr.header_ptr(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(ptr) => ptr.header_ptr(), Stream::HttpWrite(ptr) => ptr.header_ptr(),
Stream::Null(_) => ptr::null(), Stream::Null(_) => ptr::null(),
Stream::Readline(ptr) => ptr.header_ptr(), Stream::Readline(ptr) => ptr.header_ptr(),
Stream::StandardOutput(ptr) => ptr.header_ptr(), Stream::StandardOutput(ptr) => ptr.header_ptr(),
@@ -728,14 +747,14 @@ impl CharRead for Stream {
Stream::StaticString(src) => (*src).peek_char(), Stream::StaticString(src) => (*src).peek_char(),
Stream::Byte(cursor) => (*cursor).peek_char(), Stream::Byte(cursor) => (*cursor).peek_char(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => Some(Err(std::io::Error::new( Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
))), ))),
Stream::OutputFile(_) | Stream::OutputFile(_)
Stream::StandardError(_) | | Stream::StandardError(_)
Stream::StandardOutput(_) | | Stream::StandardOutput(_)
Stream::Null(_) => Some(Err(std::io::Error::new( | Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
))), ))),
@@ -754,14 +773,14 @@ impl CharRead for Stream {
Stream::StaticString(src) => (*src).read_char(), Stream::StaticString(src) => (*src).read_char(),
Stream::Byte(cursor) => (*cursor).read_char(), Stream::Byte(cursor) => (*cursor).read_char(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => Some(Err(std::io::Error::new( Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
))), ))),
Stream::OutputFile(_) | Stream::OutputFile(_)
Stream::StandardError(_) | | Stream::StandardError(_)
Stream::StandardOutput(_) | | Stream::StandardOutput(_)
Stream::Null(_) => Some(Err(std::io::Error::new( | Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
))), ))),
@@ -780,11 +799,11 @@ impl CharRead for Stream {
Stream::StaticString(src) => src.put_back_char(c), Stream::StaticString(src) => src.put_back_char(c),
Stream::Byte(cursor) => cursor.put_back_char(c), Stream::Byte(cursor) => cursor.put_back_char(c),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => {} Stream::HttpWrite(_) => {}
Stream::OutputFile(_) | Stream::OutputFile(_)
Stream::StandardError(_) | | Stream::StandardError(_)
Stream::StandardOutput(_) | | Stream::StandardOutput(_)
Stream::Null(_) => {} | Stream::Null(_) => {}
} }
} }
@@ -800,11 +819,11 @@ impl CharRead for Stream {
Stream::StaticString(ref mut src) => src.consume(nread), Stream::StaticString(ref mut src) => src.consume(nread),
Stream::Byte(ref mut cursor) => cursor.consume(nread), Stream::Byte(ref mut cursor) => cursor.consume(nread),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => {} Stream::HttpWrite(_) => {}
Stream::OutputFile(_) | Stream::OutputFile(_)
Stream::StandardError(_) | | Stream::StandardError(_)
Stream::StandardOutput(_) | | Stream::StandardOutput(_)
Stream::Null(_) => {} | Stream::Null(_) => {}
} }
} }
} }
@@ -823,17 +842,17 @@ impl Read for Stream {
Stream::StaticString(src) => (*src).read(buf), Stream::StaticString(src) => (*src).read(buf),
Stream::Byte(cursor) => (*cursor).read(buf), Stream::Byte(cursor) => (*cursor).read(buf),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => Err(std::io::Error::new( Stream::HttpWrite(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
)), )),
Stream::OutputFile(_) Stream::OutputFile(_)
| Stream::StandardError(_) | Stream::StandardError(_)
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::Null(_) => Err(std::io::Error::new( | Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
)), )),
}; };
bytes_read bytes_read
@@ -851,16 +870,16 @@ impl Write for Stream {
Stream::StandardOutput(stream) => stream.write(buf), Stream::StandardOutput(stream) => stream.write(buf),
Stream::StandardError(stream) => stream.write(buf), Stream::StandardError(stream) => stream.write(buf),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf), Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpRead(_) => Err(std::io::Error::new( Stream::HttpRead(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::WriteToInputStream, StreamError::WriteToInputStream,
)), )),
Stream::StaticString(_) | Stream::StaticString(_)
Stream::Readline(_) | | Stream::Readline(_)
Stream::InputFile(..) | | Stream::InputFile(..)
Stream::Null(_) => Err(std::io::Error::new( | Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::WriteToInputStream, StreamError::WriteToInputStream,
)), )),
@@ -877,16 +896,16 @@ impl Write for Stream {
Stream::StandardError(stream) => stream.stream.flush(), Stream::StandardError(stream) => stream.stream.flush(),
Stream::StandardOutput(stream) => stream.stream.flush(), Stream::StandardOutput(stream) => stream.stream.flush(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(), Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpRead(_) => Err(std::io::Error::new( Stream::HttpRead(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::FlushToInputStream, StreamError::FlushToInputStream,
)), )),
Stream::StaticString(_) | Stream::StaticString(_)
Stream::Readline(_) | | Stream::Readline(_)
Stream::InputFile(_) | | Stream::InputFile(_)
Stream::Null(_) => Err(std::io::Error::new( | Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::FlushToInputStream, StreamError::FlushToInputStream,
)), )),
@@ -898,8 +917,10 @@ impl Write for Stream {
enum StreamError { enum StreamError {
PeekByteFailed, PeekByteFailed,
PeekByteFromNonPeekableStream, PeekByteFromNonPeekableStream,
#[allow(unused)] PeekCharFailed, #[allow(unused)]
#[allow(unused)] PeekCharFromNonPeekableStream, PeekCharFailed,
#[allow(unused)]
PeekCharFromNonPeekableStream,
ReadFromOutputStream, ReadFromOutputStream,
WriteToInputStream, WriteToInputStream,
FlushToInputStream, FlushToInputStream,
@@ -958,7 +979,11 @@ impl PartialEq for Stream {
impl Eq for Stream {} impl Eq for Stream {}
fn cursor_position<T>(past_end_of_stream: &mut bool, cursor: &Cursor<T>, cursor_len: u64) -> AtEndOfStream { fn cursor_position<T>(
past_end_of_stream: &mut bool,
cursor: &Cursor<T>,
cursor_len: u64,
) -> AtEndOfStream {
let position = cursor.position(); let position = cursor.position();
let at_end_of_stream = match position.cmp(&cursor_len) { let at_end_of_stream = match position.cmp(&cursor_len) {
@@ -984,17 +1009,10 @@ impl Stream {
Stream::StaticString(string_stream_layout) => { Stream::StaticString(string_stream_layout) => {
Some(string_stream_layout.stream.stream.position()) Some(string_stream_layout.stream.stream.position())
} }
Stream::InputFile(file_stream) => { Stream::InputFile(file_stream) => file_stream.position(),
file_stream.position()
}
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
Stream::NamedTls(..) => { Stream::NamedTls(..) => Some(0),
Some(0) Stream::NamedTcp(..) | Stream::Readline(..) => Some(0),
}
Stream::NamedTcp(..)
| Stream::Readline(..) => {
Some(0)
}
_ => None, _ => None,
}; };
@@ -1011,7 +1029,11 @@ impl Stream {
.. ..
} = &mut **stream_layout; } = &mut **stream_layout;
stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap(); stream
.get_mut()
.file
.seek(SeekFrom::Start(position))
.unwrap();
stream.reset_buffer(); // flush the internal buffer. stream.reset_buffer(); // flush the internal buffer.
if let Ok(metadata) = stream.get_ref().file.metadata() { if let Ok(metadata) = stream.get_ref().file.metadata() {
@@ -1127,9 +1149,7 @@ impl Stream {
} }
} }
} }
_ => { _ => AtEndOfStream::Not,
AtEndOfStream::Not
}
} }
} }
@@ -1153,14 +1173,16 @@ impl Stream {
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
Stream::NamedTls(..) => atom!("read_append"), Stream::NamedTls(..) => atom!("read_append"),
Stream::Byte(_) Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
| Stream::InputFile(..) => atom!("read"), | Stream::InputFile(..) => atom!("read"),
Stream::NamedTcp(..) => atom!("read_append"), Stream::NamedTcp(..) => atom!("read_append"),
Stream::OutputFile(file) if file.is_append => atom!("append"), Stream::OutputFile(file) if file.is_append => atom!("append"),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(_) => atom!("write"), Stream::HttpWrite(_) => atom!("write"),
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"), Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => {
atom!("write")
}
Stream::Null(_) => atom!(""), Stream::Null(_) => atom!(""),
} }
} }
@@ -1182,11 +1204,7 @@ impl Stream {
} }
#[inline] #[inline]
pub(crate) fn from_tcp_stream( pub(crate) fn from_tcp_stream(address: Atom, tcp_stream: TcpStream, arena: &mut Arena) -> Self {
address: Atom,
tcp_stream: TcpStream,
arena: &mut Arena,
) -> Self {
tcp_stream.set_read_timeout(None).unwrap(); tcp_stream.set_read_timeout(None).unwrap();
tcp_stream.set_write_timeout(None).unwrap(); tcp_stream.set_write_timeout(None).unwrap();
@@ -1234,17 +1252,17 @@ impl Stream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
#[inline] #[inline]
pub(crate) fn from_http_sender( pub(crate) fn from_http_sender(
response: TypedArenaPtr<HttpResponse>, response: TypedArenaPtr<HttpResponse>,
status_code: u16, status_code: u16,
headers: hyper::HeaderMap, headers: hyper::HeaderMap,
arena: &mut Arena, arena: &mut Arena,
) -> Self { ) -> Self {
Stream::HttpWrite(arena_alloc!( Stream::HttpWrite(arena_alloc!(
StreamLayout::new(CharReader::new(HttpWriteStream { StreamLayout::new(CharReader::new(HttpWriteStream {
response, response,
status_code, status_code,
headers, headers: mem::ManuallyDrop::new(headers),
buffer: Vec::new(), buffer: mem::ManuallyDrop::new(Vec::new()),
})), })),
arena arena
)) ))
@@ -1282,11 +1300,9 @@ impl Stream {
match stream { match stream {
Stream::NamedTcp(ref mut tcp_stream) => { Stream::NamedTcp(ref mut tcp_stream) => {
tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both) tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
},
#[cfg(feature = "tls")]
Stream::NamedTls(ref mut tls_stream) => {
tls_stream.inner_mut().tls_stream.shutdown()
} }
#[cfg(feature = "tls")]
Stream::NamedTls(ref mut tls_stream) => tls_stream.inner_mut().tls_stream.shutdown(),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpRead(ref mut http_stream) => { Stream::HttpRead(ref mut http_stream) => {
unsafe { unsafe {
@@ -1297,14 +1313,15 @@ impl Stream {
Ok(()) Ok(())
} }
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(ref mut http_stream) => { Stream::HttpWrite(ref mut http_stream) => {
http_stream.inner_mut().drop();
unsafe { unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped); http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _); std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _);
} }
Ok(()) Ok(())
} }
Stream::InputFile(mut file_stream) => { Stream::InputFile(mut file_stream) => {
// close the stream by dropping the inner File. // close the stream by dropping the inner File.
unsafe { unsafe {
@@ -1323,7 +1340,7 @@ impl Stream {
Ok(()) Ok(())
} }
_ => Ok(()) _ => Ok(()),
} }
} }
@@ -1344,10 +1361,10 @@ impl Stream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpRead(..) => true, Stream::HttpRead(..) => true,
Stream::NamedTcp(..) Stream::NamedTcp(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
| Stream::InputFile(..) => true, | Stream::InputFile(..) => true,
_ => false, _ => false,
} }
} }
@@ -1360,10 +1377,10 @@ impl Stream {
#[cfg(feature = "http")] #[cfg(feature = "http")]
Stream::HttpWrite(..) => true, Stream::HttpWrite(..) => true,
Stream::StandardError(_) Stream::StandardError(_)
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::NamedTcp(..) | Stream::NamedTcp(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::OutputFile(..) => true, | Stream::OutputFile(..) => true,
_ => false, _ => false,
} }
} }
@@ -1381,7 +1398,12 @@ impl Stream {
return true; return true;
} }
Stream::InputFile(ref mut file_stream) => { Stream::InputFile(ref mut file_stream) => {
file_stream.stream.get_mut().file.seek(SeekFrom::Start(0)).unwrap(); file_stream
.stream
.get_mut()
.file
.seek(SeekFrom::Start(0))
.unwrap();
return true; return true;
} }
Stream::Readline(ref mut readline_stream) => { Stream::Readline(ref mut readline_stream) => {
@@ -1410,17 +1432,13 @@ impl Stream {
_ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")), _ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")),
} }
} }
Stream::InputFile(ref mut file) => { Stream::InputFile(ref mut file) => match file.peek_byte() {
match file.peek_byte() { Some(result) => Ok(result?),
Some(result) => { _ => Err(std::io::Error::new(
Ok(result?) ErrorKind::UnexpectedEof,
} StreamError::PeekByteFailed,
_ => Err(std::io::Error::new( )),
ErrorKind::UnexpectedEof, },
StreamError::PeekByteFailed,
)),
}
}
Stream::Readline(ref mut stream) => stream.stream.peek_byte(), Stream::Readline(ref mut stream) => stream.stream.peek_byte(),
Stream::NamedTcp(ref mut stream) => { Stream::NamedTcp(ref mut stream) => {
let mut b = [0u8; 1]; let mut b = [0u8; 1];
@@ -1663,7 +1681,10 @@ impl MachineState {
} }
} }
pub(crate) fn open_parsing_stream(&mut self, mut stream: Stream) -> Result<Stream, ParserError> { pub(crate) fn open_parsing_stream(
&mut self,
mut stream: Stream,
) -> Result<Stream, ParserError> {
match stream.peek_char() { match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
Some(Err(e)) => Err(ParserError::IO(e)), Some(Err(e)) => Err(ParserError::IO(e)),
@@ -1687,7 +1708,7 @@ impl MachineState {
arity: usize, arity: usize,
) -> MachineStub { ) -> MachineStub {
let stub = functor_stub(caller, arity); let stub = functor_stub(caller, arity);
let err = self.permission_error( let err = self.permission_error(
perm, perm,
err_atom, err_atom,
if let Some(alias) = stream.options().get_alias() { if let Some(alias) = stream.options().get_alias() {
@@ -1723,7 +1744,7 @@ impl MachineState {
stub_arity: usize, stub_arity: usize,
) -> MachineStub { ) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity); let stub = functor_stub(stub_name, stub_arity);
let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit); let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
self.error_form(err, stub) self.error_form(err, stub)
} }
@@ -1798,7 +1819,7 @@ impl MachineState {
) -> Result<Stream, MachineStub> { ) -> Result<Stream, MachineStub> {
if file_spec == atom!("") { if file_spec == atom!("") {
let stub = functor_stub(atom!("open"), 4); let stub = functor_stub(atom!("open"), 4);
let err = self.domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); let err = self.domain_error(DomainErrorType::SourceSink, self.registers[1]);
return Err(self.error_form(err, stub)); return Err(self.error_form(err, stub));
} }
@@ -1810,9 +1831,7 @@ impl MachineState {
} }
} }
let mode = MachineState::deref(self, self[temp_v!(2)]); let mode = cell_as_atom!(self.store(MachineState::deref(self, self.registers[2])));
let mode = cell_as_atom!(self.store(mode));
let mut open_options = OpenOptions::new(); let mut open_options = OpenOptions::new();
let (is_input_file, in_append_mode) = match mode { let (is_input_file, in_append_mode) = match mode {
@@ -1847,7 +1866,7 @@ impl MachineState {
} }
}; };
let file = match open_options.open(file_spec.as_str()) { let file = match open_options.open(&*file_spec.as_str()) {
Ok(file) => file, Ok(file) => file,
Err(err) => { Err(err) => {
match err.kind() { match err.kind() {
@@ -1855,19 +1874,23 @@ impl MachineState {
// 8.11.5.3j) // 8.11.5.3j)
let stub = functor_stub(atom!("open"), 4); let stub = functor_stub(atom!("open"), 4);
let err = self.existence_error( let err =
ExistenceError::SourceSink(self[temp_v!(1)]), self.existence_error(ExistenceError::SourceSink(self[temp_v!(1)]));
);
return Err(self.error_form(err, stub)); return Err(self.error_form(err, stub));
} }
ErrorKind::PermissionDenied => { ErrorKind::PermissionDenied => {
// 8.11.5.3k) // 8.11.5.3k)
return Err(self.open_permission_error(self.registers[1], atom!("open"), 4)); return Err(self.open_permission_error(
self.registers[1],
atom!("open"),
4,
));
} }
_ => { _ => {
// assume the OS is out of file descriptors.
let stub = functor_stub(atom!("open"), 4); let stub = functor_stub(atom!("open"), 4);
let err = self.syntax_error(ParserError::IO(err)); let err = self.resource_error(ResourceError::OutOfFiles);
return Err(self.error_form(err, stub)); return Err(self.error_form(err, stub));
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
use crate::forms::*; use crate::forms::*;
use crate::machine::*;
use crate::machine::load_state::*; use crate::machine::load_state::*;
use crate::machine::loader::*; use crate::machine::loader::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::parser::*; use crate::parser::parser::*;
use crate::read::devour_whitespace; use crate::read::devour_whitespace;
@@ -45,7 +45,10 @@ impl<'a> BootstrappingTermStream<'a> {
listing_src: ListingSource, listing_src: ListingSource,
) -> Self { ) -> Self {
let parser = Parser::new(stream, machine_st); let parser = Parser::new(stream, machine_st);
Self { parser, listing_src } Self {
parser,
listing_src,
}
} }
} }
@@ -101,7 +104,7 @@ impl<TS> LoadStatePayload<TS> {
non_counted_bt_preds: IndexSet::with_hasher(FxBuildHasher::default()), non_counted_bt_preds: IndexSet::with_hasher(FxBuildHasher::default()),
predicates: predicate_queue![], predicates: predicate_queue![],
clause_clauses: vec![], clause_clauses: vec![],
} }
} }
} }
@@ -122,20 +125,18 @@ impl TermStream for LiveTermStream {
} }
} }
pub struct InlineTermStream { pub struct InlineTermStream {}
}
impl TermStream for InlineTermStream { impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> { fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::unexpected_eof())) Err(CompilationError::from(ParserError::unexpected_eof()))
} }
fn eof(&mut self) -> Result<bool, CompilationError> { fn eof(&mut self) -> Result<bool, CompilationError> {
Ok(true) Ok(true)
} }
fn listing_src(&self) -> &ListingSource { fn listing_src(&self) -> &ListingSource {
&ListingSource::User &ListingSource::User
} }
} }

View File

@@ -1,9 +1,9 @@
use crate::arena::*; use crate::arena::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_iter::stackful_preorder_iter; use crate::heap_iter::{NonListElider, stackful_preorder_iter};
use crate::machine::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::*;
use crate::types::*; use crate::types::*;
use std::cmp::Ordering; use std::cmp::Ordering;
@@ -12,6 +12,7 @@ use std::ops::{Deref, DerefMut};
use derive_deref::*; use derive_deref::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet; use indexmap::IndexSet;
use num_order::NumOrd;
pub(crate) trait Unifier: DerefMut<Target = MachineState> { pub(crate) trait Unifier: DerefMut<Target = MachineState> {
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) { fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
@@ -190,8 +191,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
machine_st.pdl.push(pstr_iter1.focus); machine_st.pdl.push(pstr_iter1.focus);
} }
} }
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::FirstIterContinuable(iteratee)
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
if continuable.is_second_iter() { if continuable.is_second_iter() {
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
} }
@@ -426,8 +427,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
match Number::try_from(value) { match Number::try_from(value) {
Ok(n2) => match n2 { Ok(n2) => match n2 {
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {} Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
Number::Integer(n2) if n1.get_num() == *n2 => {} Number::Integer(n2) if (*n2).num_eq(&n1.get_num()) => {}
Number::Rational(n2) if n1.get_num() == *n2 => {} Number::Rational(n2) if (*n2).num_eq(&Integer::from(n1.get_num())) => {}
_ => { _ => {
self.fail = true; self.fail = true;
} }
@@ -439,10 +440,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
} }
fn unify_big_num<N>(&mut self, n1: TypedArenaPtr<N>, value: HeapCellValue) fn unify_big_num<N>(&mut self, n1: TypedArenaPtr<N>, value: HeapCellValue)
where N: PartialEq<Rational> where
+ PartialEq<Integer> N: PartialEq<Rational> + PartialEq<Integer> + PartialEq<i64> + ArenaAllocated,
+ PartialEq<i64>
+ ArenaAllocated
{ {
if let Some(r) = value.as_var() { if let Some(r) = value.as_var() {
Self::bind(self, r, typed_arena_ptr_as_cell!(n1)); Self::bind(self, r, typed_arena_ptr_as_cell!(n1));
@@ -464,6 +463,48 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
} }
} }
fn unify_big_integer(&mut self, n1: TypedArenaPtr<Integer>, value: HeapCellValue) {
if let Some(r) = value.as_var() {
Self::bind(self, r, typed_arena_ptr_as_cell!(n1));
return;
}
match Number::try_from(value) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if (*n1).num_eq(&n2.get_num()) => {}
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
Number::Rational(n2) if (*n2).num_eq(&*n1) => {}
_ => {
self.fail = true;
}
},
Err(_) => {
self.fail = true;
}
}
}
fn unify_big_rational(&mut self, n1: TypedArenaPtr<Rational>, value: HeapCellValue) {
if let Some(r) = value.as_var() {
Self::bind(self, r, typed_arena_ptr_as_cell!(n1));
return;
}
match Number::try_from(value) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if (*n1).num_eq(&Integer::from(n2.get_num())) => {}
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
Number::Rational(n2) if n1 == n2 => {}
_ => {
self.fail = true;
}
},
Err(_) => {
self.fail = true;
}
}
}
fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
if let Some(r) = value.as_var() { if let Some(r) = value.as_var() {
Self::bind(self, r, HeapCellValue::from(f1)); Self::bind(self, r, HeapCellValue::from(f1));
@@ -489,10 +530,10 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
match_untyped_arena_ptr!(ptr, match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Integer, int_ptr) => { (ArenaHeaderTag::Integer, int_ptr) => {
Self::unify_big_num(self, int_ptr, value); Self::unify_big_integer(self, int_ptr, value);
} }
(ArenaHeaderTag::Rational, rat_ptr) => { (ArenaHeaderTag::Rational, rat_ptr) => {
Self::unify_big_num(self, rat_ptr, value); Self::unify_big_rational(self, rat_ptr, value);
} }
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
read_heap_cell!(value, read_heap_cell!(value,
@@ -650,6 +691,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
(HeapCellValueTag::Cons, ptr_1) => { (HeapCellValueTag::Cons, ptr_1) => {
Self::unify_constant(self, ptr_1, d2); Self::unify_constant(self, ptr_1, d2);
} }
(HeapCellValueTag::CutPoint, n1) => {
Self::unify_fixnum(self, n1, d2);
}
_ => { _ => {
unreachable!(); unreachable!();
} }
@@ -676,7 +720,7 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
if !value.is_constant() { if !value.is_constant() {
let machine_st: &mut MachineState = unifier.deref_mut(); let machine_st: &mut MachineState = unifier.deref_mut();
for cell in stackful_preorder_iter(&mut machine_st.heap, &mut machine_st.stack, value) { for cell in stackful_preorder_iter::<NonListElider>(&mut machine_st.heap, &mut machine_st.stack, value) {
let cell = unmark_cell_bits!(cell); let cell = unmark_cell_bits!(cell);
if let Some(inner_r) = cell.as_var() { if let Some(inner_r) = cell.as_var() {

View File

@@ -57,13 +57,6 @@ macro_rules! atom_as_cell {
}; };
} }
macro_rules! cell_as_ossified_op_dir {
($cell:expr) => {{
let ptr_u64 = cell_as_untyped_arena_ptr!($cell);
TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir)
}};
}
macro_rules! cell_as_string { macro_rules! cell_as_string {
($cell:expr) => { ($cell:expr) => {
PartialString::from(cell_as_atom!($cell)) PartialString::from(cell_as_atom!($cell))
@@ -88,7 +81,7 @@ macro_rules! cell_as_atom_cell {
macro_rules! cell_as_f64_ptr { macro_rules! cell_as_f64_ptr {
($cell:expr) => {{ ($cell:expr) => {{
let offset = $cell.get_value() as usize; let offset = $cell.get_value() as usize;
F64Ptr::from_offset(offset) F64Ptr::from_offset(F64Offset::new(offset))
}}; }};
} }
@@ -236,12 +229,14 @@ macro_rules! cell_as_stream {
} }
macro_rules! cell_as_load_state_payload { macro_rules! cell_as_load_state_payload {
($cell:expr) => { unsafe { ($cell:expr) => {
let ptr = cell_as_untyped_arena_ptr!($cell); unsafe {
let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset()); let ptr = cell_as_untyped_arena_ptr!($cell);
let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset());
TypedArenaPtr::new(ptr) TypedArenaPtr::new(ptr)
}}; }
};
} }
macro_rules! match_untyped_arena_ptr_pat_body { macro_rules! match_untyped_arena_ptr_pat_body {
@@ -258,13 +253,15 @@ macro_rules! match_untyped_arena_ptr_pat_body {
$code $code
}}; }};
($ptr:ident, OssifiedOpDir, $n:ident, $code:expr) => {{ ($ptr:ident, OssifiedOpDir, $n:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut OssifiedOpDir>($ptr.payload_offset()) }; let payload_ptr =
unsafe { std::mem::transmute::<_, *mut OssifiedOpDir>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr); let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, LiveLoadState, $n:ident, $code:expr) => {{ ($ptr:ident, LiveLoadState, $n:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut LiveLoadState>($ptr.payload_offset()) }; let payload_ptr =
unsafe { std::mem::transmute::<_, *mut LiveLoadState>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr); let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
@@ -275,21 +272,24 @@ macro_rules! match_untyped_arena_ptr_pat_body {
$code $code
}}; }};
($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{ ($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) }; let payload_ptr =
unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) };
#[allow(unused_mut)] #[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr); let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, HttpListener, $listener:ident, $code:expr) => {{ ($ptr:ident, HttpListener, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpListener>($ptr.payload_offset()) }; let payload_ptr =
unsafe { std::mem::transmute::<_, *mut HttpListener>($ptr.payload_offset()) };
#[allow(unused_mut)] #[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr); let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, HttpResponse, $listener:ident, $code:expr) => {{ ($ptr:ident, HttpResponse, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpResponse>($ptr.payload_offset()) }; let payload_ptr =
unsafe { std::mem::transmute::<_, *mut HttpResponse>($ptr.payload_offset()) };
#[allow(unused_mut)] #[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr); let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -297,7 +297,8 @@ macro_rules! match_untyped_arena_ptr_pat_body {
}}; }};
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{ ($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
#[allow(unused_mut)] #[allow(unused_mut)]
let mut $ip = TypedArenaPtr::new(unsafe { std::mem::transmute::<_, *mut IndexPtr>($ptr.get_ptr()) }); let mut $ip =
TypedArenaPtr::new(unsafe { std::mem::transmute::<_, *mut IndexPtr>($ptr.get_ptr()) });
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
@@ -315,7 +316,7 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::NamedTcpStream | ArenaHeaderTag::NamedTcpStream
| ArenaHeaderTag::NamedTlsStream | ArenaHeaderTag::NamedTlsStream
| ArenaHeaderTag::HttpReadStream | ArenaHeaderTag::HttpReadStream
| ArenaHeaderTag::HttpWriteStream | ArenaHeaderTag::HttpWriteStream
| ArenaHeaderTag::ReadlineStream | ArenaHeaderTag::ReadlineStream
| ArenaHeaderTag::StaticStringStream | ArenaHeaderTag::StaticStringStream
| ArenaHeaderTag::ByteStream | ArenaHeaderTag::ByteStream
@@ -323,10 +324,10 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::StandardErrorStream
}; };
(IndexPtr) => { (IndexPtr) => {
ArenaHeaderTag::IndexPtrUndefined | ArenaHeaderTag::IndexPtrUndefined
ArenaHeaderTag::IndexPtrDynamicUndefined | | ArenaHeaderTag::IndexPtrDynamicUndefined
ArenaHeaderTag::IndexPtrDynamicIndex | | ArenaHeaderTag::IndexPtrDynamicIndex
ArenaHeaderTag::IndexPtrIndex | ArenaHeaderTag::IndexPtrIndex
}; };
($tag:ident) => { ($tag:ident) => {
ArenaHeaderTag::$tag ArenaHeaderTag::$tag
@@ -347,71 +348,71 @@ macro_rules! match_untyped_arena_ptr {
} }
macro_rules! read_heap_cell_pat_body { macro_rules! read_heap_cell_pat_body {
($cell:ident, Cons, $n:ident, $code:expr) => ({ ($cell:ident, Cons, $n:ident, $code:expr) => {{
let $n = cell_as_untyped_arena_ptr!($cell); let $n = cell_as_untyped_arena_ptr!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, F64, $n:ident, $code:expr) => ({ ($cell:ident, F64, $n:ident, $code:expr) => {{
let $n = cell_as_f64_ptr!($cell); let $n = cell_as_f64_ptr!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({ ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => {{
let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity(); let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, PStr, $atom:ident, $code:expr) => ({ ($cell:ident, PStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell); let $atom = cell_as_atom!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, CStr, $atom:ident, $code:expr) => ({ ($cell:ident, CStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell); let $atom = cell_as_atom!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({ ($cell:ident, CStr | PStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell); let $atom = cell_as_atom!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({ ($cell:ident, PStr | CStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell); let $atom = cell_as_atom!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, Fixnum, $value:ident, $code:expr) => ({ ($cell:ident, Fixnum, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes()); let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, CutPoint, $value:ident, $code:expr) => ({ ($cell:ident, CutPoint, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes()); let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, Fixnum | CutPoint, $value:ident, $code:expr) => ({ ($cell:ident, Fixnum | CutPoint, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes()); let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, CutPoint | Fixnum, $value:ident, $code:expr) => ({ ($cell:ident, CutPoint | Fixnum, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes()); let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, Char, $value:ident, $code:expr) => ({ ($cell:ident, Char, $value:ident, $code:expr) => {{
let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) }; let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) };
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({ ($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => {{
let $value = $cell.get_value() as usize; let $value = $cell.get_value() as usize;
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}); }};
} }
macro_rules! read_heap_cell_pat { macro_rules! read_heap_cell_pat {
@@ -596,7 +597,9 @@ macro_rules! index_store {
IndexStore { IndexStore {
code_dir: $code_dir, code_dir: $code_dir,
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()), extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()), local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
FxBuildHasher::default(),
),
global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()), global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()),
goal_expansion_indices: GoalExpansionIndices::with_hasher(FxBuildHasher::default()), goal_expansion_indices: GoalExpansionIndices::with_hasher(FxBuildHasher::default()),
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()), meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),

View File

@@ -10,6 +10,7 @@ use std::hash::{Hash, Hasher};
use std::io::{Error as IOError, ErrorKind}; use std::io::{Error as IOError, ErrorKind};
use std::ops::{Deref, Neg}; use std::ops::{Deref, Neg};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use std::vec::Vec; use std::vec::Vec;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
@@ -33,6 +34,7 @@ pub const FY: u32 = 0x0080;
pub const DELIMITER: u32 = 0x0100; pub const DELIMITER: u32 = 0x0100;
pub const TERM: u32 = 0x1000; pub const TERM: u32 = 0x1000;
pub const LTERM: u32 = 0x3000; pub const LTERM: u32 = 0x3000;
pub const BTERM: u32 = 0x11000;
pub const NEGATIVE_SIGN: u32 = 0x0200; pub const NEGATIVE_SIGN: u32 = 0x0200;
@@ -258,7 +260,8 @@ impl GenContext {
pub struct OpDesc { pub struct OpDesc {
prec: B11, prec: B11,
spec: B8, spec: B8,
#[allow(unused)] padding: B13, #[allow(unused)]
padding: B13,
} }
impl OpDesc { impl OpDesc {
@@ -417,13 +420,13 @@ pub enum ParserError {
impl ParserError { impl ParserError {
pub fn line_and_col_num(&self) -> Option<(usize, usize)> { pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self { match self {
&ParserError::BackQuotedString(line_num, col_num) | &ParserError::BackQuotedString(line_num, col_num)
&ParserError::IncompleteReduction(line_num, col_num) | | &ParserError::IncompleteReduction(line_num, col_num)
&ParserError::MissingQuote(line_num, col_num) | | &ParserError::MissingQuote(line_num, col_num)
&ParserError::NonPrologChar(line_num, col_num) | | &ParserError::NonPrologChar(line_num, col_num)
&ParserError::ParseBigInt(line_num, col_num) | | &ParserError::ParseBigInt(line_num, col_num)
&ParserError::UnexpectedChar(_, line_num, col_num) | | &ParserError::UnexpectedChar(_, line_num, col_num)
&ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None, _ => None,
} }
} }
@@ -432,8 +435,12 @@ impl ParserError {
match self { match self {
ParserError::BackQuotedString(..) => atom!("back_quoted_string"), ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"), ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"), ParserError::InvalidSingleQuotedCharacter(..) => {
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => atom!("unexpected_end_of_file"), atom!("invalid_single_quoted_character")
}
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
atom!("unexpected_end_of_file")
}
ParserError::IO(_) => atom!("input_output_error"), ParserError::IO(_) => atom!("input_output_error"),
ParserError::LexicalError(_) => atom!("lexical_error"), ParserError::LexicalError(_) => atom!("lexical_error"),
ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::MissingQuote(..) => atom!("missing_quote"),
@@ -522,9 +529,12 @@ pub enum Fixity {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Fixnum { pub struct Fixnum {
num: B56, num: B56,
#[allow(unused)] f: bool, #[allow(unused)]
#[allow(unused)] m: bool, f: bool,
#[allow(unused)] tag: B6, #[allow(unused)]
m: bool,
#[allow(unused)]
tag: B6,
} }
impl Fixnum { impl Fixnum {
@@ -623,7 +633,7 @@ impl fmt::Display for Literal {
} }
impl Literal { impl Literal {
pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option<Atom> { pub fn to_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
match self { match self {
Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)), Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
_ => None, _ => None,
@@ -631,7 +641,6 @@ impl Literal {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct VarPtr(Rc<RefCell<Var>>); pub struct VarPtr(Rc<RefCell<Var>>);
@@ -800,7 +809,7 @@ pub fn source_arity(terms: &[Term]) -> usize {
terms.len() terms.len()
} }
fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
if let Term::Clause(_, ref name, ref mut subterms) = term { if let Term::Clause(_, ref name, ref mut subterms) = term {
if let Some(last_arg) = subterms.last() { if let Some(last_arg) = subterms.last() {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {

View File

@@ -20,7 +20,7 @@ use std::str;
pub struct CharReader<R> { pub struct CharReader<R> {
inner: R, inner: R,
buf: SmallVec<[u8;32]>, buf: SmallVec<[u8; 32]>,
pos: usize, pos: usize,
} }
@@ -78,7 +78,7 @@ pub trait CharRead {
self.consume(c.len_utf8()); self.consume(c.len_utf8());
Some(Ok(c)) Some(Ok(c))
} }
result => result result => result,
} }
} }
@@ -161,9 +161,7 @@ impl<R: Read> CharRead for CharReader<R> {
return Some(Ok(c)); return Some(Ok(c));
} }
Err(e) => { Err(e) => e,
e
}
}; };
if buf.len() - e.valid_up_to() >= 4 { if buf.len() - e.valid_up_to() >= 4 {
@@ -192,13 +190,15 @@ impl<R: Read> CharRead for CharReader<R> {
// the buffer, it will be returned on the next // the buffer, it will be returned on the next
// loop. // loop.
return Some(Err(io::Error::new(io::ErrorKind::InvalidData, return Some(Err(io::Error::new(
BadUtf8Error { bytes: badbytes }))); io::ErrorKind::InvalidData,
BadUtf8Error { bytes: badbytes },
)));
} else { } else {
if self.pos >= self.buf.len() { if self.pos >= self.buf.len() {
return None; return None;
} else if self.buf.len() - self.pos >= 4 { } else if self.buf.len() - self.pos >= 4 {
return match str::from_utf8(&self.buf[self.pos .. e.valid_up_to()]) { return match str::from_utf8(&self.buf[self.pos..e.valid_up_to()]) {
Ok(s) => { Ok(s) => {
let mut chars = s.chars(); let mut chars = s.chars();
let c = chars.next().unwrap(); let c = chars.next().unwrap();
@@ -206,10 +206,12 @@ impl<R: Read> CharRead for CharReader<R> {
Some(Ok(c)) Some(Ok(c))
} }
Err(e) => { Err(e) => {
let badbytes = self.buf[self.pos .. e.valid_up_to()].to_vec(); let badbytes = self.buf[self.pos..e.valid_up_to()].to_vec();
Some(Err(io::Error::new(io::ErrorKind::InvalidData, Some(Err(io::Error::new(
BadUtf8Error { bytes: badbytes }))) io::ErrorKind::InvalidData,
BadUtf8Error { bytes: badbytes },
)))
} }
}; };
} else { } else {
@@ -223,7 +225,7 @@ impl<R: Read> CharRead for CharReader<R> {
let buf_len = self.buf.len(); let buf_len = self.buf.len();
let mut word = [0u8;4]; let mut word = [0u8; 4];
let word_slice = &mut word[buf_len..4]; let word_slice = &mut word[buf_len..4];
match self.inner.read(word_slice) { match self.inner.read(word_slice) {
@@ -250,7 +252,7 @@ impl<R: Read> CharRead for CharReader<R> {
let c_len = c.len_utf8(); let c_len = c.len_utf8();
let mut shifted_slice = [0u8; 32]; let mut shifted_slice = [0u8; 32];
shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]); shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos..self.buf.len()]);
self.buf.resize(c_len, 0); self.buf.resize(c_len, 0);
self.buf.extend_from_slice(&shifted_slice[0..src_len]); self.buf.extend_from_slice(&shifted_slice[0..src_len]);
@@ -311,7 +313,10 @@ impl<R: Read> Read for CharReader<R> {
} }
if !buf.is_empty() { if !buf.is_empty() {
Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) Err(io::Error::new(
ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
} else { } else {
Ok(()) Ok(())
} }
@@ -364,12 +369,14 @@ where
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("CharReader") fmt.debug_struct("CharReader")
.field("reader", &self.inner) .field("reader", &self.inner)
.field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len())) .field(
"buf",
&format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len()),
)
.finish() .finish()
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::parser::char_reader::*; use crate::parser::char_reader::*;

View File

@@ -86,14 +86,14 @@ impl<'a, R: CharRead> Lexer<'a, R> {
pub fn lookahead_char(&mut self) -> Result<char, ParserError> { pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
match self.reader.peek_char() { match self.reader.peek_char() {
Some(Ok(c)) => Ok(c), Some(Ok(c)) => Ok(c),
_ => Err(ParserError::unexpected_eof()) _ => Err(ParserError::unexpected_eof()),
} }
} }
pub fn read_char(&mut self) -> Result<char, ParserError> { pub fn read_char(&mut self) -> Result<char, ParserError> {
match self.reader.read_char() { match self.reader.read_char() {
Some(Ok(c)) => Ok(c), Some(Ok(c)) => Ok(c),
_ => Err(ParserError::unexpected_eof()) _ => Err(ParserError::unexpected_eof()),
} }
} }
@@ -168,13 +168,15 @@ impl<'a, R: CharRead> Lexer<'a, R> {
match comment_loop() { match comment_loop() {
Err(e) if e.is_unexpected_eof() => { Err(e) if e.is_unexpected_eof() => {
return Err(ParserError::IncompleteReduction(self.line_num, self.col_num)); return Err(ParserError::IncompleteReduction(
self.line_num,
self.col_num,
));
} }
Err(e) => { Err(e) => {
return Err(e); return Err(e);
} }
Ok(_) => { Ok(_) => {}
}
} }
if prolog_char!(c) { if prolog_char!(c) {
@@ -362,7 +364,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if hexadecimal_digit_char!(c) { if hexadecimal_digit_char!(c) {
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
} else { } else {
Err(ParserError::IncompleteReduction(self.line_num, self.col_num)) Err(ParserError::IncompleteReduction(
self.line_num,
self.col_num,
))
} }
} }
@@ -395,7 +400,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}, },
) )
} else { } else {
Err(ParserError::IncompleteReduction(self.line_num, self.col_num)) Err(ParserError::IncompleteReduction(
self.line_num,
self.col_num,
))
} }
} }
@@ -463,9 +471,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| { .or_else(|_| {
Integer::from_str_radix(&token, 16) Integer::from_str_radix(&token, 16)
.map(|n| Token::Literal(Literal::Integer( .map(|n| {
arena_alloc!(n, &mut self.machine_st.arena) Token::Literal(Literal::Integer(arena_alloc!(
))) n,
&mut self.machine_st.arena
)))
})
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
} else { } else {
@@ -495,9 +506,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| { .or_else(|_| {
Integer::from_str_radix(&token, 8) Integer::from_str_radix(&token, 8)
.map(|n| Token::Literal(Literal::Integer( .map(|n| {
arena_alloc!(n, &mut self.machine_st.arena) Token::Literal(Literal::Integer(arena_alloc!(
))) n,
&mut self.machine_st.arena
)))
})
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
} else { } else {
@@ -527,9 +541,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| { .or_else(|_| {
Integer::from_str_radix(&token, 2) Integer::from_str_radix(&token, 2)
.map(|n| Token::Literal(Literal::Integer( .map(|n| {
arena_alloc!(n, &mut self.machine_st.arena) Token::Literal(Literal::Integer(arena_alloc!(
))) n,
&mut self.machine_st.arena
)))
})
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
} else { } else {
@@ -620,16 +637,20 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if token.as_str() == "[]" { if token.as_str() == "[]" {
Ok(Token::Literal(Literal::Atom(atom!("[]")))) Ok(Token::Literal(Literal::Atom(atom!("[]"))))
} else { } else {
Ok(Token::Literal(Literal::Atom( Ok(Token::Literal(Literal::Atom(AtomTable::build_with(
self.machine_st.atom_tbl.build_with(&token), &self.machine_st.atom_tbl,
))) &token,
))))
} }
} }
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> { fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
self.return_char(token.pop().unwrap()); self.return_char(token.pop().unwrap());
let n = parse_lossy::<f64, _>(token.as_bytes())?; let n = parse_lossy::<f64, _>(token.as_bytes())?;
Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena)))) Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
))))
} }
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> { fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -675,7 +696,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
token token
.parse::<Integer>() .parse::<Integer>()
.map(|n| { .map(|n| {
Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
)))
}) })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
@@ -740,17 +764,19 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
let n = parse_lossy::<f64, _>(token.as_bytes())?; let n = parse_lossy::<f64, _>(token.as_bytes())?;
Ok(Token::Literal(Literal::from( Ok(Token::Literal(Literal::from(float_alloc!(
float_alloc!(n, self.machine_st.arena) n,
))) self.machine_st.arena
))))
} else { } else {
return Ok(self.vacate_with_float(token)?); return Ok(self.vacate_with_float(token)?);
} }
} else { } else {
let n = parse_lossy::<f64, _>(token.as_bytes())?; let n = parse_lossy::<f64, _>(token.as_bytes())?;
Ok(Token::Literal(Literal::from( Ok(Token::Literal(Literal::from(float_alloc!(
float_alloc!(n, self.machine_st.arena) n,
))) self.machine_st.arena
))))
} }
} else { } else {
self.return_char('.'); self.return_char('.');
@@ -761,7 +787,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
token token
.parse::<Integer>() .parse::<Integer>()
.map(|n| { .map(|n| {
Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
)))
}) })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
@@ -772,7 +801,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
self.hexadecimal_constant(c).or_else(|e| { self.hexadecimal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e { if let ParserError::ParseBigInt(..) = e {
i64::from_str_radix(&token, 10) i64::from_str_radix(&token, 10)
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| {
Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
})
.or_else(|_| { .or_else(|_| {
token token
.parse::<Integer>() .parse::<Integer>()
@@ -794,7 +825,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
self.octal_constant(c).or_else(|e| { self.octal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e { if let ParserError::ParseBigInt(..) = e {
i64::from_str_radix(&token, 10) i64::from_str_radix(&token, 10)
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| {
Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
})
.or_else(|_| { .or_else(|_| {
token token
.parse::<Integer>() .parse::<Integer>()
@@ -816,7 +849,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
self.binary_constant(c).or_else(|e| { self.binary_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e { if let ParserError::ParseBigInt(..) = e {
i64::from_str_radix(&token, 10) i64::from_str_radix(&token, 10)
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| {
Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
})
.or_else(|_| { .or_else(|_| {
token token
.parse::<Integer>() .parse::<Integer>()
@@ -856,15 +891,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
.map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64)))) .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64))))
.or_else(|err| { .or_else(|err| {
match err { match err {
ParserError::UnexpectedChar('\'', ..) => { ParserError::UnexpectedChar('\'', ..) => {}
}
err => return Err(err), err => return Err(err),
} }
self.return_char(c); self.return_char(c);
i64::from_str_radix(&token, 10) i64::from_str_radix(&token, 10)
.map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .map(|n| {
Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
})
.or_else(|_| { .or_else(|_| {
token token
.parse::<Integer>() .parse::<Integer>()
@@ -901,7 +937,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
token token
.parse::<Integer>() .parse::<Integer>()
.map(|n| { .map(|n| {
Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
)))
}) })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
}) })
@@ -940,11 +979,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
pub fn scan_for_layout(&mut self) -> Result<bool, ParserError> { pub fn scan_for_layout(&mut self) -> Result<bool, ParserError> {
match self.lookahead_char() { match self.lookahead_char() {
Err(e) => { Err(e) => Err(e),
Err(e)
}
Ok(c) => { Ok(c) => {
let mut layout_info = LayoutInfo { inserted: false, more: true }; let mut layout_info = LayoutInfo {
inserted: false,
more: true,
};
let mut cr = Some(c); let mut cr = Some(c);
loop { loop {
@@ -1044,7 +1084,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if c == '"' { if c == '"' {
let s = self.char_code_list_token(c)?; let s = self.char_code_list_token(c)?;
let atom = self.machine_st.atom_tbl.build_with(&s); let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
Ok(Token::Literal(Literal::Atom(atom))) Ok(Token::Literal(Literal::Atom(atom)))
@@ -1054,7 +1094,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
if c == '\u{0}' { if c == '\u{0}' {
return Err(ParserError::unexpected_eof()) return Err(ParserError::unexpected_eof());
} }
self.name_token(c) self.name_token(c)

View File

@@ -7,13 +7,14 @@ macro_rules! char_class {
#[macro_export] #[macro_export]
macro_rules! alpha_char { macro_rules! alpha_char {
($c: expr) => { ($c: expr) => {
(!$c.is_numeric() && (!$c.is_numeric()
!$c.is_whitespace() && && !$c.is_whitespace()
!$c.is_control() && && !$c.is_control()
!$crate::graphic_token_char!($c) && && !$crate::graphic_token_char!($c)
!$crate::layout_char!($c) && && !$crate::layout_char!($c)
!$crate::meta_char!($c) && && !$crate::meta_char!($c)
!$crate::solo_char!($c)) || $c == '_' && !$crate::solo_char!($c))
|| $c == '_'
}; };
} }
@@ -131,7 +132,7 @@ macro_rules! hexadecimal_digit_char {
#[macro_export] #[macro_export]
macro_rules! layout_char { macro_rules! layout_char {
($c: expr) => { ($c: expr) => {
$crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) $crate::char_class!($c, [' ', '\r', '\n', '\t', '\u{0B}', '\u{0C}'])
}; };
} }

View File

@@ -7,7 +7,6 @@ use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::lexer::*; use crate::parser::lexer::*;
use std::cell::Cell; use std::cell::Cell;
use std::mem; use std::mem;
use std::ops::Neg; use std::ops::Neg;
@@ -59,6 +58,7 @@ struct TokenDesc {
tt: TokenType, tt: TokenType,
priority: usize, priority: usize,
spec: u32, spec: u32,
unfold_bounds: usize,
} }
pub(crate) fn as_partial_string( pub(crate) fn as_partial_string(
@@ -108,7 +108,7 @@ pub(crate) fn as_partial_string(
tail_ref = tail; tail_ref = tail;
} }
Term::CompleteString(_, cstr) => { Term::CompleteString(_, cstr) => {
string += cstr.as_str(); string += &*cstr.as_str();
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
break; break;
} }
@@ -120,26 +120,17 @@ pub(crate) fn as_partial_string(
} }
match &tail { match &tail {
Term::AnonVar | Term::Var(..) => { Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
Ok((string, Some(Box::new(tail)))) Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
}
Term::Literal(_, Literal::Atom(atom!("[]"))) => {
Ok((string, None))
}
Term::Literal(_, Literal::String(tail)) => { Term::Literal(_, Literal::String(tail)) => {
string += tail.as_str(); string += &*tail.as_str();
Ok((string, None)) Ok((string, None))
} }
_ => { _ => Ok((string, Some(Box::new(tail)))),
Ok((string, Some(Box::new(tail))))
}
} }
} }
pub fn get_op_desc( pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option<CompositeOpDesc> {
name: Atom,
op_dir: &CompositeOpDir,
) -> Option<CompositeOpDesc> {
let mut op_desc = CompositeOpDesc { let mut op_desc = CompositeOpDesc {
pre: 0, pre: 0,
inf: 0, inf: 0,
@@ -295,17 +286,17 @@ fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserEr
Ok(tokens) Ok(tokens)
} }
fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option<Atom> { fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
match term { match term {
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c), Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
_ => None, _ => None,
} }
} }
fn atomize_constant(atom_tbl: &mut AtomTable, c: Literal) -> Option<Atom> { fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
match c { match c {
Literal::Atom(ref name) => Some(*name), Literal::Atom(ref name) => Some(*name),
Literal::Char(c) => Some(atom_tbl.build_with(&c.to_string())), Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
_ => None, _ => None,
} }
} }
@@ -381,6 +372,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec, spec,
unfold_bounds: 0,
}); });
} }
} }
@@ -402,6 +394,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec, spec,
unfold_bounds: 0,
}); });
} }
} }
@@ -409,17 +402,21 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom))); self.terms
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
self.stack.push(TokenDesc { self.stack.push(TokenDesc {
tt: TokenType::Term, tt: TokenType::Term,
priority, priority,
spec: assoc, spec: assoc,
unfold_bounds: 0,
}); });
} }
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
let tt = match token { let tt = match token {
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => { Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_codes() =>
{
let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
for c in s.as_str().chars().rev() { for c in s.as_str().chars().rev() {
@@ -436,7 +433,9 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.push(list); self.terms.push(list);
TokenType::Term TokenType::Term
} }
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => { Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_chars() =>
{
self.terms.push(Term::CompleteString(Cell::default(), s)); self.terms.push(Term::CompleteString(Cell::default(), s));
TokenType::Term TokenType::Term
} }
@@ -465,7 +464,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
Token::End => TokenType::End, Token::End => TokenType::End,
}; };
self.stack.push(TokenDesc { tt, priority, spec }); self.stack.push(TokenDesc { tt, priority, spec, unfold_bounds: 0, });
} }
fn reduce_op(&mut self, priority: usize) { fn reduce_op(&mut self, priority: usize) {
@@ -573,7 +572,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
let idx = self.terms.len() - arity; let idx = self.terms.len() - arity;
if TokenType::Term == self.stack[stack_len].tt { if TokenType::Term == self.stack[stack_len].tt {
if atomize_term(&mut self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() { if atomize_term(&self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() {
self.stack.truncate(stack_len + 1); self.stack.truncate(stack_len + 1);
let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
@@ -581,38 +580,46 @@ impl<'a, R: CharRead> Parser<'a, R> {
if let Some(name) = self if let Some(name) = self
.terms .terms
.pop() .pop()
.and_then(|t| atomize_term(&mut self.lexer.machine_st.atom_tbl, &t)) .and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t))
{ {
// reduce the '.' functor to a cons cell if it applies. // reduce the '.' functor to a cons cell if it applies.
if name == atom!(".") && subterms.len() == 2 { if name == atom!(".") && subterms.len() == 2 {
let tail = subterms.pop().unwrap(); let tail = subterms.pop().unwrap();
let head = subterms.pop().unwrap(); let head = subterms.pop().unwrap();
self.terms.push( self.terms.push(match as_partial_string(head, tail) {
match as_partial_string(head, tail) { Ok((string_buf, Some(tail))) => {
Ok((string_buf, Some(tail))) => { Term::PartialString(Cell::default(), string_buf, tail)
Term::PartialString(Cell::default(), string_buf, tail) }
} Ok((string_buf, None)) => {
Ok((string_buf, None)) => { let atom = AtomTable::build_with(
let atom = self.lexer.machine_st.atom_tbl.build_with(&string_buf); &self.lexer.machine_st.atom_tbl,
Term::CompleteString(Cell::default(), atom) &string_buf,
} );
Err(term) => term, Term::CompleteString(Cell::default(), atom)
}, }
); Err(term) => term,
});
} else { } else {
self.terms.push(Term::Clause(Cell::default(), name, subterms)); self.terms
.push(Term::Clause(Cell::default(), name, subterms));
} }
if let Some(&mut TokenDesc { if let Some(&mut TokenDesc {
ref mut tt,
ref mut priority, ref mut priority,
ref mut spec, ref mut spec,
ref mut tt, ref mut unfold_bounds,
}) = self.stack.last_mut() }) = self.stack.last_mut()
{ {
if *spec == BTERM {
return false;
}
*tt = TokenType::Term; *tt = TokenType::Term;
*priority = 0; *priority = 0;
*spec = TERM; *spec = TERM;
*unfold_bounds = 0;
} }
return true; return true;
@@ -628,8 +635,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
if let Some(term) = self.terms.pop() { if let Some(mut term) = self.terms.pop() {
let op_desc = self.stack[index - 1]; let mut op_desc = self.stack[index - 1];
if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority {
/* '|' is a head-tail separator here, not /* '|' is a head-tail separator here, not
@@ -637,7 +644,26 @@ impl<'a, R: CharRead> Parser<'a, R> {
* terms it compacted out again. */ * terms it compacted out again. */
match (term.name(), term.arity()) { match (term.name(), term.arity()) {
(Some(name), 2) if name == atom!(",") => { (Some(name), 2) if name == atom!(",") => {
let terms = unfold_by_str(term, name); // notice: name == "," here. let terms = if op_desc.unfold_bounds == 0 {
unfold_by_str(term, atom!(","))
} else {
let mut terms = vec![];
while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) {
terms.push(fst);
term = snd;
op_desc.unfold_bounds -= 2;
if op_desc.unfold_bounds == 0 {
break;
}
}
terms.push(term);
terms
};
let arity = terms.len() - 1; let arity = terms.len() - 1;
self.terms.extend(terms.into_iter()); self.terms.extend(terms.into_iter());
@@ -695,7 +721,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
td.tt = TokenType::Term; td.tt = TokenType::Term;
td.priority = 0; td.priority = 0;
self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); self.terms
.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
return Ok(true); return Ok(true);
} }
} }
@@ -736,8 +763,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
if arity > self.terms.len() { if arity > self.terms.len() {
return Err(ParserError::IncompleteReduction( return Err(ParserError::IncompleteReduction(
self.lexer.line_num, self.lexer.line_num,
self.lexer.col_num self.lexer.col_num,
)) ));
} }
let idx = self.terms.len() - arity; let idx = self.terms.len() - arity;
@@ -752,21 +779,20 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: 0, priority: 0,
spec: TERM, spec: TERM,
unfold_bounds: 0,
}); });
self.terms.push(match list { self.terms.push(match list {
Term::Cons(_, head, tail) => { Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
match as_partial_string(*head, *tail) { Ok((string_buf, Some(tail))) => {
Ok((string_buf, Some(tail))) => { Term::PartialString(Cell::default(), string_buf, tail)
Term::PartialString(Cell::default(), string_buf, tail)
}
Ok((string_buf, None)) => {
let atom = self.lexer.machine_st.atom_tbl.build_with(&string_buf);
Term::CompleteString(Cell::default(), atom)
}
Err(term) => term,
} }
} Ok((string_buf, None)) => {
let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
Term::CompleteString(Cell::default(), atom)
}
Err(term) => term,
},
term => term, term => term,
}); });
@@ -784,10 +810,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
td.priority = 0; td.priority = 0;
td.spec = TERM; td.spec = TERM;
let term = Term::Literal( let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}")));
Cell::default(),
Literal::Atom(atom!("{}")),
);
self.terms.push(term); self.terms.push(term);
return Ok(true); return Ok(true);
@@ -818,11 +841,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
}; };
self.terms.push(Term::Clause( self.terms
Cell::default(), .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
atom!("{}"),
vec![term],
));
return Ok(true); return Ok(true);
} }
@@ -862,7 +882,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
.push(Term::Literal(Cell::default(), Literal::Atom(atom))); .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
} }
self.stack[idx].spec = TERM; self.stack[idx].spec = if self.stack[idx].priority > 0 { TERM } else { BTERM };
self.stack[idx].tt = TokenType::Term; self.stack[idx].tt = TokenType::Term;
self.stack[idx].priority = 0; self.stack[idx].priority = 0;
@@ -933,7 +953,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
if let Some(term) = self.terms.last().cloned() { if let Some(term) = self.terms.last().cloned() {
match term { match term {
Term::Literal(_, Literal::Atom(name)) Term::Literal(_, Literal::Atom(name))
if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => if name == atom!("-")
&& (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
{ {
self.stack.pop(); self.stack.pop();
self.terms.pop(); self.terms.pop();
@@ -983,7 +1004,9 @@ impl<'a, R: CharRead> Parser<'a, R> {
|n, arena| Literal::from(float_alloc!(n, arena)), |n, arena| Literal::from(float_alloc!(n, arena)),
), ),
Token::Literal(c) => { Token::Literal(c) => {
if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) { let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
if let Some(name) = atomized {
if !self.shift_op(name, op_dir)? { if !self.shift_op(name, op_dir)? {
self.shift(Token::Literal(c), 0, TERM); self.shift(Token::Literal(c), 0, TERM);
} }
@@ -1026,13 +1049,20 @@ impl<'a, R: CharRead> Parser<'a, R> {
/* '|' as an operator must have priority > 1000 and can only be infix. /* '|' as an operator must have priority > 1000 and can only be infix.
* See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78
*/ */
let bar_atom = atom!("|"); let (priority, spec) = get_op_desc(atom!("|"), op_dir)
let (priority, spec) = get_op_desc(bar_atom, op_dir)
.map(|CompositeOpDesc { inf, spec, .. }| (inf, spec)) .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER)); .unwrap_or((1000, DELIMITER));
let old_stack_len = self.stack.len();
self.reduce_op(priority); self.reduce_op(priority);
let new_stack_len = self.stack.len();
if let Some(term_desc) = self.stack.last_mut() {
term_desc.unfold_bounds = old_stack_len - new_stack_len;
}
self.shift(Token::HeadTailSeparator, priority, spec); self.shift(Token::HeadTailSeparator, priority, spec);
} }
Token::Comma => { Token::Comma => {
@@ -1069,7 +1099,11 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
// on success, returns the parsed term and the number of lines read. // on success, returns the parsed term and the number of lines read.
pub fn read_term(&mut self, op_dir: &CompositeOpDir, tokens: Tokens) -> Result<Term, ParserError> { pub fn read_term(
&mut self,
op_dir: &CompositeOpDir,
tokens: Tokens,
) -> Result<Term, ParserError> {
self.tokens = match tokens { self.tokens = match tokens {
Tokens::Default => read_tokens(&mut self.lexer)?, Tokens::Default => read_tokens(&mut self.lexer)?,
Tokens::Provided(tokens) => tokens, Tokens::Provided(tokens) => tokens,

View File

@@ -1,6 +1,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use std::alloc; use std::alloc;
use std::cell::UnsafeCell;
use std::ptr; use std::ptr;
pub trait RawBlockTraits { pub trait RawBlockTraits {
@@ -12,7 +13,7 @@ pub trait RawBlockTraits {
pub struct RawBlock<T: RawBlockTraits> { pub struct RawBlock<T: RawBlockTraits> {
pub base: *const u8, pub base: *const u8,
pub top: *const u8, pub top: *const u8,
pub ptr: *mut u8, pub ptr: UnsafeCell<*mut u8>,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
@@ -22,7 +23,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
RawBlock { RawBlock {
base: ptr::null(), base: ptr::null(),
top: ptr::null(), top: ptr::null(),
ptr: ptr::null_mut(), ptr: UnsafeCell::new(ptr::null_mut()),
_marker: PhantomData, _marker: PhantomData,
} }
} }
@@ -42,7 +43,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
self.base = alloc::alloc(layout) as *const _; self.base = alloc::alloc(layout) as *const _;
self.top = (self.base as usize + cap) as *const _; self.top = (self.base as usize + cap) as *const _;
self.ptr = self.base as *mut _; *self.ptr.get_mut() = self.base as *mut _;
} }
pub unsafe fn grow(&mut self) { pub unsafe fn grow(&mut self) {
@@ -54,7 +55,25 @@ impl<T: RawBlockTraits> RawBlock<T> {
self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _; self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
self.top = (self.base as usize + size * 2) as *const _; self.top = (self.base as usize + size * 2) as *const _;
self.ptr = (self.base as usize + size) as *mut _; *self.ptr.get_mut() = (self.base as usize + size) as *mut _;
}
}
pub unsafe fn grow_new(&self) -> Option<Self> {
if self.base.is_null() {
Some(Self::new())
} else {
let mut new_block = Self::empty_block();
new_block.init_at_size(self.size() * 2);
if new_block.base.is_null() {
// allocation failed
None
} else {
let allocated = (*self.ptr.get()) as usize - self.base as usize;
self.base.copy_to(new_block.base.cast_mut(), allocated);
*new_block.ptr.get_mut() = new_block.base.offset(allocated as isize).cast_mut();
Some(new_block)
}
} }
} }
@@ -64,35 +83,39 @@ impl<T: RawBlockTraits> RawBlock<T> {
} }
#[inline(always)] #[inline(always)]
fn free_space(&self) -> usize { unsafe fn free_space(&self) -> usize {
debug_assert!( debug_assert!(
self.ptr as *const _ >= self.base, *self.ptr.get() as *const _ >= self.base,
"self.ptr = {:?} < {:?} = self.base", "self.ptr = {:?} < {:?} = self.base",
self.ptr, *self.ptr.get(),
self.base self.base
); );
self.top as usize - self.ptr as usize self.top as usize - (*self.ptr.get()) as usize
} }
pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 { pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
if self.free_space() >= size { if self.free_space() >= size {
let ptr = self.ptr; let ptr = *self.ptr.get();
self.ptr = (self.ptr as usize + size) as *mut _; *self.ptr.get() = (ptr as usize + size) as *mut _;
ptr ptr
} else { } else {
ptr::null_mut() ptr::null_mut()
} }
} }
}
pub fn deallocate(&mut self) { impl<T: RawBlockTraits> Drop for RawBlock<T> {
unsafe { fn drop(&mut self) {
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align()); if !self.base.is_null() {
alloc::dealloc(self.base as *mut _, layout); unsafe {
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
alloc::dealloc(self.base as *mut _, layout);
}
self.top = ptr::null(); self.top = ptr::null();
self.base = ptr::null(); self.base = ptr::null();
self.ptr = ptr::null_mut(); *self.ptr.get_mut() = ptr::null_mut();
} }
} }
} }

220
src/rcu.rs Normal file
View File

@@ -0,0 +1,220 @@
use std::{
cell::OnceCell,
fmt::Debug,
mem::ManuallyDrop,
ops::Deref,
ptr::NonNull,
sync::{
atomic::{AtomicPtr, AtomicU8},
Arc, Weak, RwLock
},
};
// the epoch counters of all threads that have ever accessed an Rcu
// threads that have finished will have a dangling Weak reference and can be cleand up
// having this be shared between all Rcu's is a tradeof,
// writes will be slower as more epoch counters need to be waited for
// reads should be faster as a thread only needs to register itself once on the first read
//
static EPOCH_COUNTERS: RwLock<Vec<Weak<AtomicU8>>> = RwLock::new(Vec::new());
thread_local! {
// odd value means the current thread is about to access the active_epoch of an Rcu
// a thread has a single epoch counter for all Rcu it accesses,
// as a thread can only access one Rcu at a time
static THREAD_EPOCH_COUNTER: OnceCell<Arc<AtomicU8>> = OnceCell::new();
}
pub struct Rcu<T> {
active_value: AtomicPtr<T>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for Rcu<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let active_epoch = self.active_epoch();
f.debug_struct("Rcu")
.field("active_value", &active_epoch)
.finish()
}
}
impl<T> Rcu<T> {
pub fn new(initial_value: T) -> Self {
Rcu {
active_value: AtomicPtr::new(Arc::into_raw(Arc::new(initial_value)).cast_mut()),
}
}
pub fn active_epoch(&self) -> RcuRef<T, T> {
THREAD_EPOCH_COUNTER.with(|epoch_counter| {
let epoch_counter = epoch_counter.get_or_init(|| {
let epoch_counter = Arc::new(AtomicU8::new(0));
// register the current threads epoch counter on init
EPOCH_COUNTERS
.write()
.unwrap()
.push(Arc::downgrade(&epoch_counter));
epoch_counter
});
let old = epoch_counter.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
assert!(old % 2 == 0, "Old Epoch counter value should be even!");
});
let arc_ptr = self.active_value.load(std::sync::atomic::Ordering::Acquire);
let arc = unsafe {
// Safety:
// - the ptr was created in Rcu::new or Rcu::replace with Arc::into_raw
// - the Rcu is responsible for of the arc's strong refrences
// - the Rcu is alive as this function takes a reference to the Rcu
// - replace will wait with decrementing the old values strong count until our epoich counter is even again
Arc::increment_strong_count(arc_ptr);
// Safety:
// - the ptr was created in Rcu::new or Rcu::replace with Arc::into_raw
// - we have just ensured an additional strong count by incrementing the count
Arc::from_raw(arc_ptr)
};
THREAD_EPOCH_COUNTER.with(|epoch_counter| {
let old = epoch_counter
.get().expect("we initialized the OnceCell when we incremented the epoch counter the fist time")
.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
assert!(old % 2 != 0, "Old Epoch counter value should be odd!");
});
RcuRef {
data: arc.deref().into(),
arc,
}
}
/*
* replace the Rcu'S content with a new value
*
* This does not syncronize write and last to update the active_value pointer wins,
* all writes that do not win will be lost, though not leaked.
* This will block untill the old value can be reclaimed,
* i.e. all threads whitnest to be in the read critical sections
* have been witnest to have left the critical section at least once
*/
pub fn replace(&self, new_value: T) {
let arc_ptr = self.active_value.swap(
Arc::into_raw(Arc::new(new_value)).cast_mut(),
std::sync::atomic::Ordering::AcqRel,
);
// maually drop as we need to ensure not to drop the arc while
// we have not witnest all threads to be or have been outside the read critical section
// i.e. even epoch counter or different odd epoch counter
// Safety:
// - the ptr was created in Rcu::new or Rcu::replace with Arc::into_raw
// - the Rcu itself holds one strong count
let arc = unsafe { ManuallyDrop::new(Arc::from_raw(arc_ptr)) };
let epochs = EPOCH_COUNTERS.read().unwrap().clone();
let mut epochs = epochs
.into_iter()
.flat_map(|elem| {
let arc = elem.upgrade()?;
let init_val = arc.load(std::sync::atomic::Ordering::Acquire);
if init_val % 2 == 0 {
// already even can be ignored
return None;
}
// odd initial value thread is in read critical section
// need to wait for the value to change before we can drop the arc
Some((init_val, elem))
})
.collect::<Vec<_>>();
while !epochs.is_empty() {
epochs.retain(|elem| {
let Some(arc) = elem.1.upgrade() else {
// as the thread is dead it can't have a ref to old arc
return false;
};
// the epoch counter has not changed so the thread is still in the same instance of the critical section
// any different value is ok as
// - even values indicate the thread is outside the critical section
// - a diffrent odd value indicates the thread has left the critical section and can subsequently only read the new active_value
arc.load(std::sync::atomic::Ordering::Acquire) == elem.0
})
}
// Safety:
// - we have not dropped the arc another way
// - we witnessed all threads either with an even epoch count or with a new odd count
// as such they must have left the critical section at some point
ManuallyDrop::into_inner(arc);
}
}
pub struct RcuRef<T, M>
where
T: ?Sized,
M: ?Sized,
{
arc: Arc<T>,
data: NonNull<M>,
}
impl<T: ?Sized, M: ?Sized + Debug> Debug for RcuRef<T, M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RcuRef")
.field("data", &self.deref())
.finish()
}
}
// use assoiated functions rather than methods so that we don't overlap
// with functions of the Deref Target type
impl<T: ?Sized, M: ?Sized> RcuRef<T, M> {
pub fn map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> &'a N>(referece: Self, f: F) -> RcuRef<T, N> {
RcuRef {
arc: referece.arc,
data: f(unsafe { referece.data.as_ref() }).into(),
}
}
pub fn try_map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> Option<&'a N>>(
referece: Self,
f: F,
) -> Option<RcuRef<T, N>> {
let val = f(unsafe { referece.data.as_ref() })?;
Some(RcuRef {
arc: Arc::clone(&referece.arc),
data: val.into(),
})
}
pub fn same_epoch<M2>(this: &Self, other: &RcuRef<T, M2>) -> bool {
Arc::ptr_eq(&this.arc, &other.arc)
}
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.data == other.data
}
pub fn clone(this: &Self) -> Self {
Self {
arc: Arc::clone(&this.arc),
data: this.data,
}
}
pub fn get_root(this: &Self) -> &T {
&this.arc
}
}
impl<T: ?Sized, M: ?Sized> Deref for RcuRef<T, M> {
type Target = M;
fn deref(&self) -> &Self::Target {
// Safety: The pointer points into the arc we are holding
// while we are alive so is the target
// as the content is in an Rcu no mutable acess is given out
unsafe { self.data.as_ref() }
}
}

View File

@@ -16,8 +16,6 @@ use crate::types::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
@@ -26,19 +24,20 @@ use rustyline::history::DefaultHistory;
use rustyline::{Config, Editor}; use rustyline::{Config, Editor};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::{Cursor, Error, ErrorKind, Read}; use std::io::{Cursor, Read};
#[cfg(feature = "repl")]
use std::io::{Error, ErrorKind};
use std::sync::Arc;
type SubtermDeque = VecDeque<(usize, usize)>; type SubtermDeque = VecDeque<(usize, usize)>;
pub(crate) fn devour_whitespace<'a, R: CharRead>(parser: &mut Parser<'a, R>) -> Result<bool, ParserError> { pub(crate) fn devour_whitespace<'a, R: CharRead>(
parser: &mut Parser<'a, R>,
) -> Result<bool, ParserError> {
match parser.lexer.scan_for_layout() { match parser.lexer.scan_for_layout() {
Err(e) if e.is_unexpected_eof() => { Err(e) if e.is_unexpected_eof() => Ok(true),
Ok(true)
}
Err(e) => Err(e), Err(e) => Err(e),
Ok(_) => { Ok(_) => Ok(false),
Ok(false)
}
} }
} }
@@ -60,7 +59,6 @@ pub(crate) fn error_after_read_term<R>(
CompilationError::from(err) CompilationError::from(err)
} }
impl MachineState { impl MachineState {
pub(crate) fn read( pub(crate) fn read(
&mut self, &mut self,
@@ -74,18 +72,20 @@ impl MachineState {
parser.add_lines_read(prior_num_lines_read); parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&op_dir, Tokens::Default) let term = parser
.read_term(&op_dir, Tokens::Default)
.map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
(term, parser.lines_read() - prior_num_lines_read) (term, parser.lines_read() - prior_num_lines_read)
}; };
inner.add_lines_read(num_lines_read); inner.add_lines_read(num_lines_read);
write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl) write_term_to_heap(&term, &mut self.heap, &self.atom_tbl)
} }
} }
static mut PROMPT: bool = false; static mut PROMPT: bool = false;
#[cfg(feature = "repl")]
const HISTORY_FILE: &'static str = ".scryer_history"; const HISTORY_FILE: &'static str = ".scryer_history";
pub(crate) fn set_prompt(value: bool) { pub(crate) fn set_prompt(value: bool) {
@@ -94,6 +94,7 @@ pub(crate) fn set_prompt(value: bool) {
} }
} }
#[cfg(feature = "repl")]
#[inline] #[inline]
fn get_prompt() -> &'static str { fn get_prompt() -> &'static str {
unsafe { unsafe {
@@ -110,55 +111,54 @@ pub struct ReadlineStream {
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
rl: Editor<Helper, DefaultHistory>, rl: Editor<Helper, DefaultHistory>,
pending_input: CharReader<Cursor<String>>, pending_input: CharReader<Cursor<String>>,
#[allow(dead_code)]
add_history: bool, add_history: bool,
} }
impl ReadlineStream { impl ReadlineStream {
#[cfg(feature = "repl")]
#[inline] #[inline]
pub fn new(pending_input: &str, add_history: bool) -> Self { pub fn new(pending_input: &str, add_history: bool) -> Self {
let config = Config::builder() #[cfg(feature = "repl")]
.check_cursor_position(true) {
.build(); let config = Config::builder().check_cursor_position(true).build();
let helper = Helper::new(); let helper = Helper::new();
let mut rl = Editor::with_config(config).unwrap(); let mut rl = Editor::with_config(config).unwrap();
rl.set_helper(Some(helper)); rl.set_helper(Some(helper));
if let Some(mut path) = dirs_next::home_dir() { if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE); path.push(HISTORY_FILE);
if path.exists() && rl.load_history(&path).is_err() { if path.exists() && rl.load_history(&path).is_err() {
println!("Warning: loading history failed"); println!("Warning: loading history failed");
}
}
ReadlineStream {
rl,
pending_input: CharReader::new(Cursor::new(pending_input.to_owned())),
add_history: add_history,
} }
} }
ReadlineStream { #[cfg(not(feature = "repl"))]
rl, {
pending_input: CharReader::new(Cursor::new(pending_input.to_owned())), ReadlineStream {
add_history: add_history, pending_input: CharReader::new(Cursor::new(pending_input.to_owned())),
add_history: add_history,
}
} }
} }
#[cfg(not(feature = "repl"))] #[allow(unused_variables)]
#[inline] pub fn set_atoms_for_completion(&mut self, atoms: &Arc<AtomTable>) {
pub fn new(pending_input: &str, add_history: bool) -> Self { #[cfg(feature = "repl")]
ReadlineStream { {
pending_input: CharReader::new(Cursor::new(pending_input.to_owned())), let helper = self.rl.helper_mut().unwrap();
add_history: add_history, helper.atoms = Arc::downgrade(atoms);
} }
} }
#[cfg(feature = "repl")]
pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
let helper = self.rl.helper_mut().unwrap();
helper.atoms = atoms;
}
#[cfg(not(feature = "repl"))]
pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
}
#[inline] #[inline]
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.pending_input.reset_buffer(); self.pending_input.reset_buffer();
@@ -180,7 +180,9 @@ impl ReadlineStream {
unsafe { unsafe {
if PROMPT { if PROMPT {
self.rl.add_history_entry(self.pending_input.get_ref().get_ref()).unwrap(); self.rl
.add_history_entry(self.pending_input.get_ref().get_ref())
.unwrap();
self.save_history(); self.save_history();
PROMPT = false; PROMPT = false;
} }
@@ -219,9 +221,9 @@ impl ReadlineStream {
} }
} }
#[allow(dead_code)]
#[cfg(not(feature = "repl"))] #[cfg(not(feature = "repl"))]
fn save_history(&mut self) { fn save_history(&mut self) {}
}
#[inline] #[inline]
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> { pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
@@ -253,7 +255,7 @@ impl Read for ReadlineStream {
self.call_readline()?; self.call_readline()?;
self.pending_input.read(buf) self.pending_input.read(buf)
} }
result => result result => result,
} }
} }
} }
@@ -266,16 +268,14 @@ impl CharRead for ReadlineStream {
Some(Ok(c)) => { Some(Ok(c)) => {
return Some(Ok(c)); return Some(Ok(c));
} }
_ => { _ => match self.call_readline() {
match self.call_readline() { Err(e) => {
Err(e) => { return Some(Err(e));
return Some(Err(e));
}
_ => {
set_prompt(false);
}
} }
} _ => {
set_prompt(false);
}
},
} }
} }
} }
@@ -295,7 +295,7 @@ impl CharRead for ReadlineStream {
pub(crate) fn write_term_to_heap<'a, 'b>( pub(crate) fn write_term_to_heap<'a, 'b>(
term: &'a Term, term: &'a Term,
heap: &'b mut Heap, heap: &'b mut Heap,
atom_tbl: &mut AtomTable, atom_tbl: &AtomTable,
) -> Result<TermWriteResult, CompilationError> { ) -> Result<TermWriteResult, CompilationError> {
let term_writer = TermWriter::new(heap, atom_tbl); let term_writer = TermWriter::new(heap, atom_tbl);
term_writer.write_term_to_heap(term) term_writer.write_term_to_heap(term)
@@ -304,7 +304,7 @@ pub(crate) fn write_term_to_heap<'a, 'b>(
#[derive(Debug)] #[derive(Debug)]
struct TermWriter<'a, 'b> { struct TermWriter<'a, 'b> {
heap: &'a mut Heap, heap: &'a mut Heap,
atom_tbl: &'b mut AtomTable, atom_tbl: &'b AtomTable,
queue: SubtermDeque, queue: SubtermDeque,
var_dict: HeapVarDict, var_dict: HeapVarDict,
} }
@@ -317,7 +317,7 @@ pub struct TermWriteResult {
impl<'a, 'b> TermWriter<'a, 'b> { impl<'a, 'b> TermWriter<'a, 'b> {
#[inline] #[inline]
fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self { fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
TermWriter { TermWriter {
heap, heap,
atom_tbl, atom_tbl,
@@ -347,17 +347,18 @@ impl<'a, 'b> TermWriter<'a, 'b> {
match term { match term {
&TermRef::Cons(..) => list_loc_as_cell!(h), &TermRef::Cons(..) => list_loc_as_cell!(h),
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
&TermRef::CompleteString(_, _, ref src) => &TermRef::CompleteString(_, _, ref src) => {
if src.as_str().is_empty() { if src.as_str().is_empty() {
empty_list_as_cell!() empty_list_as_cell!()
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr { } else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
heap_loc_as_cell!(h) heap_loc_as_cell!(h)
} else { } else {
pstr_loc_as_cell!(h) pstr_loc_as_cell!(h)
}, }
}
&TermRef::PartialString(..) => pstr_loc_as_cell!(h), &TermRef::PartialString(..) => pstr_loc_as_cell!(h),
&TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
&TermRef::Clause(_,_,_,subterms) if subterms.len() == 0 => heap_loc_as_cell!(h), &TermRef::Clause(_, _, _, subterms) if subterms.len() == 0 => heap_loc_as_cell!(h),
&TermRef::Clause(..) => str_loc_as_cell!(h), &TermRef::Clause(..) => str_loc_as_cell!(h),
} }
} }
@@ -427,7 +428,8 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
&TermRef::AnonVar(_) => { &TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
self.var_dict.insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h)); self.var_dict
.insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
if arity > 1 { if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1)); self.queue.push_front((arity - 1, site_h + 1));
@@ -437,7 +439,8 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue; continue;
} }
&TermRef::CompleteString(_, _, ref src) => { &TermRef::CompleteString(_, _, ref src) => {
put_complete_string(self.heap, src.as_str(), self.atom_tbl); let src = src.as_str().to_owned();
put_complete_string(self.heap, &src, self.atom_tbl);
} }
&TermRef::PartialString(lvl, _, ref src, _) => { &TermRef::PartialString(lvl, _, ref src, _) => {
if let Level::Root = lvl { if let Level::Root = lvl {

View File

@@ -1,23 +1,24 @@
use indexmap::IndexSet; use rustyline::completion::Completer;
use rustyline::completion::{Completer, Candidate}; use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
use rustyline::hint::Hinter; use rustyline::hint::Hinter;
use rustyline::validate::Validator; use rustyline::validate::Validator;
use rustyline::highlight::{MatchingBracketHighlighter, Highlighter}; use rustyline::{Context, Helper as RlHelper, Result};
use rustyline::{Helper as RlHelper, Result, Context};
use crate::atom_table::{Atom, STATIC_ATOMS_MAP}; use std::sync::Weak;
use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP};
// TODO: Maybe add validation to the helper // TODO: Maybe add validation to the helper
pub struct Helper { pub struct Helper {
highligher: MatchingBracketHighlighter, highligher: MatchingBracketHighlighter,
pub atoms: *const IndexSet<Atom>, pub atoms: Weak<AtomTable>,
} }
impl Helper { impl Helper {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
highligher: MatchingBracketHighlighter::new(), highligher: MatchingBracketHighlighter::new(),
atoms: std::ptr::null(), atoms: Weak::new(),
} }
} }
} }
@@ -43,7 +44,7 @@ fn get_prefix(line: &str, pos: usize) -> Option<usize> {
} }
if i == pos { if i == pos {
break break;
} }
} }
@@ -54,39 +55,33 @@ fn get_prefix(line: &str, pos: usize) -> Option<usize> {
start_of_atom start_of_atom
} }
pub struct StrPtr(*const str);
impl Candidate for StrPtr {
fn display(&self) -> &str {
unsafe {
self.0.as_ref().unwrap()
}
}
fn replacement(&self) -> &str {
unsafe {
self.0.as_ref().unwrap()
}
}
}
impl Completer for Helper { impl Completer for Helper {
type Candidate = StrPtr; type Candidate = AtomString<'static>;
fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<Self::Candidate>)> { fn complete(
&self,
line: &str,
pos: usize,
_ctx: &Context<'_>,
) -> Result<(usize, Vec<Self::Candidate>)> {
let start_of_prefix = get_prefix(line, pos); let start_of_prefix = get_prefix(line, pos);
if let Some(idx) = start_of_prefix { if let Some(idx) = start_of_prefix {
let sub_str = line.get(idx..pos).unwrap(); let sub_str = line.get(idx..pos).unwrap();
Ok((idx, unsafe {
let mut matching = (*self.atoms).iter()
.chain(STATIC_ATOMS_MAP.values())
.filter(|a| a.as_str().starts_with(sub_str))
.map(|s| StrPtr(s.as_str()))
.collect::<Vec<_>>();
matching.sort_unstable_by(|a, b| Ord::cmp(&(*a.0).len(), &(*b.0).len())); let atom_table = self.atoms.upgrade().unwrap();
matching
})) let index_set = atom_table.active_table();
let mut matching = index_set
.iter()
.chain(STATIC_ATOMS_MAP.values())
.map(|a| a.as_str())
.filter(|a| a.starts_with(sub_str))
.collect::<Vec<_>>();
matching.sort_unstable_by(|a, b| Ord::cmp(&a.len(), &b.len()));
Ok((idx, matching))
} else { } else {
Ok((0, vec![])) Ok((0, vec![]))
} }

306
src/tests/acyclic_term.pl Normal file
View File

@@ -0,0 +1,306 @@
:- use_module(library(dcgs)).
:- use_module(library(format)).
term1(A) :-
B=[C|D],
A=[D|C],
B=[C|B].
term2(A) :-
A=[B|C],
D=[C|C],
D=[B|D].
term3(A) :-
A=[_B|C],
D=[C|_E],
A=[C|D].
term4(A) :-
A=[B|C],
C=[C|B].
term5(A) :-
A=[_B|C],
D=[_E|C],
A=[C|D].
term6(A) :-
A=[B|B],
B=[C|C].
term7(A) :-
B=[C|D],
A=[D|C],
B=[B|D].
term8(A) :-
B=C,
B=[C|_D],
A=[C|_E].
test("acyclic_term_1", (
L = [_Y,[M,B],B|M], acyclic_term(L)
)).
test("acyclic_term_2", (
L = [_Y,[M,_B,L]|M], \+ acyclic_term(L)
)).
test("acyclic_term_3", (
L = [_Y,[M,B,L,B]|M], \+ acyclic_term(L)
)).
test("acyclic_term_4", (
L = [_Y,[L,_A,_B]|_M], \+ acyclic_term(L)
)).
test("acyclic_term_5", (
L = [_Y,[M,_A,_B]|M], acyclic_term(L)
)).
test("acyclic_term_6", (
L = [_Y,[L,_A,_B]|_M], \+ acyclic_term(L)
)).
test("acyclic_term_7", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(T)
)).
test("acyclic_term_8", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(L)
)).
test("acyclic_term_9", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(A)
)).
test("acyclic_term_10", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(Y)
)).
test("acyclic_term_11", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(X)
)).
test("acyclic_term_12", (
A = [1|2], X = A, T=a(X, A), acyclic_term(T)
)).
test("acyclic_term_13", (
A = [A|2], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_14", (
A = [T|2], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_15", (
T = [_A|T], \+ acyclic_term(T)
)).
test("acyclic_term_16", (
T = [T|_L], \+ acyclic_term(T)
)).
test("acyclic_term_17", (
A = [1|A], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_18", (
T = [_A| [[[[L|T]|[]]]]], acyclic_term(L)
)).
test("acyclic_term_19", (
T = [A| [[[[_L|T]|[]]]]], acyclic_term(A)
)).
test("acyclic_term_20", (
T = [_A| [[[[_L|T]|[]]]]], \+ acyclic_term(T)
)).
test("acyclic_term_21", (
A = [_C|_B], X = A, T=a(t(X,A), A), acyclic_term(T)
)).
test("acyclic_term_22", (
X = [a | Rest], Rest = [_Y | Rest], \+ acyclic_term(X)
)).
test("acyclic_term_23", (
_X = [a | Rest], Rest = [_Y | Rest], \+ acyclic_term(Rest)
)).
test("acyclic_term_24", (
T = [[_A, T]], G = [1|T], \+ acyclic_term(G)
)).
test("acyclic_term_25", (
T = [[_A, T]], \+ acyclic_term(T)
)).
test("acyclic_term_26", (
T = [[_, _], T], \+ acyclic_term(T)
)).
test("acyclic_term_27", (
T = [[T, _], 1], \+ acyclic_term(T)
)).
test("acyclic_term_28", (
T = str(A,A), acyclic_term(T)
)).
test("acyclic_term_29", (
T = str(A,A,A), acyclic_term(T)
)).
test("acyclic_term_30", (
A = s(B, d(Y)), Y = B, acyclic_term(A),
acyclic_term(B), acyclic_term(Y)
)).
test("acyclic_term_31", (
A=str(B,B,B), C=str(A,_D,B), acyclic_term(C),
acyclic_term(A), acyclic_term(B)
)).
test("acyclic_term_32", (
A=B*C,A=[]*B*D*B, \+ acyclic_term(A),
\+ acyclic_term(B), \+ acyclic_term(C),
acyclic_term(D)
)).
test("acyclic_term_33", (
A=B*C,A=B*[]*B, \+ acyclic_term(A),
\+ acyclic_term(B), \+ acyclic_term(C)
)).
test("acyclic_term#2111_1", (
term1(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_2", (
term2(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_3", (
term3(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_4", (
term4(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_5", (
term5(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_6", (
term6(A), acyclic_term(A)
)).
test("acyclic_term#2113", (
A=[]*B,B=[]*B, \+ acyclic_term(A)
)).
test("acyclic_term#2114", (
A=B*B, acyclic_term(A)
)).
test("acyclic_term#2116", (
A=B*B,B=[]*[], acyclic_term(A)
)).
test("acyclic_term#2117", (
A=[]*A,B=[]*A, \+ acyclic_term(B)
)).
test("acyclic_term#2121", (
A=B*B, C=A*B, acyclic_term(C),
acyclic_term(A), acyclic_term(B)
)).
test("acyclic_term#2122", (
A=B*C,A=[]*B*B, \+ acyclic_term(A),
\+ acyclic_term(B), \+ acyclic_term(C)
)).
test("acyclic_term#2123", (
A=B*B,C=A*B,B=[]*[], acyclic_term(A),
acyclic_term(B), acyclic_term(C)
)).
test("acyclic_term#2124", (
A=B*C,B=[]*C,C=[]*B, \+ acyclic_term(A),
\+ acyclic_term(B), \+ acyclic_term(C)
)).
test("acyclic_term#2125", (
A=B*[],
D=B*[],
A=B,
\+ acyclic_term(D),
\+ acyclic_term(A),
\+ acyclic_term(B)
)).
test("acyclic_term#2130_1", (
term7(T),
\+ acyclic_term(T)
)).
test("acyclic_term#2130_2", (
term8(T),
\+ acyclic_term(T)
)).
test("acyclic_term#2131", (
A=[B],C=[B],C=[A],
\+ acyclic_term(C)
)).
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).

270
src/tests/dif.pl Normal file
View File

@@ -0,0 +1,270 @@
/**/
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(debug)).
:- use_module(library(atts)).
:- use_module(library(dif)).
% Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif
test("dif#1",(
call_residual_goals(dif(1,2), Res),
Res = []
)).
test("dif#2",(
\+ (dif(1,Y), Y = 1)
)).
test("dif#3",(
call_residual_goals((dif(1,Y), Y=2), Res),
Y == 2,
Res = []
)).
test("dif#4",(
\+ (dif(X,-Y), X= -Y)
)).
test("dif#5",(
\+ (dif(X,Y), X=Y)
)).
test("dif#6",(
\+ (dif(X,Y), X=Y, X=1)
)).
test("dif#7",(
\+ (dif(-X,-Y), X=Y)
)).
test("dif#8",(
\+ (dif(-X,-Y), X=Y, X=1)
)).
% I don't understand exactly what is expected for dif#9 and dif#10
test("dif#11",(
call_residual_goals((X=Y, dif(X-Y,1-2)), Res),
X == Y,
Res = []
)).
test("dif#12",(
call_residual_goals((dif(X-Y,1-2), X=Y), Res),
X == Y,
Res = []
)).
test("dif#13",(
call_residual_goals((X=Y, Y=1, dif(X-Y,1-2)), Res),
X == 1,
Y == 1,
Res = []
)).
test("dif#14",(
call_residual_goals((dif(X-Y,1-2), X=Y, Y=1), Res),
X == 1,
Y == 1,
Res = []
)).
test("dif#15",(
call_residual_goals((dif(X-Y,1-2), X=Y, X=2), Res),
X == 2,
Y == 2,
Res = []
)).
test("dif#16",(
call_residual_goals((dif(A-C,B-D), C-D=z-z, A-B=1-2), Res),
A == 1,
B == 2,
C == z,
D == z,
Res = []
)).
test("dif#17",(
call_residual_goals((A-B=1-2, C-D=z-z, dif(A-C,B-D)), Res),
A == 1,
B == 2,
C == z,
D == z,
Res = []
)).
test("dif#18",(
call_residual_goals((dif(A,[C|B]), A=[[]|_], A=[B]), Res),
A == [[]],
B == [],
Res = [dif:dif([[]], [C])]
)).
test("dif#19",(
call_residual_goals((dif([E],[/]), E=1), Res),
E == 1,
Res = []
)).
test("dif#20",(
call_residual_goals((dif([a],B), B=[_|_], B=[b]), Res),
B == [b],
Res = []
)).
test("dif#21",(
call_residual_goals((dif([],A), A = [_]), Res),
A = [_],
Res = []
)).
test("dif#22",(
call_residual_goals((A = [_], dif([],A)), Res),
A = [_],
Res = []
)).
test("dif#t1",(
set_prolog_flag(occurs_check, false),
\+ \+ -X=X
)).
test("dif#t2",(
set_prolog_flag(occurs_check, false),
\+ (-X=X, -Y=Y, X\=Y)
)).
test("dif#t3",(
set_prolog_flag(occurs_check, false),
call_residual_goals((-X=X, dif(X,1)), Res),
X == -X,
Res = []
)).
test("dif#t4",(
set_prolog_flag(occurs_check, false),
\+ (-X=X, -Y=Y, dif(X,Y))
)).
test("dif#t5",(
set_prolog_flag(occurs_check, false),
\+ (dif(X,Y), -X=X, -Y=Y)
)).
test("dif#t6",(
set_prolog_flag(occurs_check, false),
\+ (A=[[]|A],dif(A,B),B=[[]|A])
)).
test("dif#t7",(
set_prolog_flag(occurs_check, false),
\+ (dif(-X,X),-Y=Y,X=Y)
)).
test("dif#o1",(
set_prolog_flag(occurs_check, true),
\+ (-X = X)
)).
test("dif#o2",(
set_prolog_flag(occurs_check, true),
call_residual_goals((dif(-X,X)), Res),
Res = []
)).
test("dif#o3",(
set_prolog_flag(occurs_check, true),
call_residual_goals((dif(-X,Y), X=Y), Res),
X == Y,
Res = []
)).
test("dif#12 but with multiple variables in the residuals",(
call_residual_goals((dif(X-Y-_, 1-2-3), X = Y), Res),
X == Y,
Res = []
)).
% https://github.com/mthom/scryer-prolog/issues/1956
test("scryer-prolog#1956",(
call_residue_vars((dif(a-a,X-_),X=b), Res),
X == b,
Res = []
)).
% https://github.com/mthom/scryer-prolog/issues/2056
test("scryer-prolog#2056",(
set_prolog_flag(occurs_check, false),
C=[D|E],
D=[C],
A=[A],
dif(A,[D]),
\+ E=[]
)).
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
assert_p(A, B) :-
phrase(portray_clause_(A), Portrayed),
phrase((B, ".\n"), Portrayed).
call_residual_goals(Goal, ResidualGoals) :-
call_residue_vars(Goal, Vars),
variables_residual_goals(Vars, ResidualGoals).
variables_residual_goals(Vars, Goals) :-
phrase(variables_residual_goals(Vars), Goals).
variables_residual_goals([]) --> [].
variables_residual_goals([Var|Vars]) -->
dif:attribute_goals(Var),
variables_residual_goals(Vars).

83
src/tests/ground.pl Normal file
View File

@@ -0,0 +1,83 @@
/**/
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(debug)).
:- use_module(library(atts)).
:- attribute a/1.
a(Var) :- put_atts(Var, +a(hello)).
test("ground#239", (
% double negate to avoid residual goal being printed
\+ \+ (a(X), var(X), \+ ground(X))
)).
test("ground#1411",(
G_0 = ( A=s(A) ), G_0,
ground(A), ground(G_0)
)).
test("ground#2065",(
A = [B|_C], B = [A], \+ ground(B), \+ground([B])
)).
test("ground#2073",(
\+ ground(_-1+_-1),
\+ ground(1-1-_)
)).
test("ground#2075",(
G_0 = (_,_,ground(_)),
G_0 = (D=[D|_],_=D*[],ground(D)),
\+ G_0,
_=_B*_,_D=_B*_A,_B=_B*_D,\+ ground(_B),
A=[A|B],B=A*B,ground(A)
)).
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).

117
src/tests/term_variables.pl Normal file
View File

@@ -0,0 +1,117 @@
/**/
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(debug)).
test("term_variables#1400", (
term_variables(A+B*C/B-D, Vars),
term_variables(t(A,B,C,D), Vars),
Vars = [A,B,C,D]
)).
test("term_variables#1405", (
\+ (B=[C|D],C=[_|D],C=[B|B], term_variables(B,_), false)
)).
test("term_variables#1409", (
G_0 = (A=[B|B],A=[C|C]), G_0, term_variables(G_0, Vars), Vars = [B]
)).
test("term_variables#1410", (
\+ \+ (G_0 = ( A=s(A) ), G_0, term_variables(G_0, Vars), Vars = []),
E_0 = (_=[B|B]), G_0 = (E_0,\_=B), G_0, term_variables(G_0, Vars)
)).
test("term_variables#1412", (
G_0 = =([A|B],[A|B]), G_0, term_variables(G_0, Vars),
Vars = [A,B]
)).
test("term_variables#1414", (
\+ (\B=A,C=[A|D],B=[a,b|E],C=[D|E], term_variables(\E,_), false)
)).
test("term_variables#2063", (
A=[B|C], B=[A], term_variables([B], Vars),
Vars = [C]
)).
test("term_variables#2097", (
termt(T), term_variables(T,Vs),
T = [[[A|B]|A]|A], Vs == [A,B]
)).
test("term_variables#2100", (
termt2(T), term_variables(T,Vs),
T = [[T|A]|B], Vs == [A,B]
)).
test("term_variables#2101", (
termt3(T), term_variables(T,Vs),
T = [[[[A|B]|A]|A]|A], Vs == [A, B]
)).
termt(T) :-
T = [T1|T2],
T1 = [T3|A],
T3 = [A|_],
T2 = A.
termt2(T) :-
T = [T1|_B],
T1 = [T|_A].
termt3(T) :-
T = [T1|T0],
T1 = [T2|T3],
T2 = [T4|A],
T4 = [A|_],
T3 = A,
T0 = A.
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).

View File

@@ -235,8 +235,12 @@ double_quotes_option(DQ) :-
; DQ = false ; DQ = false
). ).
answer_write_options(Os) :-
current_prolog_flag(answer_write_options, Os).
write_goal(G, VarList, MaxDepth) :- write_goal(G, VarList, MaxDepth) :-
double_quotes_option(DQ), double_quotes_option(DQ),
answer_write_options(Os),
( G = (Var = Value) -> ( G = (Var = Value) ->
( var(Value) -> ( var(Value) ->
select((Var = _), VarList, NewVarList) select((Var = _), VarList, NewVarList)
@@ -246,17 +250,18 @@ write_goal(G, VarList, MaxDepth) :-
write(' = '), write(' = '),
( needs_bracketing(Value, =) -> ( needs_bracketing(Value, =) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)]), write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)|Os]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)]) ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)|Os])
) )
; G == [] -> ; G == [] ->
write('true') write('true')
; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth), double_quotes(DQ)]) ; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth), double_quotes(DQ)|Os])
). ).
write_last_goal(G, VarList, MaxDepth) :- write_last_goal(G, VarList, MaxDepth) :-
double_quotes_option(DQ), double_quotes_option(DQ),
answer_write_options(Os),
( G = (Var = Value) -> ( G = (Var = Value) ->
( var(Value) -> ( var(Value) ->
select((Var = _), VarList, NewVarList) select((Var = _), VarList, NewVarList)
@@ -266,9 +271,9 @@ write_last_goal(G, VarList, MaxDepth) :-
write(' = '), write(' = '),
( needs_bracketing(Value, =) -> ( needs_bracketing(Value, =) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)]), write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)|Os]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)]), ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth), double_quotes(DQ)|Os]),
( trailing_period_is_ambiguous(Value) -> ( trailing_period_is_ambiguous(Value) ->
write(' ') write(' ')
; true ; true
@@ -276,7 +281,7 @@ write_last_goal(G, VarList, MaxDepth) :-
) )
; G == [] -> ; G == [] ->
write('true') write('true')
; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth), double_quotes(DQ)]) ; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth), double_quotes(DQ)|Os])
). ).
write_eq((G1, G2), VarList, MaxDepth) :- write_eq((G1, G2), VarList, MaxDepth) :-
@@ -447,3 +452,4 @@ print_exception_with_check(E) :-
% is expected to be printed instead. % is expected to be printed instead.
; print_exception(E) ; print_exception(E)
). ).

View File

@@ -24,7 +24,7 @@ pub enum HeapCellValueTag {
PStrOffset = 0b001111, PStrOffset = 0b001111,
// constants. // constants.
Cons = 0b0, Cons = 0b0,
F64 = 0b010001, F64 = 0b010001,
Fixnum = 0b010011, Fixnum = 0b010011,
Char = 0b010101, Char = 0b010101,
Atom = 0b010111, Atom = 0b010111,
@@ -45,7 +45,7 @@ pub enum HeapCellValueView {
PStrOffset = 0b001111, PStrOffset = 0b001111,
// constants. // constants.
Cons = 0b0, Cons = 0b0,
F64 = 0b010001, F64 = 0b010001,
Fixnum = 0b010011, Fixnum = 0b010011,
Char = 0b010101, Char = 0b010101,
Atom = 0b010111, Atom = 0b010111,
@@ -56,9 +56,9 @@ pub enum HeapCellValueView {
TrailedHeapVar = 0b101111, TrailedHeapVar = 0b101111,
TrailedStackVar = 0b101011, TrailedStackVar = 0b101011,
TrailedAttrVar = 0b100001, TrailedAttrVar = 0b100001,
TrailedAttrVarListLink = 0b100011, TrailedAttrVarListLink = 0b100011,
TrailedAttachedValue = 0b100101, TrailedAttachedValue = 0b100101,
TrailedBlackboardEntry = 0b100111, TrailedBlackboardEntry = 0b100111,
TrailedBlackboardOffset = 0b110011, TrailedBlackboardOffset = 0b110011,
} }
@@ -88,7 +88,7 @@ impl ConsPtr {
.with_tag(tag) .with_tag(tag)
} }
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
#[inline(always)] #[inline(always)]
pub fn as_ptr(self) -> *mut u8 { pub fn as_ptr(self) -> *mut u8 {
let bytes = self.into_bytes(); let bytes = self.into_bytes();
@@ -96,7 +96,7 @@ impl ConsPtr {
unsafe { mem::transmute(raw_ptr_bytes) } unsafe { mem::transmute(raw_ptr_bytes) }
} }
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
#[inline(always)] #[inline(always)]
pub fn as_ptr(self) -> *mut u8 { pub fn as_ptr(self) -> *mut u8 {
self.ptr() as *mut _ self.ptr() as *mut _
@@ -121,28 +121,24 @@ pub(crate) enum RefTag {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Ref { pub struct Ref {
val: B56, val: B56,
#[allow(unused)] m: bool, #[allow(unused)]
#[allow(unused)] f: bool, m: bool,
#[allow(unused)]
f: bool,
tag: RefTag, tag: RefTag,
} }
impl Ord for Ref { impl Ord for Ref {
fn cmp(&self, rhs: &Ref) -> Ordering { fn cmp(&self, rhs: &Ref) -> Ordering {
match self.get_tag() { match self.get_tag() {
RefTag::HeapCell | RefTag::AttrVar => { RefTag::HeapCell | RefTag::AttrVar => match rhs.get_tag() {
match rhs.get_tag() { RefTag::StackCell => Ordering::Less,
RefTag::StackCell => Ordering::Less, _ => self.get_value().cmp(&rhs.get_value()),
_ => self.get_value().cmp(&rhs.get_value()), },
} RefTag::StackCell => match rhs.get_tag() {
} RefTag::StackCell => self.get_value().cmp(&rhs.get_value()),
RefTag::StackCell => { _ => Ordering::Greater,
match rhs.get_tag() { },
RefTag::StackCell =>
self.get_value().cmp(&rhs.get_value()),
_ =>
Ordering::Greater,
}
}
} }
} }
} }
@@ -204,9 +200,9 @@ pub(crate) enum TrailEntryTag {
TrailedHeapVar = 0b101111, TrailedHeapVar = 0b101111,
TrailedStackVar = 0b101011, TrailedStackVar = 0b101011,
TrailedAttrVar = 0b100001, TrailedAttrVar = 0b100001,
TrailedAttrVarListLink = 0b100011, TrailedAttrVarListLink = 0b100011,
TrailedAttachedValue = 0b100101, TrailedAttachedValue = 0b100101,
TrailedBlackboardEntry = 0b100111, TrailedBlackboardEntry = 0b100111,
TrailedBlackboardOffset = 0b110011, TrailedBlackboardOffset = 0b110011,
} }
@@ -215,9 +211,12 @@ pub(crate) enum TrailEntryTag {
#[repr(u64)] #[repr(u64)]
pub(crate) struct TrailEntry { pub(crate) struct TrailEntry {
val: B56, val: B56,
#[allow(unused)] f: bool, #[allow(unused)]
#[allow(unused)] m: bool, f: bool,
#[allow(unused)] tag: TrailEntryTag, #[allow(unused)]
m: bool,
#[allow(unused)]
tag: TrailEntryTag,
} }
impl TrailEntry { impl TrailEntry {
@@ -233,9 +232,9 @@ impl TrailEntry {
#[inline(always)] #[inline(always)]
pub(crate) fn get_tag(self) -> TrailEntryTag { pub(crate) fn get_tag(self) -> TrailEntryTag {
match self.tag_or_err() { match self.tag_or_err() {
Ok(tag) => tag, Ok(tag) => tag,
Err(_) => TrailEntryTag::TrailedAttachedValue, Err(_) => TrailEntryTag::TrailedAttachedValue,
} }
} }
#[inline] #[inline]
@@ -257,14 +256,13 @@ pub struct HeapCellValue {
impl fmt::Debug for HeapCellValue { impl fmt::Debug for HeapCellValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::F64 => { HeapCellValueTag::F64 => f
f.debug_struct("HeapCellValue") .debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::F64) .field("tag", &HeapCellValueTag::F64)
.field("offset", &self.get_value()) .field("offset", &self.get_value())
.field("m", &self.m()) .field("m", &self.m())
.field("f", &self.f()) .field("f", &self.f())
.finish() .finish(),
}
HeapCellValueTag::Cons => { HeapCellValueTag::Cons => {
let cons_ptr = ConsPtr::from_bytes(self.into_bytes()); let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
@@ -276,8 +274,7 @@ impl fmt::Debug for HeapCellValue {
.finish() .finish()
} }
HeapCellValueTag::Atom => { HeapCellValueTag::Atom => {
let (name, arity) = cell_as_atom_cell!(self) let (name, arity) = cell_as_atom_cell!(self).get_name_and_arity();
.get_name_and_arity();
f.debug_struct("HeapCellValue") f.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::Atom) .field("tag", &HeapCellValueTag::Atom)
@@ -288,8 +285,7 @@ impl fmt::Debug for HeapCellValue {
.finish() .finish()
} }
HeapCellValueTag::PStr => { HeapCellValueTag::PStr => {
let (name, _) = cell_as_atom_cell!(self) let (name, _) = cell_as_atom_cell!(self).get_name_and_arity();
.get_name_and_arity();
f.debug_struct("HeapCellValue") f.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::PStr) .field("tag", &HeapCellValueTag::PStr)
@@ -298,14 +294,13 @@ impl fmt::Debug for HeapCellValue {
.field("f", &self.f()) .field("f", &self.f())
.finish() .finish()
} }
tag => { tag => f
f.debug_struct("HeapCellValue") .debug_struct("HeapCellValue")
.field("tag", &tag) .field("tag", &tag)
.field("value", &self.get_value()) .field("value", &self.get_value())
.field("m", &self.get_mark_bit()) .field("m", &self.get_mark_bit())
.field("f", &self.get_forwarding_bit()) .field("f", &self.get_forwarding_bit())
.finish() .finish(),
}
} }
} }
} }
@@ -320,10 +315,7 @@ impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue {
impl From<F64Ptr> for HeapCellValue { impl From<F64Ptr> for HeapCellValue {
#[inline] #[inline]
fn from(f64_ptr: F64Ptr) -> HeapCellValue { fn from(f64_ptr: F64Ptr) -> HeapCellValue {
HeapCellValue::build_with( HeapCellValue::build_with(HeapCellValueTag::F64, f64_ptr.as_offset().to_u64())
HeapCellValueTag::F64,
f64_ptr.as_offset().to_u64(),
)
} }
} }
@@ -402,9 +394,13 @@ impl HeapCellValue {
#[inline] #[inline]
pub fn is_ref(self) -> bool { pub fn is_ref(self) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var | HeapCellValueTag::Str
HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | | HeapCellValueTag::Lis
HeapCellValueTag::PStrOffset => true, | HeapCellValueTag::Var
| HeapCellValueTag::StackVar
| HeapCellValueTag::AttrVar
| HeapCellValueTag::PStrLoc
| HeapCellValueTag::PStrOffset => true,
_ => false, _ => false,
} }
} }
@@ -431,16 +427,14 @@ impl HeapCellValue {
#[inline] #[inline]
pub fn is_constant(self) -> bool { pub fn is_constant(self) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum | HeapCellValueTag::Cons
HeapCellValueTag::Char | HeapCellValueTag::CStr => { | HeapCellValueTag::F64
true | HeapCellValueTag::Fixnum
} | HeapCellValueTag::CutPoint
HeapCellValueTag::Atom => { | HeapCellValueTag::Char
cell_as_atom_cell!(self).get_arity() == 0 | HeapCellValueTag::CStr => true,
} HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,
_ => { _ => false,
false
}
} }
} }
@@ -455,17 +449,13 @@ impl HeapCellValue {
HeapCellValueTag::Str => { HeapCellValueTag::Str => {
cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0 cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0
} }
HeapCellValueTag::Lis | HeapCellValueTag::Lis
HeapCellValueTag::CStr | | HeapCellValueTag::CStr
HeapCellValueTag::PStr | | HeapCellValueTag::PStr
HeapCellValueTag::PStrLoc | | HeapCellValueTag::PStrLoc
HeapCellValueTag::PStrOffset => { | HeapCellValueTag::PStrOffset => true,
true HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0,
} _ => false,
HeapCellValueTag::Atom => {
cell_as_atom_cell!(self).get_arity() > 0
}
_ => { false }
} }
} }
@@ -530,9 +520,7 @@ impl HeapCellValue {
#[inline] #[inline]
pub fn to_pstr(self) -> Option<PartialString> { pub fn to_pstr(self) -> Option<PartialString> {
match self.tag() { match self.tag() {
HeapCellValueTag::PStr => { HeapCellValueTag::PStr => Some(PartialString::from(Atom::from(self.val() << 3))),
Some(PartialString::from(Atom::from(self.val() << 3)))
}
_ => None, _ => None,
} }
} }
@@ -545,26 +533,35 @@ impl HeapCellValue {
} }
} }
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
#[inline] #[inline]
pub fn from_raw_ptr_bytes(ptr_bytes: [u8; 4]) -> Self { pub fn from_raw_ptr_bytes(ptr_bytes: [u8; 4]) -> Self {
HeapCellValue::from_bytes([ptr_bytes[0], ptr_bytes[1], ptr_bytes[2], ptr_bytes[3], 0, 0, 0, 0]) HeapCellValue::from_bytes([
ptr_bytes[0],
ptr_bytes[1],
ptr_bytes[2],
ptr_bytes[3],
0,
0,
0,
0,
])
} }
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
#[inline] #[inline]
pub fn from_raw_ptr_bytes(ptr_bytes: [u8; 8]) -> Self { pub fn from_raw_ptr_bytes(ptr_bytes: [u8; 8]) -> Self {
HeapCellValue::from_bytes(ptr_bytes) HeapCellValue::from_bytes(ptr_bytes)
} }
#[inline] #[inline]
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
pub fn to_raw_ptr_bytes(self) -> [u8; 4] { pub fn to_raw_ptr_bytes(self) -> [u8; 4] {
let bytes = self.into_bytes(); let bytes = self.into_bytes();
[bytes[0], bytes[1], bytes[2], bytes[3]] [bytes[0], bytes[1], bytes[2], bytes[3]]
} }
#[inline] #[inline]
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
pub fn to_raw_ptr_bytes(self) -> [u8; 8] { pub fn to_raw_ptr_bytes(self) -> [u8; 8] {
self.into_bytes() self.into_bytes()
} }
@@ -577,7 +574,9 @@ impl HeapCellValue {
#[inline] #[inline]
pub fn to_untyped_arena_ptr(self) -> Option<UntypedArenaPtr> { pub fn to_untyped_arena_ptr(self) -> Option<UntypedArenaPtr> {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.to_untyped_arena_ptr_bytes())), HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(
self.to_untyped_arena_ptr_bytes(),
)),
_ => None, _ => None,
} }
} }
@@ -586,7 +585,7 @@ impl HeapCellValue {
pub fn get_forwarding_bit(self) -> bool { pub fn get_forwarding_bit(self) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(), HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(),
_ => self.f() _ => self.f(),
} }
} }
@@ -604,9 +603,7 @@ impl HeapCellValue {
#[inline(always)] #[inline(always)]
pub fn get_mark_bit(self) -> bool { pub fn get_mark_bit(self) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons => { HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).m(),
ConsPtr::from_bytes(self.into_bytes()).m()
}
_ => self.m(), _ => self.m(),
} }
} }
@@ -633,15 +630,12 @@ impl HeapCellValue {
Some(TermOrderCategory::Variable) Some(TermOrderCategory::Variable)
} }
HeapCellValueTag::Char => Some(TermOrderCategory::Atom), HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
HeapCellValueTag::Atom => { HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 {
Some(if cell_as_atom_cell!(self).get_arity() > 0 { TermOrderCategory::Compound
TermOrderCategory::Compound } else {
} else { TermOrderCategory::Atom
TermOrderCategory::Atom }),
}) HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => {
}
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr => {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
HeapCellValueTag::Str => { HeapCellValueTag::Str => {
@@ -654,9 +648,7 @@ impl HeapCellValue {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
} }
_ => { _ => None,
None
}
}, },
} }
} }
@@ -680,16 +672,17 @@ const_assert!(mem::size_of::<HeapCellValue>() == 8);
#[repr(u64)] #[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct UntypedArenaPtr { pub struct UntypedArenaPtr {
#[allow(unused)] ptr: B61, #[allow(unused)]
ptr: B61,
m: bool, m: bool,
#[allow(unused)] padding: B2, #[allow(unused)]
padding: B2,
} }
impl UntypedArenaPtr { impl UntypedArenaPtr {
#[inline(always)] #[inline(always)]
pub fn build_with(ptr: usize) -> Self { pub fn build_with(ptr: usize) -> Self {
UntypedArenaPtr::new() UntypedArenaPtr::new().with_ptr(ptr as u64)
.with_ptr(ptr as u64)
} }
} }
@@ -722,7 +715,7 @@ impl UntypedArenaPtr {
self.set_m(m); self.set_m(m);
} }
#[cfg(target_pointer_width="32")] #[cfg(target_pointer_width = "32")]
#[inline] #[inline]
pub fn get_ptr(self) -> *const u8 { pub fn get_ptr(self) -> *const u8 {
let bytes = self.into_bytes(); let bytes = self.into_bytes();
@@ -730,10 +723,10 @@ impl UntypedArenaPtr {
unsafe { mem::transmute(raw_ptr_bytes) } unsafe { mem::transmute(raw_ptr_bytes) }
} }
#[cfg(target_pointer_width="64")] #[cfg(target_pointer_width = "64")]
#[inline] #[inline]
pub fn get_ptr(self) -> *const u8 { pub fn get_ptr(self) -> *const u8 {
self.ptr() as *const u8 self.ptr() as *const u8
} }
#[inline] #[inline]
@@ -763,17 +756,15 @@ impl Add<usize> for HeapCellValue {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self.get_tag() { match self.get_tag() {
tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Str
tag @ HeapCellValueTag::Lis | | tag @ HeapCellValueTag::Lis
tag @ HeapCellValueTag::PStrOffset | | tag @ HeapCellValueTag::PStrOffset
tag @ HeapCellValueTag::PStrLoc | | tag @ HeapCellValueTag::PStrLoc
tag @ HeapCellValueTag::Var | | tag @ HeapCellValueTag::Var
tag @ HeapCellValueTag::AttrVar => { | tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, (self.get_value() as usize + rhs) as u64) HeapCellValue::build_with(tag, (self.get_value() as usize + rhs) as u64)
} }
_ => { _ => self,
self
}
} }
} }
} }
@@ -783,17 +774,15 @@ impl Sub<usize> for HeapCellValue {
fn sub(self, rhs: usize) -> Self::Output { fn sub(self, rhs: usize) -> Self::Output {
match self.get_tag() { match self.get_tag() {
tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Str
tag @ HeapCellValueTag::Lis | | tag @ HeapCellValueTag::Lis
tag @ HeapCellValueTag::PStrOffset | | tag @ HeapCellValueTag::PStrOffset
tag @ HeapCellValueTag::PStrLoc | | tag @ HeapCellValueTag::PStrLoc
tag @ HeapCellValueTag::Var | | tag @ HeapCellValueTag::Var
tag @ HeapCellValueTag::AttrVar => { | tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, (self.get_value() as usize - rhs) as u64) HeapCellValue::build_with(tag, (self.get_value() as usize - rhs) as u64)
} }
_ => { _ => self,
self
}
} }
} }
} }
@@ -811,21 +800,18 @@ impl Sub<i64> for HeapCellValue {
fn sub(self, rhs: i64) -> Self::Output { fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 { if rhs < 0 {
match self.get_tag() { match self.get_tag() {
tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Str
tag @ HeapCellValueTag::Lis | | tag @ HeapCellValueTag::Lis
tag @ HeapCellValueTag::PStrOffset | | tag @ HeapCellValueTag::PStrOffset
tag @ HeapCellValueTag::PStrLoc | | tag @ HeapCellValueTag::PStrLoc
tag @ HeapCellValueTag::Var | | tag @ HeapCellValueTag::Var
tag @ HeapCellValueTag::AttrVar => { | tag @ HeapCellValueTag::AttrVar => {
HeapCellValue::build_with(tag, self.get_value() + rhs.abs() as u64) HeapCellValue::build_with(tag, self.get_value() + rhs.abs() as u64)
} }
_ => { _ => self,
self
}
} }
} else { } else {
self.sub(rhs as usize) self.sub(rhs as usize)
} }
} }
} }

View File

@@ -56,8 +56,10 @@ impl VarSafetyStatus {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum PermVarAllocation { pub enum PermVarAllocation {
Done { shallow_safety: VarSafetyStatus, Done {
deep_safety: VarSafetyStatus }, shallow_safety: VarSafetyStatus,
deep_safety: VarSafetyStatus,
},
Pending, Pending,
} }
@@ -81,11 +83,13 @@ impl PermVarAllocation {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum VarAlloc { pub enum VarAlloc {
Temp { term_loc: GenContext, Temp {
temp_reg: usize, term_loc: GenContext,
temp_var_data: TempVarData, temp_reg: usize,
safety: VarSafetyStatus, temp_var_data: TempVarData,
to_perm_var_num: Option<usize> }, safety: VarSafetyStatus,
to_perm_var_num: Option<usize>,
},
Perm(usize, PermVarAllocation), // stack offset, allocation info Perm(usize, PermVarAllocation), // stack offset, allocation info
} }
@@ -102,7 +106,9 @@ impl VarAlloc {
pub(crate) fn set_register(&mut self, reg_num: usize) { pub(crate) fn set_register(&mut self, reg_num: usize) {
match self { match self {
VarAlloc::Perm(ref mut p, _) => *p = reg_num, VarAlloc::Perm(ref mut p, _) => *p = reg_num,
VarAlloc::Temp { ref mut temp_reg, .. } => *temp_reg = reg_num, VarAlloc::Temp {
ref mut temp_reg, ..
} => *temp_reg = reg_num,
}; };
} }
} }
@@ -191,7 +197,8 @@ impl VariableRecords {
// Compute the conflict set of u. // Compute the conflict set of u.
// 1. // 1.
let mut use_sets: IndexMap<usize, IndexSet<(GenContext, usize), FxBuildHasher>> = IndexMap::new(); let mut use_sets: IndexMap<usize, IndexSet<(GenContext, usize), FxBuildHasher>> =
IndexMap::new();
for (var_gen_index, record) in self.0.iter_mut().enumerate() { for (var_gen_index, record) in self.0.iter_mut().enumerate() {
match &mut record.allocation { match &mut record.allocation {
@@ -203,8 +210,7 @@ impl VariableRecords {
use_sets.insert(var_gen_index, use_set); use_sets.insert(var_gen_index, use_set);
} }
_ => { _ => {}
}
} }
} }
@@ -214,7 +220,11 @@ impl VariableRecords {
if let GenContext::Last(cn_u) = term_loc { if let GenContext::Last(cn_u) = term_loc {
for (var_gen_index, record) in self.0.iter_mut().enumerate() { for (var_gen_index, record) in self.0.iter_mut().enumerate() {
match &mut record.allocation { match &mut record.allocation {
VarAlloc::Temp { term_loc, temp_var_data, .. } => { VarAlloc::Temp {
term_loc,
temp_var_data,
..
} => {
if cn_u == term_loc.chunk_num() && u != var_gen_index { if cn_u == term_loc.chunk_num() && u != var_gen_index {
if !temp_var_data.uses_reg(reg) { if !temp_var_data.uses_reg(reg) {
temp_var_data.no_use_set.insert(reg); temp_var_data.no_use_set.insert(reg);
@@ -228,7 +238,7 @@ impl VariableRecords {
} }
// 3. // 3.
if let VarAlloc::Temp{ temp_var_data, .. } = &mut self[u].allocation { if let VarAlloc::Temp { temp_var_data, .. } = &mut self[u].allocation {
temp_var_data.use_set = use_set; temp_var_data.use_set = use_set;
temp_var_data.populate_conflict_set(); temp_var_data.populate_conflict_set();
} }

View File

@@ -467,13 +467,14 @@ test_195_205_196_197 :-
setup_call_cleanup(op(100,xf,''), setup_call_cleanup(op(100,xf,''),
( read_from_chars("(0 '') = ''(X).", T0), ( read_from_chars("(0 '') = ''(X).", T0),
call(T0), call(T0),
T0 = (_ = ('')(0)), writeq_term_to_chars(T0, C0),
C0 == "0 ''=0 ''",
read_from_chars("0 ''.", T1), read_from_chars("0 ''.", T1),
writeq_term_to_chars(T1, C0), writeq_term_to_chars(T1, C1),
C0 == "0 ''", C1 == "0 ''",
read_from_chars("0''.", T2), read_from_chars("0''.", T2),
writeq_term_to_chars(T2, C1), writeq_term_to_chars(T2, C2),
C1 == "0 ''" ), C2 == "0 ''" ),
op(0,xf,'')). op(0,xf,'')).
test_118_119_120 :- test_118_119_120 :-
@@ -774,7 +775,7 @@ test_175 :- T = t(0b1,0o1,0x1),
test_176 :- X is 0b1mod 2, test_176 :- X is 0b1mod 2,
X == 1. X == 1.
test_217_181_290 :- test_217_181_290_317 :-
setup_call_cleanup(( current_op(P, xfy, '|') -> setup_call_cleanup(( current_op(P, xfy, '|') ->
true true
; P = 0 ; P = 0
@@ -785,7 +786,10 @@ test_217_181_290 :-
C0 == "a-->b,c | d", C0 == "a-->b,c | d",
read_from_chars("[(a|b)].", T1), read_from_chars("[(a|b)].", T1),
writeq_term_to_chars(T1, C1), writeq_term_to_chars(T1, C1),
C1 == "[(a | b)]" C1 == "[(a | b)]",
read_from_chars("[a,(b,c)|[]].", T2),
writeq_term_to_chars(T2, C2),
C2 == "[a,(b,c)]"
), ),
op(P, xfy, '|')). op(P, xfy, '|')).

View File

@@ -1,5 +1,4 @@
use crate::helper::{load_module_test, run_top_level_test_no_args, run_top_level_test_with_args}; use crate::helper::{load_module_test, run_top_level_test_no_args, run_top_level_test_with_args};
use scryer_prolog::machine::Machine;
use serial_test::serial; use serial_test::serial;
// issue #857 // issue #857
@@ -30,7 +29,7 @@ fn do_not_duplicate_path_components() {
['tests-pl/issue852-throw_e.pl'].\n\ ['tests-pl/issue852-throw_e.pl'].\n\
halt.\n\ halt.\n\
", ",
" throw(e).\n false.\n throw(e).\n false.\n", " throw(e).\n throw(e).\n",
); );
} }
@@ -171,16 +170,3 @@ fn call_0() {
" error(existence_error(procedure,call/0),call/0).\n", " error(existence_error(procedure,call/0),call/0).\n",
); );
} }
// issue #1206
#[serial]
#[test]
#[should_panic(expected = "Overwriting atom table base pointer")]
fn atomtable_is_not_concurrency_safe() {
// this is basically the same test as scryer_prolog::atom_table::atomtable_is_not_concurrency_safe
// but for this integration test scryer_prolog is compiled with cfg!(not(test)) while for the unit test it is compiled with cfg!(test)
// as the atom table implementation differ between cfg!(test) and cfg!(not(test)) both test serve a pourpose
// Note: this integration test itself is compiled with cfg!(test) independent of scryer_prolog itself
let _machine_a = Machine::with_test_streams();
let _machine_b = Machine::with_test_streams();
}

View File

@@ -73,8 +73,41 @@ fn clpz_load() {
#[serial] #[serial]
#[test] #[test]
fn iso_conformity_tests() { fn iso_conformity_tests() {
load_module_test( load_module_test("tests-pl/iso-conformity-tests.pl", "All tests passed");
"tests-pl/iso-conformity-tests.pl", }
#[test]
fn dif_tests() {
run_top_level_test_with_args(
&["src/tests/dif.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}
#[test]
fn ground_tests() {
run_top_level_test_with_args(
&["src/tests/ground.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}
#[test]
fn term_variables_tests() {
run_top_level_test_with_args(
&["src/tests/term_variables.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}
#[test]
fn acyclic_term_tests() {
run_top_level_test_with_args(
&["src/tests/acyclic_term.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed", "All tests passed",
); );
} }